Check if file is already in use by other process - c#

I'm working on a Form application which is suppose to run on multiple machines in one network at once. There is a Form in my application (let's call it Form1) from which you can edit a XML file located on the network. In order to prevent this file from being overwritten I have to make sure that only one person at a time can access Form1.
My first try was to create an attribute inside the XML file to indicate when someone is already accessing Form1. The problem with that solution was that in the case of a sudden crash like a power outage the attribute would not be changed back to its normal value because Form1 was never properly exited. So you would have to manually change the value inside the XML file.
My current solution is running a thread inside Form1 which is constantly reading a file until Form1 is closed again. And checking if the file is already being read before allowing other people to access Form1. This solution works fine but it's not pretty since I have to have an additional file which sole purpose is to be read since I can't constantly read the XML file itself without causing other problems.
Edit: Since the first answers are the same as my current solution here is the code of my current solution.
//CODE INSIDE FORM1
//Create thread which is reading File2
Thread readerThread = new Thread(new ThreadStart(ReadFile2));
readerThread.Start();
private void ReadFile2()
{
using (FileStream stream = File.Open(pathFile2, FileMode.Open, FileAccess.Read, FileShare.None))
{
//Wait until Form1 is being closed
threadWait.WaitOne();
stream.Close();
}
}
//CODE BEFORE ACCESSING FORM1
private bool Form1OpenCheck()
{
//Check if file2 is being read
bool noAccess = false;
try
{
using (FileStream stream = File.Open(pathFile2, FileMode.Open, FileAccess.Read, FileShare.None))
{
stream.Close();
}
}
catch (IOException)
{
noAccess = true;
}
return noAccess;
}
I would appreciate it if anyone has a better solution for this problem. Thanks.

I'm using this implementation (it's not mine, props to the dude who wrote this)
/// <summary>
/// Checks if a file is ready
/// </summary>
/// <param name="sFilename"></param>
/// <returns></returns>
public static bool IsFileReady(string sFilename)
{
// If the file can be opened for exclusive access it means that the file
// is no longer locked by another process.
try
{
using (FileStream inputStream = File.Open(sFilename, FileMode.Open, FileAccess.Read, FileShare.None))
{
return inputStream.Length > 0;
}
}
catch (Exception)
{
return false;
}
}

You don't have to change the file to open it exclusively for you, just mention in your File.Open that no one may open it, not even for read-only:
string fileName = ...
using (var stream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.None))
{
// while here, no one else can access the file, not even delete it.
...
}
// now others can open the file again.
While you have the file open with FileShare.None, neither your process, nor another process can open the file, or access it any other way. They get an exception if they try to open or delete it. See FileShare Enum.
You or others can only open it after you Closed the Stream. Hence it is always good practice to enclose the opening in a using statement. Any exception will Close and Dispose the stream.
By the way, the overload of File.Open without a fileShare parameter also opens with FileShare.None.
So, it might be a good idea if in other use cases, you only want to read the file once, while others may still start changing it, maybe it is a good practice to open the file with FileShare.Read

Ok after talking to a colleague and a bit of brainstorming I came up with a better solution.
Inside Form1 I create a TCP Socket which is listening for connections to an IPEndPoint inside the network. Now in order to check if Form1 is already running on another machine I create another TCP Socket which is trying to connect to the same IPEndPoint. If the connection fails this means Form1 is running nowhere else and I can safely open it. If the connection works Form1 is already open somewhere and I can inform the user about it.

Related

.NET Core - Multiple read/write operations on a text file

Multiple read/write operation are access a single file, and while write operation I'm facing this issue
The process cannot access the file because it is being used in another process
Using this to add text to file
using (StreamWriter writer=System.IO.File.AppendText("wwwroot/Files/file.txt"))
{
writer.WriteLine(stringData.ToString());
writer.Close();
}
Is there anyway to perform multiple read/write on a file?
Thanks
If are using the same code from multiple threads or apps writing to the same file, you may find when one thread is wiring it finds the file already in use.
The only reason for the error message is that the file is not closed.
If the calls to write to the file are sequential from the same app then the file is not getting closed properly.
One way to handle this is to check for locked files and retry later.
something like this can be used to check if the file is open:
public static bool CanBeOpenedForExclusiveRead(string filename)
{
try
{
// Test file for exclusive read/write
using (System.IO.FileStream fileStream = System.IO.File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.None))
{
fileStream.Close();
}
return true;
}
catch
{
}
return false;
}
if you are already using something like NLog is to use nlog to "log" writes to a file, where nlog will have better handling of these issues across threads.
Try the below code. You may not need a StreamWriter for this
// To append text to file
System.IO.File.AppendAllText("FilePath", "TextToWrite");
// To read all text from file
string textFromFile = System.IO.File.ReadAllText("FilePath");

File contents stops updating on windows share

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?

Problem with reading text file

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/

My C# app is locking a file, how I can find where it does it?

I'm writing code that check files path calculate hash (SHA1) and copy them.
I made sure that I do not lock them like for example using
public static string SHA1(string filePath)
{
var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
var formatted = string.Empty;
using (var sha1 = new SHA1Managed())
{
byte[] hash = sha1.ComputeHash(fs);
foreach (byte b in hash)
{
formatted += b.ToString("X2");
}
}
return formatted;
}
So how I can, in Visual Studio, find where it does lock the file?
Can you keep the above syntax as and give a try?
using(var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
//Your code goes here.
}
There is a little windows soft : process explorer and in this you can find which process has an handle on a file :
http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx
Locking usually happens whenever you create a file stream on a file without later closing that stream. Unless you call fs.Close(); in your code, your application will keep the file open (and thus locked).
You could wrap this in a try-finally block or try the code that Siva Gopal posted.
You assumption that opening the file stream with just FileAccess.Read will not lock the file is faulty; the file is locked while it has been opened for a file operation and has not been closed.
A FileStream does not close an opened file until the FileStream is garbage collected or you explicitly call its Close or Dispose method. Either insert such an explicit call as soon as you are done with the file you opened, Or wrap the use of the FileStream in a using statement, which implies the call to Dispose, like other answers suggest.

Reusing a filestream

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.

Categories