Read log file from last read position - c#

This is my working code, I have a filewatcher monitoring my log file, when the file updates (it updates a lot) it reads the log and outputs the lines that comply with the regex to a textbox. The problem with it is that it reads the file from the beginning and re-prints the regexed lines again so I get repeated data in the textbox. I also don't know if I have it setup correctly to run the file read from a separate thread so my program don't "freeze" while reading large log files.
private void btnStart_Click(object sender, EventArgs e)
{
if ((Properties.Settings.Default.setting_logfile != "") && (Properties.Settings.Default.setting_logfolder != ""))
{
if (btnStart.Text == "Start Parsing")
{
// change text on button and switch status image
btnStart.Text = "Stop Parsing";
pbStatus.Image = Properties.Resources.online;
new Thread(() => Run()).Start();
}
else
{
btnStart.Text = "Start Parsing";
pbStatus.Image = Properties.Resources.offline;
fsWatcher.EnableRaisingEvents = false;
}
}
else
{
tbOutput.Text = "Please select a log file to parse.";
}
}
private void Run()
{
try
{
fsWatcher.Changed += new FileSystemEventHandler(OnChanged);
fsWatcher.EnableRaisingEvents = true;
}
catch (Exception ex)
{
MessageBox.Show("An error occurred: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void OnChanged(object source, FileSystemEventArgs e)
{
string line;
Regex pattern = new Regex(#"\[[\w :]+\]\s<SYSTEMWIDE_MESSAGE>:");
Stream stream = File.Open(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
StreamReader streamReader = new StreamReader(stream);
while ((line = streamReader.ReadLine()) != null)
{
Match match = pattern.Match(line);
if (match.Success)
{
tbOutput.AppendText(line + "\r\n");
}
}
streamReader.Close();
stream.Close();
}

You could remember the last position that you read at and start from there.
Regex pattern = new Regex(#"\[[\w :]+\]\s<SYSTEMWIDE_MESSAGE>:");
long lastPosition = 0;
private void OnChanged(object source, FileSystemEventArgs e)
{
string line;
Stream stream = File.Open(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
stream.Seek(lastPosition, SeekOrigin.Begin);
StreamReader streamReader = new StreamReader(stream);
while ((line = streamReader.ReadLine()) != null)
{
if (pattern.Match(line).Success)
{
tbOutput.AppendText(line + Environment.NewLine);
}
}
lastPosition = stream.Position; // may need to subtract 1!!!
streamReader.Close();
stream.Close();
}

Related

c# FileSystemWatcher triggers twice when listening to OnChanged

Trying to implement FileSystemWatcher but the OnChanged function is called twice when the file is saved. based on some other posts, I suspect the LastWrite filter has multiple events? I thought the NotifyFilters would limit it to only firing when the file is written to, but something else is causing the function to run twice. e.ChangeType only tells me the file changed, but not exactly how. Is there a way to limit this to running only once?
public MainWindow()
{
InitializeComponent();
FileSystemWatcher fsw = new FileSystemWatcher(path);
fsw.NotifyFilter = NotifyFilters.LastWrite;
fsw.EnableRaisingEvents = true;
fsw.Changed += new FileSystemEventHandler(OnChanged);
}
private void OnChanged(object sender, FileSystemEventArgs e)
{
if (newString == null)
{
using (StreamReader sr = new StreamReader(new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
{
lastString = sr.ReadToEnd();
}
difference = lastString;
} else {
using (StreamReader sr = new StreamReader(new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
{
newString = sr.ReadToEnd();
}
int newCount = newString.Count();
int count = lastString.Count();
// MessageBox.Show("last:" + lastString.Count().ToString(), "next: " + newString.Count());
difference = newString.Remove(0,5);
lastString = newString;
}
Application.Current.Dispatcher.Invoke(new Action(() => { tb_content.Text = difference; }));
MessageBox.Show(e.ChangeType.ToString(), "");
}
}
You can filter it out yourself, as I've posted here.
An alternative to Frederik's answer:
A small workaround that comes to mind would be to prevent the OnChanged method from executing if it is already executing.
For example:
private bool IsExecuting { get; set; }
private void OnChanged(object sender, FileSystemEventArgs e)
{
if (!IsExecuting)
{
IsExecuting = true;
// rest of your code
IsExecuting = false;
}
}

How to send CheckedListBox selection into textfile?

I'm trying to code on my own for the first time, and decided to make a music player on Winforms.
I have a CheckedListBox that is already populated with the names of songs in a folder.
When I click a button, it's supposed to send the names of my selected songs into a .txt file for further manipulation, before closing the form.
For simplification, I'm just going with 1 selected song first.
private void selectbtn_Click(object sender, EventArgs e)
{
selectedSongs = checkedListBox1.CheckedItems.ToString();
songRecord.writeRecord(selectedSongs); //i initialised my streamreader/streamwriter class and called it songRecord
this.Close();
}
in my streamreader/writer class, this is what I have
class DataRecord
{
public void writeRecord(string line)
{
StreamWriter sw = null;
try
{
sw = new StreamWriter(#"C:\Users\Me\Desktop\JAM_MACHINE\record.txt", true);
sw.WriteLine(line);
}
catch (FileNotFoundException)
{
Console.WriteLine("Error: File not found.");
}
catch (IOException)
{
Console.WriteLine("Error: IO");
}
catch(Exception)
{
throw;
}
finally
{
if (sw != null)
sw.Close();
}
}
public void readRecord()
{
StreamReader sr = null;
string myInputline;
try
{
sr = new StreamReader(#"C:\Users\Me\Desktop\JAM_MACHINE\record.txt");
while ((myInputline = sr.ReadLine()) != null) ; //readline reads whole line
Console.WriteLine(myInputline);
}
catch (FileNotFoundException)
{
Console.WriteLine("Error: File not found");
}
catch(IOException)
{
Console.WriteLine("Error: IO");
}
catch (Exception)
{
throw;
}
finally
{
if (sr != null)
sr.Close();
}
}
}
When I run it, the .txt file doesn't show my selection. It only shows:
System.Windows.Forms.CheckedListBox+CheckedItemCollection
What went wrong?
Iterate through the CheckedItems Collection and collect each item inside a string array. I assume you fill the checkedListBox with strings
private void selectbtn_Click(object sender, EventArgs e)
{
string[] checkedtitles = new string[checkedListBox1.CheckedItems.Count];
for (int ii = 0; ii < checkedListBox1.CheckedItems.Count; ii++)
{
checkedtitles[ii] = checkedListBox1.CheckedItems[ii].ToString();
}
string selectedSongs = String.Join(Environment.NewLine, checkedtitles);
songRecord.writeRecord(selectedSongs);
this.Close();
}

DataGridView and copy image

I met one problem when I tried to copy file.
Error description
I worked with DataGridView and PictureBox.
Deguber of VS 2015 stopped me at
FileStream fs = File.Open(file, FileMode.Open);
in function CopyFile. I cant understand what's wrong i did.
This is some code (C#, .NET 4.5.1) from main form:
static string CopyFile(string file, string to)
{
FileInfo fileInfo = new FileInfo(file);
byte tmp = 0;
string temp = to + "\\" + fileInfo.Name;
FileStream newFile = File.Open(temp, FileMode.Create);
try
{
FileStream fs = File.Open(file, FileMode.Open);
for (int i = 0; i < fileInfo.Length; i++)
{
tmp = (byte)fs.ReadByte();
newFile.WriteByte(tmp);
}
fs.Close();
}
catch (FileNotFoundException ex)
{
MessageBox.Show("Не вдалося найти файл.");
}
newFile.Close();
return temp;
}
private void WriteNewUserToFile(User item, string pathToFile)
{
StreamWriter sw = new StreamWriter(File.Open(#pathToFile, FileMode.Append, FileAccess.Write));
sw.WriteLine(string.Format("{0}, {1}, {2}, {3}, {4}, {5}",
item.Id,
item.Image,
item.FirstName,
item.LastName,
item.Email,
item.Phone));
sw.Close();
}
private void btnAddUser_Click(object sender, EventArgs e)
{
AddUserForm dlg = new AddUserForm();
if (dlg.ShowDialog() == DialogResult.OK)
{
User item = dlg.NewUser;
item.Image = CopyFile(item.Image, "images");
WriteNewUserToFile(item, "data/users.dat");
users.Add(item);
//this.AddNewDataGridRow(item);
}
}
And some code of AddNewUserForm:
public User NewUser
{
get { return newUser; }
set { newUser = value; }
}
private void btnImage_Click(object sender, EventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
if (dlg.ShowDialog() == DialogResult.OK)
{
txtImage.Text = dlg.FileName;
try
{
picboxImage.Image = Image.FromFile(txtImage.Text);
}
catch
{
picboxImage.Image = Image.FromFile(#"images\NoImg.bmp");
}
}
}
private void btnApply_Click(object sender, EventArgs e)
{
NewUser = new User
{
Id = Convert.ToInt32(txtId.Text),
LastName = txtLastName.Text,
FirstName = txtFirstName.Text,
Email = txtEmail.Text,
Phone = txtPhone.Text,
Image = txtImage.Text
};
this.DialogResult = DialogResult.OK;
}
If somebody need all project/code, click here (download VS project).
When you set the Image for the PictureBox using the following code, the call keeps the file handle open. So when you try to open the file again you encounter the exception.
picboxImage.Image = Image.FromFile(txtImage.Text);
According to this accepted answer, when the file handle is closed is unpredictable, in some cases, the handle won't be closed even if you explicitly close the Image.
So you may use the technique in that answer like this, to ensure the file handle is closed properly.
picboxImage.Image = Image.FromStream(new MemoryStream(File.ReadAllBytes(txtImage.Text)));

StreamReader Multiple lines

I am trying to figure out how to read multiple lines whith StreamReader. I have a text file with a list of commands inside it that I need to read from. My code works, however it will only read the first line. This causes me to have to move all my commands to a single line with a space between them. This is not a very tidy way of doing this seeing as I need to leave comments next to the commands. Example: CONNECT: "Connects to given IP."
public void ConsoleEnter_KeyDown(object sender, KeyEventArgs e)
{
string line;
if (e.KeyCode == Keys.Enter)
{
// Read the file and display it line by line.
StreamReader file = new StreamReader("C:\\Users\\Home\\Desktop\\commands.txt");
while ((line = file.ReadLine()) != null)
{
if (line.Contains(ConsoleEnter.Text))
{
COMBOX.Items.Add(ConsoleEnter.Text);
COMBOX.Items.Remove("");
ConsoleEnter.Text = "";
}
else
{
COMBOX.Items.Add("Invalid Command");
COMBOX.Items.Remove("");
ConsoleEnter.Text = "";
}
}
}
}
This is what am using in one of my app and its working fine hope it'll help you out.......
if (TxtPath.Text != string.Empty)
{
StreamReader srr = new StreamReader(TxtPath.Text);
try
{
ss = srr.ReadToEnd().Split('\n');
MessageBox.Show("File Successfully Loded in Memory \n" + TxtPath.Text, "System Manager", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
catch (Exception)
{
throw new Exception("File are not readable or write protacted");
}
LblLineCount.Text = ss.Count().ToString();
}
else
{
MessageBox.Show("Please Browse any Log File 1st", "System Manager", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
you can also trim the
.Split('\n')
to take all data in single line, i can't try it right now but if check it will get u out of stuck...........
u should empty the variable after the loop, not inside the loop
public void ConsoleEnter_KeyDown(object sender, KeyEventArgs e)
{
string line;
if (e.KeyCode == Keys.Enter)
{
// Read the file and display it line by line.
StreamReader file = new StreamReader("C:\\Users\\Home\\Desktop\\commands.txt");
while ((line = file.ReadLine()) != null)
{
if (line.Contains(ConsoleEnter.Text))
{
COMBOX.Items.Add(ConsoleEnter.Text);
}
else
{
COMBOX.Items.Add("Invalid Command");
}
}
COMBOX.Items.Remove("");
ConsoleEnter.Text = "";
}
}
public void ConsoleEnter_KeyDown(object sender, KeyEventArgs e)
{
string line;
string path = #"C:\\Users\\Home\\Desktop\\commands.txt";
WebClient client = new WebClient();
System.IO.Stream stream = client.OpenRead(path);
System.IO.StreamReader str = new StreamReader(stream);
string Text=str.ReadToEnd();
string[] words = Text.Split(':');
if (e.KeyCode == Keys.Enter)
{
for(int i=1;i<words.Length;i++)
{
if (string.compare(words[i],textBox1.text)==0)
{
COMBOX.Items.Add(ConsoleEnter.Text);
COMBOX.Items.Remove("");
ConsoleEnter.Text = "";
}
else
{
COMBOX.Items.Add("Invalid Command");
COMBOX.Items.Remove("");
ConsoleEnter.Text = "";
}
}
}
}
try this ..
use namespace using System.Net;

working with StreamReader and text files

I want to put a test loop on the button click event. When I click this button, it reads the contents of the text file, but I want it to pop up an error message showing “unable to read file”, if it’s not a text file....
This is my code
private void button3_Click(object sender, EventArgs e)
{
StreamReader sr = new StreamReader(textBox1.Text);
richTextBox1.Text = sr.ReadToEnd();
sr.Close();
}
How can I go about it?
A few if-statements and the namespace System.IO will do it
string filename = textBox1.Text;
if (Path.GetExtension(filename).ToLower()) == ".txt") {
if (File.Exists(filename)) {
// Process the file here
} else {
MessageBox.Show("The file does not exist");
}
} else {
MessageBox.Show("Not a text file");
}
Not the best code, but it should work. Ideally you would separate the logic into two methods, a function to check the file exists and is a text file (returning a bool), another to read the contents if the check function returned true and populate the textbox with the contents.
EDIT: This is better:
private void button3_Click(object sender, EventArgs e)
{
string filePath = textBox1.Text;
bool FileValid = ValidateFile(filePath);
if (!IsFileValid)
{
MessageBox.Show(string.Format("File {0} does not exist or is not a text file", filePath));
}
else
{
textbox2.Text = GetFileContents(filePath);
}
}
private bool IsFileValid(string filePath)
{
bool IsValid = true;
if (!File.Exists(filePath))
{
IsValid = false;
}
else if (Path.GetExtension(filePath).ToLower() != ".txt")
{
IsValid = false;
}
return IsValid;
}
private string GetFileContents(string filePath)
{
string fileContent = string.Empty;
using (StreamReader reader = new StreamReader(filePath))
{
fileContent = reader.ReadToEnd();
}
return fileContent;
}

Categories

Resources