Читать текстовый файл построчно, используя таймер - PullRequest
0 голосов
/ 30 июня 2018
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";
}

Проблема в том, что я читаю текстовый файл, полный переменных, обратно через графический интерфейс, как при воспроизведении видео. Как показывает код, он работает, и я могу контролировать тик таймера, чтобы изменить скорость воспроизведения. Проблема в том, что файл используется, поэтому я не могу писать или удалять текст, пока файл используется, не закрывая его в первую очередь. Я хотел бы либо найти обходной путь Streamreader, либо использовать код Filestream to Streamreader, который позволит мне редактировать файл во время его использования. Проблема в том, что я не могу понять, как заставить его работать с таймером, он просто очень быстро читает весь файл. Любая помощь или идеи с благодарностью.

Вопрос здесь в том, как получить закомментированный код для:

  1. читать строку текстового файла,
  2. есть таймер для отметки
  3. затем прочитайте следующую строку текстового файла и так далее. Очевидно, обработка данных по мере их поступления.

Ответы [ 2 ]

0 голосов
/ 03 июля 2018

Проверенный рабочий раствор

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

Это исправление, к которому я пришел, оно позволяет редактировать файл или удалять содержимое файла. Я получаю количество строк, прежде чем пытаться загрузить файл. Затем я использую счетчик для перебора строк. Я могу изменить задержку между чтением следующей строки на основе интервала времени таймера, приостановить или остановить его.

0 голосов
/ 30 июня 2018

Открытие файла во время его использования

Я думаю, что вы ищете FileStream с FileShare.ReadWrite для экземпляра вашего StreamReader (не для экземпляра, который вы закомментировали) ,

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

Настройка положения потока

Похоже, на основании ваших комментариев у вас возникли проблемы с позиционированием потока, вот как вы могли это сделать ...

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

Разница между последовательным и произвольным доступом

Наконец, вы можете взглянуть ниже, чтобы увидеть разницу между последовательным и произвольным доступом

concept


Потенциальное решение

Вот класс с именем 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.

...