【问题标题】:Read text file line by line using timer使用计时器逐行读取文本文件
【发布时间】:2018-06-30 19:24:53
【问题描述】:
StreamReader sr = new StreamReader("C:/CR EZ Test/Log.txt");    //use with IF
private void timer2_Tick(object sender, EventArgs e)
{
    if ((line = sr.ReadLine()) != null)
    {   
        //FileStream fs = File.Open("C:/CR EZ Test/Log.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
        //StreamReader sr = new StreamReader(fs); //use with While can't use with }else{
        //while ((line = sr.ReadLine()) != null) 
        //{
        string[] dataLog = line.Split(new[] { ',' }, StringSplitOptions.None);
        mpa = (dataLog[1]);
        ml  = (dataLog[2]);
        lph = (dataLog[3]);
        elapsedTime = float.Parse(dataLog[4]) / 1000;

        if (testStatus > 0) time = elapsedTime.ToString("0.0");
        tb2.Value = int.Parse(dataLog[6]);

        if (chart1.Series[0].Points.Count > tb1.Value && tb1.Value > 0)
        {
            chart1.Series[0].Points.RemoveAt(0);
            chart1.Series[1].Points.RemoveAt(0);
        }
        chart1.Series[0].Points.AddXY(dataLog[5], int.Parse(dataLog[1]));
        chart1.Series[1].Points.AddXY(dataLog[5], int.Parse(dataLog[6]));
        //}
    }
    else
    {
        sr.DiscardBufferedData();
        sr.BaseStream.Seek(0, SeekOrigin.Begin);
        sr.BaseStream.Position = 0;
        //sr.Close();
        //alertTB.Text = "";
        timer2.Enabled = false;
    }
    alertTB.ForeColor = Color.Red;
    alertTB.Text = "Data Log Viewing In Progress";
}

问题是我正在通过 GUI 读取一个充满变量的文本文件,例如重播视频。如代码所示,它可以工作,我可以控制计时器滴答声来改变重播速度。问题是文件正在使用中,因此我无法在文件使用时写入或删除文本,而无需先关闭它。我希望能够找到 Streamreader 的解决方法,或者使用 Filestream 到 Streamreader 代码,这将允许我在使用文件时对其进行编辑。存在的问题是,我不知道如何使它与计时器一起工作,它只是非常快速地读取整个文件。非常感谢任何帮助或想法。

这里的问题是如何让注释掉的代码:

  1. 读取文本文件的一行,
  2. 让计时器计时
  3. 然后读取文本文件的下一行,以此类推。显然是在数据到达时对其进行处理。

【问题讨论】:

  • 是否可以一次读取整个文件,然后使用计时器从内存中读取数据?然后,您只需要确定何时再次读取文件
  • 你知道这样做的例子吗?
  • 尽量减少阅读时间。给System.IO.File.ReadAllLines一个机会
  • 打开文件,一次将其所有内容读入List<string> 或其他东西,关闭它,然后处理(“回放”)列表的内容。当您到达列表末尾时,重新打开文件,阅读,重复。

标签: c# streamreader datalog


【解决方案1】:

打开正在使用的文件

我认为您正在寻找的是 FileStreamFileShare.ReadWrite 为您的 StreamReader 实例(不是您已注释掉的实例)

