2011-12-20 2 views
15

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

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

Столбец слева представляет собой время (ччммсс формат), а столбец справа данных который обновляется второй раз. Как вы можете видеть, однако, это не второй раз в секунду, и в этом примере отсутствуют некоторые недостающие моменты (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, ища решение для этого, но пока их не нашли.

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

+0

Я полагаю, что строки из текстового файла, и вы хотите создать новый с пропущенными значениями? – Strillo

+6

+1 для отличного (хорошо написанного, объясненного и отформатированного) первого вопроса. –

+0

Да, извините, я должен был включить это в мой вопрос. Строки находятся в текстовом файле, и я хочу сохранить вновь созданные данные в новом текстовом файле. –

ответ

3

нормально, вот весь матч съемки, протестировано и работает против ваших тестовых данных:

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); } 
    } 
} 
+0

Будучи довольно простым вопросом, моя первая мысль заключается в том, что это какой-то вопрос о домашнем задании или задании на работу - не обязательно, но стоит подумать, прежде чем публиковать ответ на полный исходный код для легкой проблемы. –

+1

Эй, Билл К, это пришло мне в голову, но это было хорошо написано и вежливо, поэтому для меня это довольно просто; люди публикуют вопросы, если вы хотите ответить на них, сделайте это, если вы хотите понизить голос, задавайте вопросы, подшучивайте над ним или даже игнорируйте его, вы можете делать все это. Вы также можете жаловаться, когда кто-то другой отвечает на него. Свобода, ты должен любить ее. –

+0

Да, я согласен - поэтому я просто нежно напоминаю людям, что дает полный набор ответов на простые вопросы, которые вы можете делать никому, кроме себя. –

1

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

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

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

+1

Есть миллионы строк, не уверен, что хранить весь файл в памяти - хорошая идея. –

+0

Если он читает миллионы строк, которые могут немного помять, тем более, что для поиска недостающей строки ему просто нужны две строки в памяти за один раз - «Текущий и предыдущий». – asawyer

+0

Оба комментария верны - это всего лишь предложение. Любое фактическое решение будет полностью зависеть от реализации. В любом случае ответ должен привести его к поиску решения, которое ему подходит. –

1
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; 
} 

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

+0

Спасибо, что написали это, я прочитаю о том, что он делает, и посмотрим, делает ли это трюк. –

4

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

  1. Почитаю строка за строкой файла: Смотрите здесь: Reading a Text File One Line at a Time
  2. Запись файла строка за строкой: StreamWriter.WriteLine
  3. Следите за последней строкой чтения. (Просто используйте переменную в цикле while, где вы читаете строки)
  4. Проверьте, есть ли пробел. Возможно, разобрав первый столбец (string.Split), используя TimeSpan.Parse. Если есть пробел, тогда напишите последнюю строку чтения, увеличивая время ожидания.
+0

Спасибо, я думаю, что у меня хватит на 1-3, но №4 совершенно для меня совершенно, поэтому я начну читать о string.Split и TimeSpan.Parse. –

3

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

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

1

Это предполагает, что время не превышает секунды. Если это предположение неверно, достаточно легко изменить ниже, чтобы он записывал 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; 
    } 

} 
+0

Большое спасибо! Я прочитаю о том, что это делает, а затем попробуем. –

1

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

 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
 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); 
      } 
     } 
Смежные вопросы