Манипулирование строками данных - PullRequest
15 голосов
/ 20 декабря 2011

У меня миллионы строк, сгенерированных из данных, обновляемых каждую секунду, которые выглядят следующим образом:

104500 4783
104501 8930
104502 21794
104503 21927
104505 5746
104506 9968
104509 5867
104510 46353
104511 7767
104512 4903

Столбец слева представляет время (формат hhmmss), а столбец справа - данные, которыеобновляется по очереди.Однако, как вы можете видеть, на самом деле это не секунда за секундой, и есть некоторые пропущенные моменты (10:45:04, 10:45:07, 10:45:08 в этом примере отсутствуют).Моя цель - добавить пропущенные секунды и использовать данные предыдущей секунды для этой пропущенной секунды, например:

104500 4783
104501 8930
104502 21794
104503 21927
104504 21927 --
104505 5746
104506 9968
104507 9968 --
104508 9968 --
104509 5867
104510 46353
104511 7767
104512 4903

Мне не нужен знак "-" в результате,Я просто положил их туда, чтобы отметить добавленные строки.До сих пор я пытался сделать это с помощью StreamReader и StreamWriter, но, похоже, они не получат то, что я хочу.Я начинающий программист и новичок в C #, так что, если бы вы могли указать мне правильное направление, это было бы здорово.Мне просто интересно, возможно ли это вообще сделать в C # ... Я потратил много времени на MSDN и здесь на SO в поисках решения, но пока не нашел.

Редактировать: строки находятся в текстовом файле, и я хочу сохранить вновь созданные данные в новом текстовом файле.

Ответы [ 8 ]

4 голосов
/ 20 декабря 2011

Есть несколько вещей, которые вам нужно собрать.

  1. Чтение файла построчно: См. Здесь: Чтение текстового файла по одной строке за раз
  2. Запись файла построчно: StreamWriter.WriteLine
  3. Отслеживание последней прочитанной строки.(Просто используйте переменную в цикле while, где вы читаете строки)
  4. Проверьте, есть ли пробел.Возможно, анализируя первый столбец (string.Split), используя TimeSpan.Parse.Если есть пробел, напишите последнюю прочитанную строку, увеличивая интервал времени.
3 голосов
/ 20 декабря 2011

В дополнение ко всем ответам, учитывая, что вы говорите об огромных файлах, рассмотрите возможность использования MemoryMappedFiles , можете прочитать здесь , чтобы увидеть, как их использовать из C #.

Это не улучшение производительности , но улучшение памяти определенно есть.

3 голосов
/ 20 декабря 2011

хорошо, вот весь стрельбище, проверено и работает против ваших тестовых данных:

public void InjectMissingData()
{
    DataLine lastDataLine = null;
    using (var writer = new StreamWriter(File.Create("c:\\temp\\out.txt")))
    {
        using (var reader = new StreamReader("c:\\temp\\in.txt"))
        {
            while (!reader.EndOfStream)
            {
                var dataLine = DataLine.Parse(reader.ReadLine());

                while (lastDataLine != null && dataLine.Occurence - lastDataLine.Occurence > TimeSpan.FromSeconds(1))
                {
                    lastDataLine = new DataLine(lastDataLine.Occurence + TimeSpan.FromSeconds(1), lastDataLine.Data);
                    writer.WriteLine(lastDataLine.Line);
                }

                writer.WriteLine(dataLine.Line);

                lastDataLine = dataLine;
            }
        }
    }
}

public class DataLine
{
    public static DataLine Parse(string line)
    {
        var timeString = string.Format("{0}:{1}:{2}", line.Substring(0, 2), line.Substring(2, 2),
                                       line.Substring(4, 2));

        return new DataLine(TimeSpan.Parse(timeString), long.Parse(line.Substring(7, line.Length - 7).Trim()));
    } 

    public DataLine(TimeSpan occurence, long data)
    {
        Occurence = occurence;
        Data = data;
    }

    public TimeSpan Occurence { get; private set; }
    public long Data { get; private set; }

