Does Ionic ZipFile lock/unlock files? - c#

I am busy developing an additional module for an existing C# (4.0) application that uses Ionic Zip library to manage the data. In my module I need to load data from zip files, manipulate them, and write back again. My routine runs OK in Unit Tests, but when called from within the host application, it throws an exception reading "The process cannot access the file because it is being used by another process". This happens at a point when I try to call the Save() function of the Zip archive.
I checked which process actually locks the file, and it happens to be the application itself. Therefore I conclude that there might be some kind of interference with the host program: e.g. a file stream opened at some place and not closed. (BTW, are there some smart techniques to look after such places?)
What puzzles me is whether those ZipFile's of Ionic really lock / unlock files when dealing with files, as in the following code piece:
ZipFile zf = new ZipFile("test01.zip");
zf.Save();
// FileSystemTools.WhoIsLocking is a utility showing a list pf processes
// holding access to a given file
// Similar to http://stackoverflow.com/questions/1304/how-to-check-for-file-lock/20623302#20623302
List<Process> processes = FileSystemTools.WhoIsLocking("test01.zip");
Assert.That(processes.Count == 1);
zf.Dispose();
processes = FileSystemTools.WhoIsLocking("test01.zip");
Assert.That(processes.Count == 0);
After Save() the number of locking processes is 1 (the running process itself), but after Dispose() there are none, which attests that Ionic.ZipFile obviously holds some file streams internally and manages them somehow. At other places, however, Dispose() has no effect: the number of locking process is not decremented. Iconic.Zip documentation is scarce and nconvincing.

Related

Prevent Multiple users accessing the same folder C#

