Читать текстовый файл построчно, используя таймер
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, который позволит мне редактировать файл во время его использования. Проблема в том, что я не могу понять, как заставить его работать с таймером, он просто очень быстро читает весь файл. Любая помощь или идеи с благодарностью.
Проблема здесь в том, как получить закомментированный код для:
- прочитать строку текстового файла,
- есть таймер, чтобы отметить
- затем прочитайте следующую строку текстового файла и так далее. Очевидно, обработка данных по мере их поступления.
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;
}
}
Это исправление, к которому я пришел, оно позволяет редактировать файл или удалять его содержимое. Я получаю количество строк, прежде чем пытаться загрузить файл. Затем я использую счетчик для перебора строк. Я могу изменить задержку между чтением следующей строки, основываясь на интервале между таймерами, приостановить или остановить его.
Открытие файла во время его использования
Я думаю, что вы ищете 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
Разница между последовательным и произвольным доступом
Наконец, вы можете посмотреть ниже, чтобы увидеть разницу между последовательным и произвольным доступом
Потенциальное решение
Вот класс называется 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
имущество.