    public string Line
    {
        get { return string.Format("{0}{1}{2} {3}", 
            Occurence.Hours.ToString().PadLeft(2, Char.Parse("0")), 
            Occurence.Minutes.ToString().PadLeft(2, Char.Parse("0")), 
            Occurence.Seconds.ToString().PadLeft(2, Char.Parse("0")),
            Data); }
    }
}
1 голос
/ 20 декабря 2011
        string line;//The line that is read.
        string previousLine = "0 0";
        int prevTime = 0;

        //These "using"'s are so that the resources they use will be freed when the block ( i.e. {} ) is finished.
        using (System.IO.StreamReader originalFile = new System.IO.StreamReader("c:\\users\\Me\\t.txt"))
        using (System.IO.StreamWriter newFile = new System.IO.StreamWriter("c:\\users\\Me\\t2.txt"))
        {
            while ((line = originalFile.ReadLine()) != null)
            {
                //"Split" changes the words in "line" (- that are separated by a space) to an array. 
                //"Parse" takes the first in that array (by using "[0]") and changes it into an integer.
                int time = int.Parse(line.Split(' ')[0]);
                while (prevTime != 0 && time > ++prevTime) newFile.WriteLine(prevTime.ToString() + " " + previousLine.Split(' ')[1]);

                previousLine = line;
                prevTime = time;
                newFile.WriteLine(line);
            }
        }
1 голос
/ 20 декабря 2011

Вот вам примерный код. Я не все должным образом утилизирую, просто для начала.

        DateTime lastTime;
        string lastValue = null;
        StreamReader reader = File.OpenText("path");
        StreamWriter writer = new StreamWriter(File.OpenWrite("newPath"));

        while (!reader.EndOfStream)
        {
            string[] lineData = reader.ReadLine().Split(' ');
            DateTime currentTime = DateTime.Parse(lineData[0]);
            string value = lineData[1];

            if (lastValue != null)
            {
                while (lastTime < currentTime.AddSeconds(-1))
                {
                    lastTime = lastTime.AddSeconds(1);
                    writer.WriteLine("{0} {1}", lastTime, lastValue);
                }
            }
            writer.WriteLine("{0} {1}", currentTime, value);
            lastTime = currentTime;
            lastValue = value;
        }
1 голос
/ 20 декабря 2011

Предполагается, что время никогда не превышает секунды. Если это предположение неверно, достаточно легко изменить приведенное ниже, чтобы оно записывало lastValue в цикл для каждой пропущенной секунды. Обновление Я пропустил в вашем примере, что он может фактически пропустить несколько секунд. Я изменил приведенный ниже пример, чтобы исправить это.

using (StreamReader reader = OpenYourInputFile())
using (StreamWriter writer = OpenYourOutputFile())
{
   TimeSpan? lastTime;
   TimeSpan currentTime, maxDiff = TimeSpan.FromSeconds(1);
   string lastValue, currentline, currentValue, format = "{0:hhmmss} {1}";

   while( (currentLine = reader.ReadLine()) != null)
   {
      string[] s = currentLine.Split(' ');
      currentTime = DateTime.ParseExact("hhmmss", s[0] CultureInfo.InvariantCulture).TimeOfDay;
      currentValue = s[1];

      if (lastTime.HasValue && currentTime - lastTime.Value > maxDiff) 
      { 
        for(int x = 1; x <= (currentTime - lastTime).Seconds; x++) writer.WriteLine(string.Format(format, DateTime.Today.Add(lastTime).AddSeconds(x), lastValue);
      }

      writer.WriteLine(string.Format(format, DateTime.Today.Add(currentTime), currentValue);

      lastTime = currentTime;
      lastValue = currentValue;
   }

}
1 голос
/ 20 декабря 2011
String prevTime;
String prevData;

while(String line = myStreamReader.ReadLine())
{
    String[] parts = line.Split(new Char[] { ' ' });
    String time = parts[0];
    String data = parts[1];

    Int32 iPrevTime = Int32.Parse(prevTime);
    Int32 iCurrentTime = Int32.Parse(time);

    // May need to loop here if you're missing more than one second
    if(iCurrentTime > iPrevTime + 1)   
          AddData((iPrevTime + 1).ToString(), prevData);

    AddData(time, data);
    prevTime = time;
    prevData = data;
}

Вот некоторый псевдокод, с которого можно начать. Я думаю, вы захотите этот тип алгоритма.

1 голос
/ 20 декабря 2011

Что касается вставки новых записей между определенными, я бы посоветовал прочитать текстовый файл в отдельные строки, а затем сохранить их в List.Таким образом, вы можете использовать метод Insert(...) для вставки новых строк.Оттуда вы можете записать строки обратно в файл.

При чтении строк вы можете использовать любой из статических вспомогательных методов в классе System.IO.File: ReadAllText и ReadAllLines.

Примечание. Я добавил ссылки на документацию MSDN для каждого из упомянутых мной методов и классов, поскольку вы сказали, чтоновичок в C # и программировании в целом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...