Read updated text file every x seconds - c#

I am working on making a program that is going to read xy coordinates in a text file from a drawing application. I am thinking that the sets of coordinates will start getting detected from the start to the end of the drawn line. For each line drawn there is gonna be a new set of xy coordinates. Then I want to make a program that is
Going to look for updated sets of xy coordinates every x seconds
If the text file is updated I want the new contents of the text file to be written in the console
If the file is not yet updated I don't want it to do anything
Also I am wondering if the best thing is to
Have a single text file that get its contents changed with the new set of xy coordinates?
Or to have a single text file that get the new set of xy coordinates addes to the previous sets of coordinates?
Or have a new text file to be created for every new set of xy coordinates?
I am really new to programming and would really appreciate if I got some kind of help. I have been programming in C# in Visual Studio. I am pretty sure I need to use FileSystemWatcher, I just don't know how to use it....
So far I have only done this:
class Test
{
public static void Main()
{
while (true)
{
try
{
using (StreamReader sr = new StreamReader("TestFile.txt"))
{
String line = sr.ReadToEnd();
Console.WriteLine(line);
}
}
catch (Exception e)
{
Console.WriteLine("This file doesn't excist:");
Console.WriteLine(e.Message);
}
Thread.Sleep(2000);
}
}
}

Initialize a watcher as follows:
FileSystemWatcher watcher = new FileSystemWatcher(_folder_name_)
{
NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size
};
watcher.Changed += watcher_Changed;
watcher.EnableRaisingEvents = true;
Event handler:
void watcher_Changed(object sender, FileSystemEventArgs e)
{
if (e.Name == "TestFile.txt")
using (StreamReader sr = new StreamReader(e.FullPath))
{
String line = sr.ReadToEnd();
Console.WriteLine(line);
}
}
Alternative way is to use a System.Threading.Timer.
If a text is appended to the file incrementally, I recommend you to use database, sockets etc instead of file.

Thank you so much for the quick answer and the help! :)
Just before I saw your answer I was working on another way of doing it. The text file will be read and written to the console when the text file exists. When it's read it will be deleted and are waiting for another text file to appear (another set of xy-coordinates). I am not going to have the program to write "Waiting for new file..." in the end, it's just to see that things are working the way I've been thinking. Also I think the Web application need to receive some kind of a message that the text file is read and is now ready to receive a new text file.
Any thoughts if this is an OK way of doing it too?
class Testing
{
public static void Main()
{
string fileName = "TestFile.txt";
while (true)
{
if(File.Exists(fileName))
{
using (StreamReader sr = new StreamReader(fileName))
{
String line = sr.ReadToEnd();
Console.WriteLine(line);
}
}
else
{
Console.WriteLine("Waiting for new file...");
}
File.Delete(fileName);
Thread.Sleep(5000);
}
}
}
Since I'm new, I'm just asking to be sure. I don't know what is going to work out the best when it comes to every part of the system working together. At least I have two ways to work with now! :D

Related

I'm trying to save and load choices and its giving me the same error over and over

I keep getting
The process cannot access the file another process is using it
Can someone tell me what's wrong?
public void SaveCheckedChoices()
{
using(StreamWriter writer = new StreamWriter(dataFile))
{
try
{
// Autorun
writer.WriteLine(sublimeAutorun);
writer.WriteLine(sublimePackagesAutorun);
writer.WriteLine(sharpDevelopAutorun);
writer.WriteLine(eclipseAutorun);
writer.WriteLine(outlookAutorun);
writer.WriteLine(youtubeAutorun);
writer.WriteLine(githubAutorun);
writer.WriteLine(trelloAutorun);
File.SetAttributes(dataFile, FileAttributes.Hidden);
}
finally
{
writer.Close();
}
}
}
public void LoadCheckedChoices()
{
StreamReader sr = new StreamReader(dataFile);
// Autorun
sublime.Checked = Convert.ToBoolean(sr.ReadLine());
sublimePackages.Checked = Convert.ToBoolean(sr.ReadLine());
sharpDevelop.Checked = Convert.ToBoolean(sr.ReadLine());
eclipse.Checked = Convert.ToBoolean(sr.ReadLine());
outlook.Checked = Convert.ToBoolean(sr.ReadLine());
youtube.Checked = Convert.ToBoolean(sr.ReadLine());
github.Checked = Convert.ToBoolean(sr.ReadLine());
trello.Checked = Convert.ToBoolean(sr.ReadLine());
sr.Close();
}
I made sure the file was created and that the only thing that was running was SharpDevelop and it still gives me the error, could someone please tell me what the problem is.
File.SetAttributes(dataFile, FileAttributes.Hidden);
Must be moved to after the writer.Close();. I believe it needs exclusive access to the file.
Also you can use File.ReadAllLines in the second function.
And the most important part of my answer. Never, ever, ever, ever, I must insist, NEVER hide a configuration file; EVER. It will come back to haunt you.
EDIT:
For proper serialization read xml or json or the documentation of newtonsoft.json

