I got a problem with reading a text file, it's not the reading it's self that is a problem it is when I should read it.
I got a server program (made by an external company so I got no control over it) where you can put files in. The server see's a new file has arrived reads it and does things with it and then he puts a result back. So I'm waiting for the file to be ready, but I can't read it to early cause I don't know if it exists already. So I'm doing this:
while (IsFileLocked(file))
{
Thread.Sleep(25);
}
private bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
Now this really helps to check if the file is readable and I never get any IOExceptions anymore when I'm reading. Now I start the reading but sometimes I just read an empty file. And I'm pretty sure it shouldn't be empty. It's not a bug of the server program (I'll explain later).
Here is the code where the problem starts:
using (StreamReader streamReader = file.OpenText())
{
while (!streamReader.EndOfStream)
{
// here starts the reading
}
}
But when I use this code I don't get the problem:
using (StreamReader streamReader = file.OpenText())
{
Thread.sleep(1000);
while (!streamReader.EndOfStream)
{
// here starts the reading
}
}
So my guess is that the file is empty when I can open it but it has no text in it.
I changed the Thread.sleep to 100 miliseconds and then I get the problem again. When I changed it to 500 the problem was solved again.
Now my software needs to run on a lot of different computers so I don't know how fast they are, but I'm afraid if I set the timer to low I might get problems on other computers. But I don't want my users to be waiting for there info to long.
Is waiting the only option or is there another way?
Will there be a problem on other computers with different hardware configuration?
Edit: I tried FileSystemWatcher, and it is not the solution!
Waiting for a file to be created in C# - SO
The tool you need to add is a FileWatcher (see MSDN System.IO.FileWatcher). This will allow you to monitor activity and add event handlers to response to file events. You can respond to file created by adding a handler for file changed.
Simply you can do like this:
http://olioul.wordpress.com/2012/01/08/4-text-readwrite-in-text-document/
Related
how to find whether specific .txt file is opened in notepad?
I have tried solutions mentioned here
Is there a way to check if a file is in use?
But they work fine for Word and pdf file but not working for txt file opened in Notepad.
here is code I have wrote.
public bool IsFileOpen(string strFileName)
{
bool retVal = false;
try
{
if (File.Exists(pstrFileName))
{
using (FileStream stream = File.OpenWrite(pstrFileName))
{
try
{
}
catch (IOException)
{
retVal = true;
}
finally
{
stream.Close();
stream.Dispose();
}
}
}
}
catch (IOException)
{ //file is opened at another location
retVal = true;
}
catch (UnauthorizedAccessException)
{ //Bypass this exception since this is due to the file is being set to read-only
}
return retVal;
}
am i missing somthing here.??
My requirement:
I have application which works similar to VSS. When user checks out specific file and opens ,and try to check in the same, while it has opened. Application is suppose to throw a warning message.For that i have used the above functionality.Its working fine for word and pdf.
To expand on my comment. A file is only locked if a handle is kept open by an application. Word for example will open the file, read in the stream and maintain the handle so that other applications cannot delete that file while the user is working on it.
Notepad, and other applications, just open the file, read in the entire stream and then close the file releasing the lock they have. This means that the file is no longer locked and can be edited by another application or even deleted and Notepad will not care as it has its own copy in memory.
You could try and hack around with getting instances of Notepad and checking if a file is open but this is ultimately not a great idea. If the file is not locked then you should be free to do what you want with it.
This is a hack solution I just came up with, but it should work for you. This makes use of System.Diagnostics.
Process[] processes = Process.GetProcessesByName("notepad");
for (int i = 0; i < processes.Length; i++)
{
Console.WriteLine(processes[i].MainWindowTitle);
if (processes[i].MainWindowTitle.Equals("myFile.txt - Notepad"))
{
Console.WriteLine("The file myFile is Open!");
}
}
Console.ReadLine();
Hopefully that should do the trick. My example looks to see if an instance of notepad is open with the window title "myFile.txt - Notepad". The window name is always "filename.extension - Notepad" so you can handle that however you might need to.
I suppose you could make a call to System.IO.File.GetLastAccessTime(filePath). You could then poll the file every so often and when the access time changes you know the file has been opened, you can then fire an event that the file has been opened. See Jeffs post here:
Detect File Read in C#
You could also do this using the following tactic: It seems that notepad does hold some kind of lock on the hosting folder (try to delete the folder and you'll see you can't).
you could use the following code Using C#, how does one figure out what process locked a file? to check list of processes that lock the folder.
one of the processes will be your notepad.
you could them compare by Title as another answers mentioned.
if you're issuing the open of the file - you could save the PID and comapre it with one of the processes that returned.
I have a strange problem. So my code follows as following.
The exe takes some data from the user
Call a web service to write(and create CSV for the data) the file at perticular network location(say \some-server\some-directory).
Although this web service is hosted at the same location where this
folder is (i.e i can also change it to be c:\some-directory). It then
returns after writing the file
the exe checks for the file to exists, if the file exists then further processing else quite with error.
The problem I am having is at step 3. When I try to read the file immediately after it has been written, I always get file not found exception(but the file there is present). I do not get this exception when I am debugging (because then I am putting a delay by debugging the code) or when Thread.Sleep(3000) before reading the file.
This is really strange because I close the StreamWriter before I return the call to exe. Now according to the documention, close should force the flush of the stream. This is also not related to the size of the file. Also I am not doing Async thread calls for writing and reading the file. They are running in same thread serially one after another(only writing is done by a web service and reading is done by exe. Still the call is serial)
I do not know, but it feels like there is some time difference between the file actually gets written on the disk and when you do Close(). However this baffling because this is not at all related to size. This happens for all file size. I have tried this with file with 10, 50, 100,200 lines of data.
Another thing which I suspected was since I was writing this file to a network location, it could be windows is optimizing the call by writing first to cache and then to network location. So I went ahead and changed the code to write it on drive(i.e use c:\some-directory), rather than network location. But it also resulted in same error.
There is no error in code(for reading and writing). As explained earlier, by putting a delay, it starts working fine. Some other useful information
The exe is .Net Framework 3.5
Windows Server 2008(64 bit, 4 GB Ram)
Edit 1
File.AppendAllText() is not correct solution, as it creates a new file, if it does not exits
Edit 2
code for writing
using (FileStream fs = new FileStream(outFileName, FileMode.Create))
{
using (StreamWriter writer = new StreamWriter(fs, Encoding.Unicode))
{
writer.WriteLine(someString)
}
}
code for reading
StreamReader rdr = new StreamReader(File.OpenRead(CsvFilePath));
string header = rdr.ReadLine();
rdr.Close();
Edit 3
used textwriter, same error
using (TextWriter writer = File.CreateText(outFileName))
{
}
Edit 3
Finally as suggested by some users, I am doing a check for the file in while loop for certain number of times before I throw the exception of file not found.
int i = 1;
while (i++ < 10)
{
bool fileExists = File.Exists(CsvFilePath);
if (!fileExists)
System.Threading.Thread.Sleep(500);
else
break;
}
So you are writing a stream to a file, then reading the file back to a stream? Do you need to write the file then post process it, or can you not just use the source stream directly?
If you need the file, I would use a loop that keeps checking if the file exists every second until it appears (or a silly amount of time has passed) - the writer would give you an error if you couldn't write the file, so you know it will turn up eventually.
Since you're writing over a network, most optimal solution would be to save your file in the local system first, then copy it to network location. This way you can avoid network connection problems. And as well have a backup in case of network failure.
Based on your update, Try this instead:
File.WriteAllText(outFileName, someString);
header = null;
using(StreamReader reader = new StreamReader(CsvFilePath)) {
header = reader.ReadLine();
}
Have you tried to read after disposing the writer FileStream?
Like this:
using (FileStream fs = new FileStream(outFileName, FileMode.Create))
{
using (StreamWriter writer = new StreamWriter(fs, Encoding.Unicode))
{
writer.WriteLine(someString)
}
}
using (StreamReader rdr = new StreamReader(File.OpenRead(CsvFilePath)))
{
string header = rdr.ReadLine();
}
I have a program that (repeatedly) reads contents of a file and, if new data arrives, do some processing. Reading is quite straightforward, something like
class Reader
{
FileStream fs_ = null;
StreamReader sr_ = null;
Reader(string filename)
{
fs_= new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete);
sr_ = new StreamReader(fs_);
}
void Read()
{
string line;
while (line = sr_.ReadLine())
{
// ...
}
}
}
Method Read() is polled every 300 ms. There is some piece of code that closes and reopens file in case of its renaming/deletion by external actors.
Generally, it works ok, but sometimes (I've encountered this two times during last month) strange thing appears. File on a share reporting correct length, but when trying to read from it, shows one and a half of string and rest of file with zeroed (0x00, not '0') contents. Moreover, I got same picture when trying to read the file via any external text/binary editor from the same machine that hosted my program. From other machines on the network file is read without any problems and shows full contents. The problem persists until I reboot the machine with my program.
Any idea what happens and how can I fix it?
I have a program that roughly does this:
open a file to read from it.
close the file
Start a filewatcher to watch for changes in the file.
As soon as a change is detected, the filewatcher's EnableRaisingEvents flag is set to false and the process repeats from Step 1.
The problem is, after going from step 4 to step 1, it cannot read the file saying that it is being used by another Process.
Error I receive:
Unhandled Exception: System.IO.IOException: The process cannot access the file 'c:\test.xml' because it is being used by another process.
Whats going wrong? does the reader from Step 1 of my program still have the file open, or is some entirely different process accessing the file, or is it that filewatcher is still watching the file after moving to Step 1 from 4, despite setting the flag to false?
If your code is similar to this:
[STAThread]
static void Main(string[] args)
{
string file = "temp.txt";
ReadFile(file);
FileSystemWatcher fswatcher = new FileSystemWatcher(".\\");
fswatcher.Changed += delegate(object sender, FileSystemEventArgs e)
{
ReadFile(e.FullPath);
};
while (true)
{
fswatcher.WaitForChanged(WatcherChangeTypes.Changed);
}
}
private static void ReadFile(string file)
{
Stream stream = File.OpenRead(file);
StreamReader streamReader = new StreamReader(stream);
string str = streamReader.ReadToEnd();
MessageBox.Show(str);
streamReader.Close();
stream.Close();
}
If you are editing the file via notepad, then, when you click the save button, it keeps the file open, while as if when you just close the program and click save it doesn't. I do no know if this is a bug or an undocumented feature of notepad, but this just might be your problem. One way to fix this is to do the following:
In your anonymous delegate, or wherever you execute the call to ReadFile() call Thread.Sleep(1000), to have the program wait before reading the file and your code should work fine.
You can use a tool like Process Explorer from http://www.sysinternals.com to see who has the open handle to the process
The file is most likely held open by whatever caused the change notification to fire in the first place.
Beside other answers it is possible that when FileWatcher reacts file it not yet closed by that app. In step 1 try not to fail immediately but try several attempts with small delay.
Note: even if "file.txt" is open in Notepad, this code still works, because it is opening for read.
using System;
using System.IO;
class Program
{
static void Main(string[] args)
{
ReadFromFile(#"C:\file.txt");
Console.ReadLine();
}
static void ReadFromFile(string filename)
{
string line;
using (StreamReader sr = File.OpenText(filename))
{
line = sr.ReadLine();
while (line != null)
{
Console.WriteLine(str);
line = sr.ReadLine();
}
sr.Close();
}
}
}
Or just:
string text = System.IO.File.ReadAllText(#"C:\file.txt");
The problem is that the FileSystemWatcher tells you immediately when the file was created. It doesn't wait for the file to be released.
For instance, when you copy a large file which takes 3 seconds to copy, so you have to open the file after that.
http://www.codeproject.com/Questions/461666/FileSystemWatcher-issue-in-windows-application
Wait until file is unlocked in .NET
There are a number of things that could be going on.
First, make sure you properly dispose of the file writer (close isn't good enough) by utilizing the using clause around everything that implements IDisposable.
Second, it you are simply reading, make sure you have the correct flags set when opening the file.
To go any further it would help if you provided a code block which showed how you were accomplishing this; particularly around the reading of the file
You can use this MS utility openfiles to obtain list of opened files and understand who has opened the file.
openfiles /query
Also it allow to disconnect files opened by network users.
openfiles /disconnect /id XXXX
If you want use it for local PC you should set Maintain Objects List global flag:
openfiles /local on
Follow the link to get more details.
In the past I've always used a FileStream object to write or rewrite an entire file after which I would immediately close the stream. However, now I'm working on a program in which I want to keep a FileStream open in order to allow the user to retain access to the file while they are working in between saves. ( See my previous question).
I'm using XmlSerializer to serialize my classes to a from and XML file. But now I'm keeping the FileStream open to be used to save (reserialized) my class instance later. Are there any special considerations I need to make if I'm reusing the same File Stream over and over again, versus using a new file stream? Do I need to reset the stream to the beginning between saves? If a later save is smaller in size than the previous save will the FileStream leave the remainder bytes from the old file, and thus create a corrupted file? Do I need to do something to clear the file so it will behave as if I'm writing an entirely new file each time?
Your suspicion is correct - if you reset the position of an open file stream and write content that's smaller than what's already in the file, it will leave trailing data and result in a corrupt file (depending on your definition of "corrupt", of course).
If you want to overwrite the file, you really should close the stream when you're finished with it and create a new stream when you're ready to re-save.
I notice from your linked question that you are holding the file open in order to prevent other users from writing to it at the same time. This probably wouldn't be my choice, but if you are going to do that, then I think you can "clear" the file by invoking stream.SetLength(0) between successive saves.
There are various ways to do this; if you are re-opening the file, perhaps set it to truncate:
using(var file = new FileStream(path, FileMode.Truncate)) {
// write
}
If you are overwriting the file while already open, then just trim it after writing:
file.SetLength(file.Position); // assumes we're at the new end
I would try to avoid delete/recreate, since this loses any ACLs etc.
Another option might be to use SetLength(0) to truncate the file before you start rewriting it.
Recently ran into the same requirement. In fact, previously, I used to create a new FileStream within a using statement and overwrite the previous file. Seems like the simple and effective thing to do.
using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write)
{
ProtoBuf.Serializer.Serialize(stream , value);
}
However, I ran into locking issues where some other process is locking the target file. In my attempt to thwart this I retried the write several times before pushing the error up the stack.
int attempt = 0;
while (true)
{
try
{
using (var stream = new FileStream(path, FileMode.Create, FileAccess.Write)
{
ProtoBuf.Serializer.Serialize(stream , value);
}
break;
}
catch (IOException)
{
// could be locked by another process
// make up to X attempts to write the file
attempt++;
if (attempt >= X)
{
throw;
}
Thread.Sleep(100);
}
}
That seemed to work for almost everyone. Then that problem machine came along and forced me down the path of maintaining a lock on the file the entire time. So in lieu of retrying to write the file in the case it's already locked, I'm now making sure I get and hold the stream open so there are no locking issues with later writes.
int attempt = 0;
while (true)
{
try
{
_stream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
break;
}
catch (IOException)
{
// could be locked by another process
// make up to X attempts to open the file
attempt++;
if (attempt >= X)
{
throw;
}
Thread.Sleep(100);
}
}
Now when I write the file the FileStream position must be reset to zero, as Aaronaught said. I opted to "clear" the file by calling _stream.SetLength(0). Seemed like the simplest choice. Then using our serializer of choice, Marc Gravell's protobuf-net, serialize the value to the stream.
_stream.SetLength(0);
ProtoBuf.Serializer.Serialize(_stream, value);
This works just fine most of the time and the file is completely written to the disk. However, on a few occasions I've observed the file not being immediately written to the disk. To ensure the stream is flushed and the file is completely written to disk I also needed to call _stream.Flush(true).
_stream.SetLength(0);
ProtoBuf.Serializer.Serialize(_stream, value);
_stream.Flush(true);
Based on your question I think you'd be better served closing/re-opening the underlying file. You don't seem to be doing anything other than writing the whole file. The value you can add by re-writing Open/Close/Flush/Seek will be next to 0. Concentrate on your business problem.