Check if a file that's not locked is open - c#

Some programs (image programs such as Paint, text editors such as notepad and Wordpad,and others) open files, load the contents into memory, then release the file lock. Is there a way to tell if a program is using that file even though it's not locked?
For example, even if image1.bmp is open in Paint, my program can overwrite the copy of image1.bmp that's on the disk because the file isn't locked. Now the copy of image1.bmp that is open in Paint is different than the copy of image1.bmp that is on the disk.
My program is written in C#. I usually use this method for checking if a file is locked, but it won't work in the above case.
Is there a way to check if a file is in use?
Is there any solution to this?

"Now the copy of image1.bmp that is open in Paint" - here's your mistake - the file is no longer open in Paint. It was opened, read, and then closed. Paint does not keep the file open at all - it only has a COPY of its contents in RAM memory. To put it in another way - the fact that you see a picture in MS Paint doesn't mean the file is open.
It is comparable to loaning a document to someone, then he makes a photocopy and returns it - that person no longer "holds" the document, he has a separate copy of it. And there is no way, just by looking at the document, to know who might have made a copy of it at some point in history.
Another way of putting it is this pseudocode:
File file = Open("image.png");
Image img = ImageFromFile(file);
file.Close();
...
img.Save("image.png");
Here no file is being opened at all, there's just a copy in RAM of its content.
Note: I actually checked that for Paint - Process Explorer can show you opened handles, I opened a file in Paint and there was no handle at all listed for a file of that name.

Here's what I came up with. I check all open processes for a window title. If the process has a window title, I see if it contains the name of the file I'm looking for.
It won't work 100% of the time since some applications can have multiple files open in a single instance.
I adapted it from this question:Getting a list of all applications
bool isFileOpen(string file)
{
string windowTitle = "";
Process[] myProcesses = Process.GetProcesses();
foreach (Process P in myProcesses)
{
if (P.MainWindowTitle.Length > 1)
{
windowTitle = P.MainWindowTitle;
if (windowTitle.Contains(file) == true)
{
return true;
}
}
}
return false;
}

Related

How to detect file copying process has finished in C#

I am working on a project that I need to do the following:
I need to rename an image file. (Open an image from folder, and give a name & save it in to same folder)
try
{
string oldFileName = #"path\to\person1.jpg";
string desFileName = #"path\to\person2.jpg";
File.Copy(oldFileName, desFileName, true);
if (File.Exists(oldFileName))
{
File.Delete(#oldFileName);
}
}
catch (Exception ex)
{
}
I did rename the file using above way.
This process copy the old file with new name, but couldn't remove old file
Exception message :
The process cannot access the file 'path\to\person1.jpg' because it is
being used by another process.
How to resolve this? Please suggest any way to detect copying process has complete or not.
Your copy process is definatly complete on if statement becouse your code is sync.
I bet you got this error becouse file is used by another proccess (not your programm). Maby you have paint open or something else.
You should find it out with process monitor or something else. Check this question.

Testing to see if a file is open doesn't give expected results

I wanted to test if a particular file is already open before trying to launch it, so I came up with this:
public void LaunchErrorLog()
{
var logFile = ConfigurationManager.AppSettings["Log"];
if (IsLogOpen(logFile))
return; //figure out how to give focus to other app later
var psi = new ProcessStartInfo(logFile);
psi.WindowStyle = ProcessWindowStyle.Maximized;
Process.Start(psi);
}
private bool IsLogOpen(string p)
{
try
{
using (var s = new FileStream(p, FileMode.Open, FileAccess.Read)){}
}
catch (IOException)
{
return true;
}
return false;
}
I'm testing using a .log file (just a text file) that I've got open in Baretail. The method always returns false regardless of whether or not the file is open. I tried opening it in Notepad, and it still returns false.
Basically, the end objective is to give focus to the application that has the file open, or launch the application/file if it's not already open. But this is always false so it just goes on and launches a new instance of Baretail with the file open.
Also tried the top solution found here;
Is there a way to check if a file is in use?
Notepad is a bad test application because it does not hold a lock open on the file. It streams in the file and closes the lock. Use Word to do the test and you will see different results. A file is only locked if a handle is kept open by an application. Word will lock files. The same holds true for "Baretail".
In other words, if "Baretail" streams the file in and closes the lock then this test will not work. You could do something hacky such as sniff around Win32 objects...window handles and title bars to extract the information...but be warned this kind of UI hacking is tricky and I would not consider the information to be reliable. There's no stopping some other program from using similar text in their title bars per se.
I believe that that method is always returning false because you are opening for read. Even if the file is open for write elsewhere, you should be able to read that file (thus no exception is thrown).
Try using a different FileAccess opetion ie
FileAccess.ReadWrite
Or you can also try different combinations of FileMode and FileOption. (Sorry not in front of a dev machine at this point)

check if a text file is opened in notepad

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.

NullReferenceException only when opening images from database

I have a table in my database that stores all kind of files.
File names are shown in a ListView and when an user clics on one of them then it's opened by the registered application based on file extension.
This is the code:
if (listViewArchivos.HasItems)
{
dynamic result = listViewArchivos.SelectedItem;
var nombre = Path.GetTempPath() + admin.buscarNombreArchivo((int)result.Id);
var bytes = admin.buscarArchivo((int)result.Id);
try
{
using (var writer = new BinaryWriter(File.Open(nombre, FileMode.Create)))
{
writer.Write(bytes);
}
var p = Process.Start(nombre);
p.WaitForExit();
}
catch (Exception exc)
{
InterfazUtil.error(exc.Message); // This shows a MessageBox
}
finally
{
File.Delete(nombre);
}
}
It's working fine for docx, pdf, txt, etc. But when I try to open an image the file is successfully opened by Window Photo Viewer (Windows 7) but a NullReferenceException is thrown.
If I close WPV first and then the MessageBox the file is deleted from temp folder.
If I close the MessageBox first then the image disappears from WPV and after I close WPV the file is not deleted from temp folder.
Now, if I remove the catch block then the file is successfully opened by WPV and after closing it the file is not deleted from temp folder. Obviously the application crashes because the exception isn't managed.
Looks like the problem is WPV.
Any idea of what is wrong?
TIA
EDIT:
The exception is thrown at
p.WaitForExit();
When you close the MessageBox first the temp file is not deleted because WPV uses it and doesn't allow it.
According to this MSDN: http://msdn.microsoft.com/en-us/library/53ezey2s.aspx
...you will not get back a Process object when the process is already running.
I found this on a forum relating to the nature of WindowsPhotoViewer:
Actually, the Windows Photo Viewer is part of Windows Explorer, and
generally runs in the Explorer.exe process. In fact, what you're
calling the Photo Viewer is really just the "preview" verb for images.
It isn't a standalone application, and opening it without an image or
images doesn't really make any sense.
Thus, you are not getting back a Process object because it is already running by virtue of the fact that explorer.exe is already running.
In the end, I think it means that if your images open in WindowsPhotoViewer, you will not be able to make WaitForExit() work because the owner process will never exit.

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