How to write to a text file until the application is closed - c#

I would like to write to a text file, but I have small problem. When use the code below, it writes just once.
StreamWriter fileWriter = new StreamWriter("test.txt");
fileWriter.WriteLine(jointHead.Position.X);
fileWriter.Close();
When I write like this:
Debug.WriteLine(jointHead.Position.X);
it writes the X position until I close the application. How can I write to a text file like I write in Debug mode until I close the application. If I take fileWrite.Close() from where it stays, the program doesnt work.
Thank you...

From your description I am assuming that the code snippets you give are in a loop.
It's likely that you will get better performance by moving the file open/close outside of the loop (which will also cure your problem).
I you really want to keep opening/closing the file every time, then specify the append flag.
using (var fileWriter = new StreamWriter("test.txt", true))
{
fileWriter.WriteLine(jointHead.Position.X);
}

Try
StreamWriter fileWriter = new StreamWriter("test.txt", true);
fileWriter.WriteLine(jointHead.Position.X);
fileWriter.Close();
This will allow text written to be appended to the end of the file.
At the moment your writing from the beginning each time.
edit
If you wish to clear the file at the start of the application then just perform the following:
StreamWriter fileWriter = new StreamWriter("test.txt");
fileWriter.Write("");
fileWriter.Close();

I'd rather suggest you to use some sort of logger with a stringbuilder.
public class Logger {
private StringBuilder sb;
public Logger() {
sb = new StringBuilder();
}
public Log(String log) {
sb.Append(log).AppendLine();
}
public void Flush() {
File.WriteAllText(String.Format(#"D:\Logs\Log at {0:yyyy-MM-dd HH:mm:ss}.txt", DateTime.Now), sb.ToString());
sb.Clear();
}
}
This class is much more elegant and reusable solution. It is really acceptable if your target log is not very big.

Keep the stream writer open. But call Flush after the WriteLine call.
Alternatively you can open the file for appending, instead of recreating it for each line.
You might also want to look into an existing logging framework. There are many existing ones, no need to reinvent the wheel. Personally I'd use Common.Logging with a backend of your choice.

that constructor of the streamwriter will delete test.txt if it already existed. so every time that bit of code gets executed it will delete the file text.txt that it created earlier. instead, use the overload for the constructor of streamwriter that takes an additional bool to append to the existing test.txt file instead of replacing it:
StreamWriter fileWriter = new StreamWriter("test.txt", true);
alternatively, you could go with the File.AppendAllLines method to append your text to the file. then you don't need to worry about closing the file handle and the method name itself clearly states what's going to happen. to me this would be more convenient and not as obscure as the overloaded streamwriter constructor.
or alternatively, you could go for a logging framework like NLog. in that case NLog will take care of all your file operations so you're free of worries there then. also, you could configure NLog to write to whatever you like, like your file or, as you mentioned, the debug output window, or the event log, etc etc. also, you can bet on any file operations probably being a whole lot more efficient than your own implementation.

Related

Is it possible to use StreamWriter methods to append text to the file that was created with the File.AppendAllText() Method?

Is there a known problem for the StreamWriter's methods to deal with the files, that were created with File.AppendAllText method?
public void WriteLog(string msg){
if (msg != string.Empty){
string logFileName = "Protokoll.txt";
using (StreamWriter logWriter = new StreamWriter(logFileName, true)){
logWriter.WriteLine(msg);
}
}
}
vs, console, directory
I wasn't able to reproduce the problem. The Protokoll.txt file seems to be responsive (assuming from the last access date) but wont add any new lines. Although it is possible to open it with editor and write manually into it. Other txt files get along without any problems. The WriteLog is a part of a Server-Client School Project. It uses NetworkStream and is called from the ReceiveMessages method. Interesting hint about file location moving during code execution, #mjwills

If no text to write via StreamWriter, then discard (do not create) the file

I am using the StreamWriter to create a file and to write some text to that file. In some cases I have no text to write via StreamWriter, but the file was already created when StreamWriter was initialized.
using (StreamWriter sw = new StreamWriter(#"C:\FileCreated.txt"))
{
}
Currently I am using the following code, when StreamWriter is closed, to check if the FileCreated.txt content is empty, if it is delete it. I am wondering if there is a more elegant approach than this (an option within StreamWriter perhaps)?
if (File.Exists(#"C:\FileCreated.txt"))
{
if (new FileInfo(#"C:\FileCreated.txt").Length == 0)
{
File.Delete(#"C:\FileCreated.txt");
}
}
By the way, I must open a stream to write before I can check if there is any text because of some other logic in the code.
If you want to take input from the user bit by bit, you can make your source a StringBuilder, and then just commit to disk when you're done
StringBuilder SB = new StringBuilder();
...
SB.AppendLine("text");
...
if(SB.Length > 0)
File.WriteAllLines(SB.ToString());
Delaying opening the file until the first output would solve this problem, but it might create a new one (if there's a permission error creating the file, you won't find out until later, maybe when the operator is no longer at the computer).
Your current approach is decent. I don't see the need to test File.Exists, though, if you just closed a stream to it. Also consider the race condition:
You find that the file is zero-length
Another process writes to the file
You delete the file
Also consider that you might have permission to create a file, and not to delete it afterwards!
Doing this correctly requires using the raw Win32 API, as I described in a previous answer. Do note that a .NET stream could be used for the first file handle, as long as you specify the equivalent of FILE_SHARE_WRITE.
Revisit your assumptions, i.e. that you must open the stream before checking for content. Simply reorganize your logic.

Why isn't this working?

I am trying to just write an array of strings to a file, which SHOULD normally be an easy thing to do. However the following trivial code is throwing an IOException saying that the file is in use by another process. The problem is, the file doesn't even exist until this code is run. And I can guarantee you that there is no other process using the file. So how do I convince the stupid .NET framework that the file is not in use by another process and that it is okay to continue? Because this really shouldn't be that hard.
StreamWriter writer = new StreamWriter(ListFileName);
foreach (string s in InfoLineList)
{
writer.WriteLine(s);
}
This might be because you're not closing the stream when you're done with it, so some handle is getting stuck open somewhere. Perhaps the code is part of a web app, and the web server process keeps that lock around, or the code is being run multiple times. I'd recommend using the stream in a using block:
using(StreamWriter writer = new StreamWriter(ListFileName))
{
foreach (string s in InfoLineList)
{
writer.WriteLine(s);
}
}
This will make sure the StreamWriter is disposed of properly.
If you really want to know what has the file open, use SysInternal's Handle tool to check. I'd be willing to bet it's your own program.
Finally, as I said in my comments, the File.WriteAllLines() method can write an enumerable list of strings to a file all at once:
File.WriteAllLines(ListFileName, InfoListList);

The file is being used by another process, I must close it? How?

I am using a text file to have some data there for later purposes. So what I do is to check if file exists, if not I am creating a new file when I need. This gives me error saying that my file is still being used by a different process, but I'm not sure why that is.
This is how I do it. Here, I am checking if file exists which starts when program runs:
private void CreateLastOpenFile()
{
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
if (!File.Exists(file))
{
File.Create(file);
}
}
Now, I am adding some data to it while checking or creating a new file (I am having this in 2 places in my program):
CreateLastOpenFile();
File.WriteAllText(file, data);
What could be wrong here? I have read some examples from the Net, but didn't see anything about closing any files.
Try this. This will close the opened stream during file creation
if (!File.Exists(file))
{
FileStream str = File.Create(file);
str.Close();
}
File.Create is creating a FileStream that locks the file. You should close it. Actually, you don't even need to create a file. File.WriteAlltext will do it for you
You are not closing the stream handle that File.Create() returns.
Suggest you do not use File.Create() in your case. You can just use File.WriteAllText(file, data); - according to MSDN documentation it creates the file if it doesn't exist or overwrites the contents when file exists. After that closes the file stream.
I recommend you to create and fill with data the file in one step, using some class like StreamWriter that allows you to dispose the class, you should not have problem doing it this way, here is an example:
StreamWriter Swr = new StreamWriter(FilePath);
Swr.Write(Data);
Swr.Close();
Swr.Dispose();
//Doing the close and Dispose you get sure the file is not locked anymore
You can also use File.WriteAllText(string Path, string Data), this method does not lock the file.
If you are using below method to write the data into text file, you dont need to check if file exists and if not create it. "WriteAllText" takes cares of all these things by itself. It will create the file if not exists, write the data and close it, or overwrite the file if already exists.
File.WriteAllText(file, data);
if you are using writeAllText() or readAllText() method than close() method is not used as they closed file after reading or writing(above methods)

wait for a TXT file to be readable c#

My application use "FileSystemWatcher()" to raise an event when a TXT file is created by an "X" application and then read its content.
the "X" application create a file (my application detect it successfully) but it take some time to fill the data on it, so the this txt file cannot be read at the creation time, so im
looking for something to wait until the txt file come available to reading. not a static delay but something related to that file.
any help ? thx
Create the file like this:
myfile.tmp
Then when it's finished, rename it to
myfile.txt
and have your filewatcher watch for the .txt extension
The only way I have found to do this is to put the attempt to read the file in a loop, and exit the loop when I don't get an exception. Hopefully someone else will come up with a better way...
bool FileRead = false;
while (!FileRead)
{
try
{
// code to read file, which you already know
FileRead = true;
}
catch(Exception)
{
// do nothing or optionally cause the code to sleep for a second or two
}
}
You could track the file's Changed event, and see if it's available for opening on change. If the file is still locked, just watch for the next change event.
You can open and read a locked file like this
using (var stream = new FileStream(#"c:\temp\file.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
using (var file = new StreamReader(stream)) {
while (!file.EndOfStream) {
var line = file.ReadLine();
Console.WriteLine(line);
}
}
}
However, make sure your file writer flushes otherwise you may not see any changes.
The application X should lock the file until it closes it. Is application X also a .NET application and can you modify it? In that case you can simply use the FileInfo class with the proper value for FileShare (in this case FileShare.Read).
If you have no control over application X, the situation becomes a little more complex. But then you can always attempt to open the file exclusively via the same FileInfo.Open method. Provide FileShare.None in that case. It will attempt to open the file exclusively and will fail if the file is still in use. You can perform this action inside a loop until the file is closed by application X and ready to be read.
We have a virtual printer for creating pdf documents, and I do something like this to access that document after it's sent to the printer:
using (FileSystemWatcher watcher = new FileSystemWatcher(folder))
{
if(!File.Exists(docname))
for (int i = 0; i < 3; i++)
watcher.WaitForChanged(WatcherChangeTypes.Created, i * 1000);
}
So I wait for a total of 6 seconds (some documents can take a while to print but most come very fast, hence the increasing wait time) before deciding that something has gone awry.
After this, I also read in a for loop, in just the same way that I wait for it to be created. I do this just in case the document has been created, but not released by the printer yet, which happens nearly every time.
You can use the same class to be notified when file changes.
The Changed event is raised when changes are made to the size, system attributes, last write time, last access time, or security permissions of a file or directory in the directory being monitored.
So I think you can use that event to check if file is readable and open it if it is.
If you have a DB at your disposal I would recommend using a DB table as a queue with the file names and then monitor that instead. nice and transactional.
You can check if file's size has changed. Although this will require you to poll it's value with some frequency.
Also, if you want to get the data faster, you can .Flush() while writing, and make sure to .Close() stream as soon as you will finish writing to it.

Categories