How to monitor a logfile that seems to be open all the time (much like notepad++ does)?

I'm trying to build a small program to monitor my pfirewall.log, but I can't seem to open it.
I found quite many (simple) answers, that all kinda say
// use FilesystemWatcher
// open FileStream
// read from last position to end
// output new lines
The problem here is: The file seems to always be opened by another process already. I guess that's the windows process writing to the file, since it's getting written to all the time, as Notepad++ shows me.
Which means, Notepad++ can for some reason do what I can not: Read the file despite it being opened already.
I initialize my monitor in the constructor:
public FirewallLogMonitor(string path)
{
if (!File.Exists(path))
throw new FileNotFoundException("Logfile not found");
this.file = path;
this.lastPosition = 0;
this.monitor = new FileSystemWatcher(Path.GetDirectoryName(path), Path.GetFileName(path));
this.monitor.NotifyFilter = NotifyFilters.Size;
}
And try to read the file on monitor.Changed event:
private void LogFileChanged(object sender, FileSystemEventArgs e)
{
using (FileStream stream = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read))
using (StreamReader reader = new StreamReader(stream))
{
stream.Seek(this.lastPosition, SeekOrigin.Begin);
var newLines = reader.ReadToEnd();
this.lastPosition = stream.Length;
var filteredLines = filterLines(newLines);
if (filteredLines.Count > 0)
NewLinesAvailable(this, filteredLines);
}
}
It always throws the IOException on new FileStream(...) to tell me the file is already in use.
Since Notepad++ does it, there has to be a way I can do it too, right?
**Edit: ** A button does this:
public void StartLogging()
{
this.IsRunning = true;
this.monitor.Changed += LogFileChanged;
this.monitor.EnableRaisingEvents = true;
}
**Edit2: ** This is not a duplicate of FileMode and FileAccess and IOException: The process cannot access the file 'filename' because it is being used by another process, since that one assumes I have control over the writing process. Will try the other suggestions, and report back with results.
If i understand your question you can use the notepad++ itself with a plugin to monitor you need to go to:
plugins -> Document Moniter -> Start to monitor
if you dont have this plugin you can download it here:
http://sourceforge.net/projects/npp-plugins/files/DocMonitor/

How do I read from a file?

