Using c#, is there a way to check that a file is in use. More specifically, I need a way to monitor a directory of .wav files and see which sound file has been loaded.
Note. It can be loaded by different applications.
I've had a look at Core Audio.. but I cannot seem to find an answer there.
I've also tried to code that if the file is locked but that also doesnt provide a solution. So if you know of a way to determine which sound file (.wav) is currently being played, please comment.
protected virtual bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None);
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
Here is the reference link : File is in Use
Hope it helps.
Related
I have a problem that is driving me mad. Maybe you could help ;)
I'm tracking file changes on the folder with FileSystemWatcher and copy changed files to another folder. I don’t want to copy the file until it is done being saved. I cannot find a solution that works at the same time for all 3 scenarios below:
1) New file being copied into the folder
2) Existing file being overwritten by copying new one
3) File is opened by another process (i.e. Word)
I have tried IsFileLocked method from the thread below.
c# check if file is open
It will work for copying but the problem is that function will always return TRUE for opened OFFICE files (maybe for some others as well).
I also tried to check in the loop if the file size changes but it’s seems to be impossible as FileInfo.Length always return the target size (even though file is still being copied).
I'm using that function to check if file is in use
public static bool IsFileLocked(string path)
{
FileInfo fileInfo = new FileInfo(path);
FileStream stream = null;
try
{
stream = fileInfo.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (UnauthorizedAccessException)
{
// file created with readonly flag
return false;
}
catch (FileNotFoundException)
{
return false;
}
catch (IOException ex)
{
int errorCode = Marshal.GetHRForException(ex) & ((1 << 16) - 1);
bool islocked = errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION;
return islocked;
}
finally
{
if (stream != null)
{
stream.Close();
stream.Dispose();
}
}
//file is not locked
return false;
}
Do you know how to distinguish if it's opened by some application or being copied?
I'm monitoring a folder for new files, and when the new file is present I read (and save in a txt) the file as following:
FileStream file = File.Open(this.filePath, FileMode.Open, FileAccess.Read);
StreamReader reader = new System.IO.StreamReader(file);
string text = reader.ReadToEnd();
reader.Close();
If I copy/paste in the folder the source file, I receive an IOExcpetion that tells me that the file is used by another process.
If I cut/paste in the folder, all works.
Moreover locking problem happens also If I copy (but also cut in this case)/paste the file from another machine into the monitored folder.
Do you have an idea about what is happening?
There is a safer way to access to the file in order to avoid this type of locks?
Thanks!
Here is a little snippet I do to ensure the file is finished copying or not in use by another process.
private bool FileUploadCompleted(string filename)
{
try
{
using (FileStream inputStream = File.Open(filename, FileMode.Open,
FileAccess.Read,
FileShare.None))
{
return true;
}
}
catch (IOException)
{
return false;
}
}
Then you can implement this before your process logic
while (!FileUploadCompleted(filePath))
{
//if the file is in use it will enter here
//So you could sleep the thread here for a second or something to allow it some time
// Also you could add a retry count and if it goes past the allotted retries you
// can break the loop and send an email or log the file for manual processing or
// something like that
}
I'm stuck with a weird problem (which is probably my lack of knowledge), I present the offending code:
try
{
f.Delete();
fTemp.MoveTo(f.FullName);
Console.WriteLine("INFO: Old file deleted new file moved in > {0}", f.FullName);
}
catch (IOException ex)
{
Console.WriteLine("ERROR: Output file has IO exception > {0}", f.FullName);
Environment.ExitCode = 1;
}
f and fTemp are FileInfo objects. So if I run this with code where f is a video file playing in a mediaplayer it throws the exception. That works fine and as expected. Now when I close the mediaplayer it deletes the file!? Even though my application is long closed. Even when I close Visual Studio it still deletes the file, when I close the mediaplayer. As if some callback is being setup somewhere to make sure the file gets deleted at some point. This offcourse in unwanted behaviour. But I can't figure out what exactly goes wrong...
Result for now :
if (!IsFileLocked(f))
{
try
{
f.Delete();
fTemp.MoveTo(f.FullName);
Console.WriteLine("INFO: Old file deleted new file moved in > {0}", f.FullName);
}
catch (IOException ex)
{
Console.WriteLine("ERROR: Output file has IO exception > {0}", f.FullName);
Environment.ExitCode = 1;
}
catch (UnauthorizedAccessException ex)
{
Environment.ExitCode = 2;
Console.WriteLine("ERROR: Output file is locked > {0}", f.FullName);
}
}
else
{
Environment.ExitCode = 3;
Console.WriteLine("ERROR: Couldn't delete file was locked");
}
I know I still can do better between Delete and MoveTo, but I'll take my changes for now, shotgun coding.....
You are getting the IOException because the file cannot immediately be deleted or written to. However, when you call Delete(), it seems the file is getting called for deletion.
Though the media player stops the file from being deleted while it is open, the file is still marked for deletion when it closes, regardless of whether your program is running. So when the media player closes the file is deleted.
You can check if the file is in use with the following code, taken from here. Make the Delete and Copy conditional on it not being locked, and you should be good.
try
{
if(!IsFileLocked(f))
{
f.Delete();
fTemp.MoveTo(f.FullName);
Console.WriteLine("INFO: Old file deleted new file moved in > {0}", f.FullName);
}
}
protected virtual bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
From the Windows SDK:
The DeleteFile function marks a file for deletion on close. Therefore, the file deletion does not occur until the last handle to the file is closed. Subsequent calls to CreateFile to open the file fail with ERROR_ACCESS_DENIED.
As far as I understand, you want your program to wait until the file can be deleted and then delete it and move the other file.
To do this, you could check, if there is a handle open on the file, but this needs unmanaged code. Another way would be to use the methode from the answer of this question: Is there a way to check if a file is in use?
protected virtual bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
Before you start to delete the file you could
A) loop until the file can be deleted
while(IsFileLocked(f)) { Thread.Sleep(100); }
or B) cancel
if (IsFileLocked(f)) { return; }
If you choose A or B depends on your requirements.
I want to check whether a particular Excel file is already opened. Otherwise when I reopen same file in my C# program it is opening in read only format. Is there any way to find out if the file is already open?
If the file if opened by another program this code can help you figure it out, but you won't be able to open it
<!-- language: c# -->
protected virtual bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
(BUt you can't do anything with it, the file must be closed from the program, which opened it)
The following code gives me a System.IO.IOException with the message 'The process cannot access the file'.
private void UnPackLegacyStats()
{
DirectoryInfo oDirectory;
XmlDocument oStatsXml;
//Get the directory
oDirectory = new DirectoryInfo(msLegacyStatZipsPath);
//Check if the directory exists
if (oDirectory.Exists)
{
//Loop files
foreach (FileInfo oFile in oDirectory.GetFiles())
{
//Check if file is a zip file
if (C1ZipFile.IsZipFile(oFile.FullName))
{
//Open the zip file
using (C1ZipFile oZipFile = new C1ZipFile(oFile.FullName, false))
{
//Check if the zip contains the stats
if (oZipFile.Entries.Contains("Stats.xml"))
{
//Get the stats as a stream
using (Stream oStatsStream = oZipFile.Entries["Stats.xml"].OpenReader())
{
//Load the stats as xml
oStatsXml = new XmlDocument();
oStatsXml.Load(oStatsStream);
//Close the stream
oStatsStream.Close();
}
//Loop hit elements
foreach (XmlElement oHitElement in oStatsXml.SelectNodes("/*/hits"))
{
//Do stuff
}
}
//Close the file
oZipFile.Close();
}
}
//Delete the file
oFile.Delete();
}
}
}
I am struggling to see where the file could still be locked. All objects that could be holding onto a handle to the file are in using blocks and are explicitly closed.
Is it something to do with using FileInfo objects rather than the strings returned by the static GetFiles method?
Any ideas?
I do not see problems in your code, everything look ok. To check is the problem lies in C1ZipFile I suggest you initialize zip from stream, instead of initialization from file, so you close stream explicitly:
//Open the zip file
using (Stream ZipStream = oFile.OpenRead())
using (C1ZipFile oZipFile = new C1ZipFile(ZipStream, false))
{
// ...
Several other suggestions:
You do not need to call Close() method, with using (...), remove them.
Move xml processing (Loop hit elements) outsize zip processing, i.e. after zip file closeing, so you keep file opened as least as possible.
I assume you're getting the error on the oFile.Delete call. I was able to reproduce this error. Interestingly, the error only occurs when the file is not a zip file. Is this the behavior you are seeing?
It appears that the C1ZipFile.IsZipFile call is not releasing the file when it's not a zip file. I was able to avoid this problem by using a FileStream instead of passing the file path as a string (the IsZipFile function accepts either).
So the following modification to your code seems to work:
if (oDirectory.Exists)
{
//Loop files
foreach (FileInfo oFile in oDirectory.GetFiles())
{
using (FileStream oStream = new FileStream(oFile.FullName, FileMode.Open))
{
//Check if file is a zip file
if (C1ZipFile.IsZipFile(oStream))
{
// ...
}
}
//Delete the file
oFile.Delete();
}
}
In response to the original question in the subject: I don't know if it's possible to know if a file can be deleted without attempting to delete it. You could always write a function that attempts to delete the file and catches the error if it can't and then returns a boolean indicating whether the delete was successful.
I'm just guessing: are you sure that oZipFile.Close() is enough? Perhaps you have to call oZipFile.Dispose() or oZipFile.Finalize() to be sure it has actually released the resources.
More then Likely it's not being disposed, anytime you access something outside of managed code(streams, files, etc.) you MUST dispose of them. I learned the hard way with Asp.NET and Image files, it will fill up your memory, crash your server, etc.
In the interest of completeness I am posing my working code as the changes came from more than one source.
private void UnPackLegacyStats()
{
DirectoryInfo oDirectory;
XmlDocument oStatsXml;
//Get the directory
oDirectory = new DirectoryInfo(msLegacyStatZipsPath);
//Check if the directory exists
if (oDirectory.Exists)
{
//Loop files
foreach (FileInfo oFile in oDirectory.GetFiles())
{
//Set empty xml
oStatsXml = null;
//Load file into a stream
using (Stream oFileStream = oFile.OpenRead())
{
//Check if file is a zip file
if (C1ZipFile.IsZipFile(oFileStream))
{
//Open the zip file
using (C1ZipFile oZipFile = new C1ZipFile(oFileStream, false))
{
//Check if the zip contains the stats
if (oZipFile.Entries.Contains("Stats.xml"))
{
//Get the stats as a stream
using (Stream oStatsStream = oZipFile.Entries["Stats.xml"].OpenReader())
{
//Load the stats as xml
oStatsXml = new XmlDocument();
oStatsXml.Load(oStatsStream);
}
}
}
}
}
//Check if we have stats
if (oStatsXml != null)
{
//Process XML here
}
//Delete the file
oFile.Delete();
}
}
}
The main lesson I learned from this is to manage file access in one place in the calling code rather than letting other components manage their own file access. This is most apropriate when you want to use the file again after the other component has finished it's task.
Although this takes a little more code you can clearly see where the stream is disposed (at the end of the using), compared to having to trust that a component has correctly disposed of the stream.