var fs = new FileStream("C:\foo.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
var sr = new StreamReader(fs);

设置流的位置

根据您的 cmets,您似乎也无法定位流,这就是您可以这样做的方法...

fs.Position = 0; // note this is the FileStream not the StreamReader!
// alternatively, you could use Seek

顺序访问和随机访问的区别

最后,您可能想看看下面的顺序访问和随机访问之间的区别


一个潜在的解决方案

这是一个名为FileMonitor 的类,它将检查文件并在文件更改/更新时更新列表。

我知道您想要一个计时器来轮询文本文件中的数据,但如果计时器非常快,我已经优化了 FileMonitor 以观察文件的变化,并且只在有变化时提取。

请注意,这只会根据流的位置继续读取中断的位置。因此,如果在“提取”之前删除或修改了行,它将不起作用。这意味着它仅根据您的要求运行,并没有改进以处理许多其他场景,但它应该足以满足您的要求。

public class FileMonitor : IDisposable
{
    private readonly FileStream _file;
    private readonly StreamReader _reader;

    private long _position;
    private List<string> _lines;

    public FileMonitor(string file)
    {
        if (String.IsNullOrEmpty(nameof(file))) throw new ArgumentNullException(nameof(file));

        _lines = new List<string>();

        FileSystemWatcher watcher = new FileSystemWatcher();
        watcher.Path = Path.GetDirectoryName(file);
        watcher.Filter = Path.GetFileName(file);
        watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
        watcher.Changed += new FileSystemEventHandler(OnChanged);
        //watcher.Created += new FileSystemEventHandler(OnCreated);
        //watcher.Deleted += new FileSystemEventHandler(OnDeleted);
        //watcher.Renamed += new RenamedEventHandler(OnRenamed);

        // begin watching.
        watcher.EnableRaisingEvents = true;

        // begin reading
        _file = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
        _reader = new StreamReader(_file);
        _lines = ReadLines(_reader).ToList();
        _position = _file.Position;
    }

    private void OnChanged(object source, FileSystemEventArgs e)
    {
        List<string> update = ReadLines(_reader).ToList();
         // fix to remove the immidate newline
        if (update.Count() > 0 && String.IsNullOrEmpty(update[0])) update.RemoveAt(0);
        _lines.AddRange(update);
        _position = _file.Position;

        // just for debugging, you should remove this
        Console.WriteLine($"File: {e.FullPath} [{e.ChangeType}]");
    }

    public IEnumerable<string> Lines { get { return _lines; } }

    public void Reset()
    {
        _file.Position = 0;
        _position = _file.Position;
        _lines.Clear(); 
    }

    private static IEnumerable<string> ReadLines(StreamReader reader)
    {
        string line;
        while ((line = reader.ReadLine()) != null)
        {
            yield return line;
        }
    }

    public void Dispose()
    {
        _reader.Dispose();
        _file.Dispose();
    }
}

这是你如何将它与你的计时器一起使用的方法

private IEnumerable<string> _lines; // holds all the lines "extracted"

void Main()
{
    string file = @"C:\Data\foo.txt";

    using (var timer = new System.Timers.Timer())
    {
        timer.Interval = 2000; // 2 second interval
        timer.Elapsed += OnTimedEvent; // attach delegate
        timer.Enabled = true; // start the timer    

        // open the file
        using (var monitor = new FileMonitor(file))
        {
            _lines = monitor.Lines;

             // loop forever, remove this
            while (true) { }
        }
    }
}

public void OnTimedEvent(object sender, EventArgs e)
{
    // just for debugging, you should remove this
    Console.WriteLine($"current count: {_lines.Count()}");
}

如果不清楚,提取的数据将保存在字符串列表中。在上面,您可以使用monitor.Line 属性从监视器中获取“提取”数据。

【讨论】:

  • 注释掉的代码将允许我编辑文件,或删除文件中的所有数据。使用该代码的问题是字符串数据只是读取到最后而没有计时器延迟下一行阅读。如果我可以在函数之外声明它,它可能会正常工作。因为 Streamreader 是在函数外部声明的,所以代码按原样工作,允许计时器计时。
  • 我刚刚尝试了该代码,它只是立即读取到文件末尾没有任何区别。我最大的问题是在读取文本文件的下一行之间实现可变延迟时间,而不会阻止代码运行。
  • @CRIMSON501 为什么不使用SeekPosition 并转到流的开头?
  • 我读到最后,想再看一遍。你在代码中没有看到吗?
  • 我可以像 lineCount ++ 那样在循环增量中使用它吗? fs.Position = lineCount;
【解决方案2】:

行之有效的解决方案

 string line;
        if (!File.Exists(logFile))
        {
            viewLog.Text = "Play";
            alertTB.ForeColor = Color.Red;
            alertTB.Text = "File Does Not Exist | Log Data To Create File";
            chart.Text = "Scope On";
        }

        if (File.Exists(logFile))
        {
            var lineCount = File.ReadLines(logFile).Count();//read text file line count to establish length for array
            if (lineCount < 2)
            {
                viewLog.Text = "Play";
                alertTB.ForeColor = Color.Red;
                alertTB.Text = "File Exists | No Data Has Been Recorded";
                chart.Text = "Scope On";
            }

            if (counter < lineCount && lineCount > 0)//if counter is less than lineCount keep reading lines
            {
                line = File.ReadAllLines(logFile).Skip(counter).Take(lineCount).First();

                string[] dataLog = line.Split(new[] { ',' }, StringSplitOptions.None);
                //-----------------------------------------Handling my data 
                counter++;
            }
            else
            {
                counter = 0;
                timer2.Enabled = false;
            }
        }

这是我得到的修复,它允许编辑文件或删除文件的内容。在尝试加载文件之前,我得到了行数。然后我使用计数器遍历这些行。我可以根据计时器滴答间隔更改读取下一行之间的延迟、暂停或停止。

【讨论】:

    猜你喜欢
    • 2014-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-15
    • 2015-05-13
    相关资源
    最近更新 更多