I'm trying to get my program to read code from a .txt and then read it back to me, but for some reason, it crashes the program when I compile. Could someone let me know what I'm doing wrong? Thanks! :)
using System;
using System.IO;
public class Hello1
{
public static void Main()
{
string winDir=System.Environment.GetEnvironmentVariable("windir");
StreamReader reader=new StreamReader(winDir + "\\Name.txt");
try {
do {
Console.WriteLine(reader.ReadLine());
}
while(reader.Peek() != -1);
}
catch
{
Console.WriteLine("File is empty");
}
finally
{
reader.Close();
}
Console.ReadLine();
}
}
I don't like your solution for two simple reasons:
1)I don't like gotta Cath 'em all(try catch). For avoing check if the file exist using System.IO.File.Exist("YourPath")
2)Using this code you haven't dispose the streamreader. For avoing this is better use the using constructor like this: using(StreamReader sr=new StreamReader(path)){ //Your code}
Usage example:
string path="filePath";
if (System.IO.File.Exists(path))
using (System.IO.StreamReader sr = new System.IO.StreamReader(path))
{
while (sr.Peek() > -1)
Console.WriteLine(sr.ReadLine());
}
else
Console.WriteLine("The file not exist!");
If your file is located in the same folder as the .exe, all you need to do is StreamReader reader = new StreamReader("File.txt");
Otherwise, where File.txt is, put the full path to the file. Personally, I think it's easier if they are in the same location.
From there, it's as simple as Console.WriteLine(reader.ReadLine());
If you want to read all lines and display all at once, you could do a for loop:
for (int i = 0; i < lineAmount; i++)
{
Console.WriteLine(reader.ReadLine());
}
Use the code below if you want the result as a string instead of an array.
File.ReadAllText(Path.Combine(winDir, "Name.txt"));
Why not use System.IO.File.ReadAllLines(winDir + "\Name.txt")
If all you're trying to do is display this as output in the console, you could do that pretty compactly:
private static string winDir = Environment.GetEnvironmentVariable("windir");
static void Main(string[] args)
{
Console.Write(File.ReadAllText(Path.Combine(winDir, "Name.txt")));
Console.Read();
}
using(var fs = new FileStream(winDir + "\\Name.txt", FileMode.Open, FileAccess.Read))
{
using(var reader = new StreamReader(fs))
{
// your code
}
}
The .NET framework has a variety of ways to read a text file. Each have pros and cons... lets go through two.
The first, is one that many of the other answers are recommending:
String allTxt = File.ReadAllText(Path.Combine(winDir, "Name.txt"));
This will read the entire file into a single String. It will be quick and painless. It comes with a risk though... If the file is large enough, you may run out of memory. Even if you can store the entire thing into memory, it may be large enough that you will have paging, and will make your software run quite slowly. The next option addresses this.
The second solution allows you to work with one line at a time and not load the entire file into memory:
foreach(String line in File.ReadLines(Path.Combine(winDir, "Name.txt")))
// Do Work with the single line.
Console.WriteLine(line);
This solution may take a little longer for files because it's going to do work MORE OFTEN with the contents of the file... however, it will prevent awkward memory errors.
I tend to go with the second solution, but only because I'm paranoid about loading huge Strings into memory.

Writing data to text file

I am sending and receiving data using COM port (serial). I have written the following code. This is actually my first C# project as I am kinda new to it. I am trying to write the received data to the text file on my desktop, the program actually creates the file but writes nothing in it. Similarly, I am able to see the received data on the console but it is not being written to the text file. Any help on what I am doing wrong will be much appreciated.
Thank you. The code is below.
class Program
{
SerialPort p = new SerialPort("COM7", 300, Parity.None, 8, StopBits.One);
string sbuffer = string.Empty;
byte i = 0;
static void Main(string[] args)
{
new Program();
}
Program()
{
string[] names = SerialPort.GetPortNames();
Console.WriteLine("Serial ports:");
foreach (string name in names)
{
Console.WriteLine(name);
}
Console.WriteLine("Using COM7");
p.Open();
string data_ = "$1RB\r";
Console.WriteLine("Writing data: {0}",data_);
p.Write(data_);
p.DataReceived += new SerialDataReceivedEventHandler(p_DataReceived);
Console.ReadKey();
p.Close();
}
void p_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Thread.Sleep(5);
sbuffer += (sender as SerialPort).ReadExisting();
i++;
if (i > 9)
{
Console.WriteLine(sbuffer);
System.IO.File.WriteAllText(#"C:\Users\myname\Desktop\WriteText.txt", sbuffer);
sbuffer = string.Empty;
}
}
}
}
You could use events, or simply use this method and pass your data string to it. It will simply append to the file as long as it exists, or create a new file if it does not. The data written should be identical to whatever output is appearing in your console screen.
static void WriteOutputToTextFile(string _data)
{
string FolderName = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); //set destination as your desktop
using (StreamWriter SW = new StreamWriter(FolderName + "\\test.txt", true)) //true makes it append to the file instead of overwrite
{
SW.WriteLine(_data);
SW.Close();
}
}
You are opening and overwriting the same file again and again. Use the FileStream (or even better, StreamWriter) class instead, keep the stream open together with the serial port and close it when you're done.
Also, if you transmit text via the serial port, you might want to consider the SerialPort.ReadLine() method that is much easier to use.
Extending #Alan's answer, you can use File.AppendAllText instead of File.WriteAllText which will overwrite the file again and again. So if you receive empty text before you check the file, the file will be overwritten with empty text.