I am currently in the process of writing a small application in C# to process batches of images and put them into a PDF. Each batch of images is stored in its own folder on a network share. The application will enable users to perform QA checks on a random number of images from a single batch before creating a PDF. At most there will be between 4-6 users running this application on individual desktops with access to the location where the image batches are stored.
The problem I'm running into at the moment is how do I prevent 2 users from processing the same batch? Initially I thought about using FileSystemWatcher to check for last access to each folder, but reading up on how FileSystemWatcher raises events it didn't seem suitable. I've condsidered using polling to check the images in each folder for File access using a filestream, but I don't think that will be suitable either(I may be wrong).
What would be the simplest solution?
I'd use a lock file with a package like this.
Code is quite simple:
var fileLock = new SimpleFileLock("networkFolder/file.lock", TimeSpan.FromMinutes(timeout));
where timeout is used to unlock the folder if the process using it crashed (so that it doesn't stay locked forever).
Then, everytime a process needs to use that directory, you go with a simple check:
if (fileLock.TryAcquireLock())
{
//Lock acquired - do your work here
}
else
{
//Failed to acquire lock - SpinWait or do something else
}
Code is taken from the samples on the repo, so that's the way the author suggests using his library.
I had the chance to use it and I found it both useful and reliable.

c# FileSystemWatcher fires on multiple clients

I'm using a FileSystemWatcher to watch a directory. I created a _Created() event handler to fire when a file is moved to this folder. My problem is the following:
The files in this directory get created when the user hits a "real life button" (a button in our stock, not in the application). The FileSystemWatcher take this file, do some stuff in the system and then delete it. That wouldn't be a problem when the application runs only once. But it is used by 6 clients. So every application on every client is trying to delete it. If one client is too slow, it will throw an exception because the file is already deleted.
What I'm asking for is: Is there a way to avoid this?
I tried using loops and check if the file still exists, but without any success.
while (File.Exists(file))
{
File.Delete(file);
Thread.Sleep(100);
}
Can someone give me a hint how it could probably work?
Design
If you want a file to be processed by a single instance only (for example, the first instance that reacts gets the job), then you should implement a locking mechanism. Only the instance that is able to obtain a lock on the file is allowed to process and remove it, all other instances should skip the file.
If you're fine with all instances processing the file, and only care that at least one of them succeeds, then you need to figure out which exceptions indicate a genuine failure and which ones indicate a failure caused by the actions of another instance.
Locking
To 'lock' a file, you can open it with share-mode FileShare.None. This prevents other processes from opening it until you close the file. However, you'll then need to close the file before you can delete it, which leaves a small gap during which another instance could open the file.
A better solution is to create a separate lock file for that purpose. Create it with file-mode FileMode.Create and share-mode FileShare.None and keep it open until the whole process is finished, including the removal of the processed file. Then the lock file can be closed and optionally removed.
Exception
As for the UnauthorizedAccessException you got, according to the documentation, that means one of 4 things:
You don't have the required permission
The file is an executable file that is in use
The path is a directory
The file is read-only
1 and 4 seem most likely in this case (if the file was open in another process you'd get an IOException).
If you want to synchronize access between multiple clients on the same computer you should use a Named Mutex.

Passing stream objects / file handles between two processes in .NET

I have a windows service and a desktop application running on the same machine. The app pre-processes some documents and transfers them to a folder where the service can take over. When the app is creating the new file for the service, it keeps a read-only lock on the file while writing. It them releases it so that the service can acquire a new read-only lock (FileStream).
I'd like the app to somehow hand-over this lock to the service without closing it. Is this possible in the managed runtime? If not, is there a way to P/Invoke this behaviour?
The reason this behaviour is desired is so that no other processes can modify or delete the file until both the app and service are done with it.
This is not possible in a managed-only way.
Try to use a simpler approach, such as naming the file with a random name in a temp directory such that no other application will try to open it.
If you insist on passing the handle, you must duplicate the handle into the service process and pass the numeric handle value of that process to the service process. Use OpenProcess, DuplicateHandle and CloseProcess for that.
From http://msdn.microsoft.com/en-us/library/windows/desktop/ms724251(v=vs.85).aspx:
The duplicate handle refers to the same object as the original handle.
Therefore, any changes to the object are reflected through both
handles. For example, if you duplicate a file handle, the current file
position is always the same for both handles. For file handles to have
different file positions, use the CreateFile function to create file
handles that share access to the same file.

Find out who locked file on a network drive in C#

A program is running on multiple machines that share a network drive. It can use
... = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read);
to lock a file from writing. All the other instance then can only read it and display a warning, that the file is not writable.
How can I find out who (i.e. which machine) locked the file, to display that along the warning?
The only way I have ever seen this achieved is for the program that opens the file to leave behind a marker file, (.lock) or similar. This .lock file can then obviously contain whatever you want (username, machine etc) and can be read separately.
This assumes you have control over the software which is reading it on the other PC.
Here is a posting with C# source code for an example of how to look through the process list and check the files that are locked by each process.
How does one figure out what process locked a file using C#.
The next step would be to use this functionality within a service on each machine so that a process can send a query for a specific file name and then receive a response as to whether a process on that machine has it locked.
The data could include process name, user id, and other information available from the process list.
This approach is more work however what it does is provide a way to access the information without require applications locking the file to do something special.
On the other hand if the files you are interested in are within your control and you can determine the file access, this is probably overkill.

Waiting to get exclusive access of file before moving it in C#

I have a requirement to move certain files after they has been processed. Another process access the file and I am not sure when it releases them. Is there any way I can find out when the handle to the file has been released so I can move them at that time.
I am using Microsoft C# and .Net framework 3.5.
Cheers,
Hamid
If you have control of both the producer of the file and the consumer, the old trick to use is create the file under a different name, and rename it once complete.
For example, say the producer is creating files always called file_.txt, and your consumer is scanning for all files beginning file_, then the producer can do this:
1. Create the file called tmpfile_.txt
2. When the file is written, the producer simply renames the file to file_.txt
The rename operation is atomic, so once your consumer sees its available, it is safe to open it.
Of course, this answer depends on if you are writing both programs.
HTH
Dermot.
Just contniually try to open the file for exclusive writing? (e.g. pass FileShare.None to the FileStream constructor). Once you have opened it, you know no one else is using it. However, this might not be the best way to do what you're doing.
If you're after two way communication, see if the other program can be talked to via a pipe.
If you have control of both of the sources, use a named mutex (which works across processes) to control access to the files rather than locking the file at the filesystem level. This way, you don't have to catch the exception raised by attempting to lock a locked file and loop on that, which is rather inelegant.

Categories

Resources