操作数据行

本文关键字:数据 操作数 操作 | 更新日期: 2023-09-27 18:18:20

我每秒更新的数据生成了数百万行,如下所示:

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上寻找解决方案,但到目前为止还没有找到任何解决方案。

编辑:这些行在文本文件中,我想将新创建的数据存储在新的文本文件中。

操作数据行

您需要将一些东西放在一起。

  1. 逐行读取文件:请参阅此处:一次读取一行文本文件
  2. 逐行写入文件:StreamWriter.WriteLine
  3. 跟踪最后一个读取行。(只需在 while 循环中使用一个变量即可读取行(
  4. 检查是否有间隙。也许通过使用TimeSpan.Parse解析第一列(string.Split(。如果有间隙,则写入最后一行读取,增加时间跨度。

好的,这是整个射击比赛,经过测试并针对您的测试数据进行处理:

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

除了所有答案之外,考虑到您正在谈论一个大文件,请考虑使用 MemoryMappedFiles,可以阅读此处了解如何从 C# 使用它们。

这不是性能改进,但内存改进肯定是。

就在某些条目之间插入新条目而言,我建议将文本文件读取为单独的行,然后将它们存储在List中。这样,您可以使用 Insert(...) 方法插入新行。从那里,您可以将这些行写回文件中。

读取这些行时,可以使用 System.IO.File 类中的任一静态帮助程序方法:ReadAllTextReadAllLines

注意:我为我提到的每个方法和类添加了指向 MSDN 文档的链接,因为您说您不熟悉 C# 和一般编程。

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

这里有一些伪代码可以帮助您入门。 我想你会想要这种类型的算法。

这里有一些粗略的代码给你。我没有正确处理所有内容,只是为了让您入门。

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

这假设时间相隔不超过一秒。如果这个假设是错误的,很容易修改以下内容,以便它为每秒缺失的时间在循环中写入 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;
   }
}
        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);
            }
        }