save file without using save file dialog

I am working on this project still and I am running into a problem. Well here is what I need to do.
When the user clicks the “Save” button, write the selected record to
the file specified in txtFilePath (absolute path not relative) without
truncating the values currently inside and handle any exceptions that arise.
Ok here is my code:
private void Save_Click(object sender, EventArgs e)
{
string filePath = txtFilePath.Text;
if (!File.Exists(filePath))
{
FileStream fs = File.Create(filePath);
fs.Close();
}
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
using (StreamWriter sw = new StreamWriter(fs))
{
foreach (string line in employeeList.Items)
{
sw.WriteLine(line);
}
}
}
}
Now when I go onto my program and want to save something from the employeelist.text that its not being saved to the place I am saving it at. I don;t know if I am missing something in my code or what but it will not save. Here is an example:
I add a person name to this list in employeelist and in the textbox I
have a file called C:\employess\employeelist.txt I want to save it to.
I click the save button then I go to that employeelist and it is not
being saved.
I don't know what I am doing wrong I have been looking online for a solution but I haven't found anything yet. Thanks
Some things to double-check:
Make sure you don't have the employeelist.txt file open when you're testing
Make sure you don't have invalid characters in your file name
Make sure your application has permission to save the file to the location you specified
Use the debugger to step-through your code and look for swallowed exceptions -- there must be a reason the file is not created.
Check that your Save_Click event is wired up to your button -- is the code in your example even running?
Once you check those things, you may want to follow this example for the create vs. append requirement of your project:
string path = txtFilePath.Text;
// This text is added only once to the file.
if (!File.Exists(path))
{
using (StreamWriter sw = File.CreateText(path))
{
foreach (var line in employeeList.Items)
sw.WriteLine(line.ToString());
}
}
else
{
using (StreamWriter sw = File.AppendText(path))
{
foreach (var line in employeeList.Items)
sw.WriteLine(line.ToString());
}
}
This will create the file if it doesn't exist, or append to it if it does.
Checking that the file exists and then creating it is a bit unnecessary as this can all be handled by the StreamWriter/FileStream parts. So your above function can be simplified into the following:
public void Save_Click(object sender, EventArgs e)
{
StreamWriter file =
new StreamWriter(txtFilePath.Text, true);//Open and append
foreach (object item in employeeList.Items) {
file.WriteLine(item.toString());
}
file.Close();
}
[Updated]
What are the types of txtFilePath and employeeList the former suggests it's a text box, the later suggests it's bound to a non-GUI element perhaps? (WAG)
You might also want to append a blank line at the end so that on further saves you can tell it was an append rather than one long list (depending on your needs of course)
Starting with .Net Framework 4 you can do it like this:
private void Save_Click(object sender, EventArgs e)
{
File.AppendAllLines(txtFilePath.Text, employeeList.Items);
}
Of course, you probably would want to add a check to have a valid path and a valid enumeration of strings.
If the path looks like a relative one (i.e. doesn't begin with a drive letter), then it will be interpreted that way.
If you put a full path in the text box, does the file get saved in the proper place? If so, perhaps this is what was intended.
If the user doesn't put in a full path, do you have a way to make it one (for example, just sticking C:\ at the beginning)? Or at least can you tell when there isn't a full path, and reject the request?

Categories