I'm downloading a file from a server and opening it using Process.Start() and attaching a file watcher to the file to catch any changes and re-upload them to the server.
Is there anyway to determine when the file has closed using the FileWatcher or any other method? The problem being I can't decide how to stop watching the file and I don't want it watched indefinitely?
Any ideas?
Thanks in advance
Jon
What I did was put a 5 minute loop and just watch for the file to be available. That way I could give it time to free up, but yet still had a definitive time. If it hasn't cleared by 5 minutes in my system something is definetely wrong. You should set your time limit to your circumstances. I got this idea from somewhere, no idea where anymore.
DateTime EndTime = System.DateTime.Now.AddMinutes((double)timeOut);
while (System.DateTime.Now <= EndTime)
{
try
{
using (Stream stream = System.IO.File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
if (stream != null)
{
break;
}
}
}
catch (FileNotFoundException)
{
//
}
catch (IOException)
{
//
}
catch (UnauthorizedAccessException)
{
//
}
System.Threading.Thread.Sleep(sleepTime);
}
Related
I have a solution that acts as an interface between two systems, reading files that were dropped on an FTP site and importing any orders/products/etc. into the target system.
When a file is picked up, it is moved to a temp file in the same location, and then the contents are read into an XmlDocument.
string[] files = Directory.GetFiles(pickupFolder, fileFilter, SearchOption.TopDirectoryOnly);
foreach (string pathToFile in files)
{
FileInfo srcFile = new FileInfo(pathToFile);
string tmpFilename = Path.Combine(srcFile.DirectoryName, $"~{Path.GetFileNameWithoutExtension(srcFile.Name)}.tmp");
srcFile.MoveTo(tmpFilename);
XmlDocument srcXml = new XmlDocument();
try
{
using (FileStream fs = srcFile.Open(FileMode.Open, FileAccess.Read))
{
srcXml.Load(fs);
}
}
catch (XmlException ex)
{
throw new FileException($"Invalid XML in {srcFile.Name}.", ex);
}
}
Very, very occassionally, the interface will attempt to open the file so that it can be loaded into the XmlDocument while the moving process has not been completed, throwing an IOException. Is there some way to prevent this from happening?
What is the best way to create something like this that needs to iterate through and process files?
The file move operation will throw an exception when the FTP server is still having a lock on the file. That may happen when the file is still being uploaded and is not yet completed, but is "visible" on the disk. Such collisions are rare, but they happen.
Start by checking your FTP server settings and features if it can hide incomplete files during upload. Another way is if you control the system that uploads files, you could upload them with a special "do not download" extension, and rename them after the upload is complete (atomic operation). Finally, as other pointed out, you could simply catch this specific exception and retry with a delay.
As others have pointed out, if process runs periodically, you can simply wrap it with try / catch block:
try
{
srcFile.MoveTo(tmpFilename);
}
catch (Excption ex)
{
// Write log entry if required
continue;
}
If it's a one-off process, then you'll need to periodically attempt MoveTo until file is released and can be moved. Something like this may work:
int maxRetries = 60;
int retries = 0;
bool success = false;
while (retries < maxRetries)
{
try
{
retries++;
srcFile.MoveTo(tmpFilename);
success = true;
break;
}
catch (Excption ex)
{
// Log the error if required
Thread.Sleep(1000); // Wait 1 second
}
}
if (success == fale)
{
// Log the error
continue; // Skip the file if its still not released
}
The code tries to access the file every second during a minute. If it fails, then program skips this file and continues to next.
I have written a small program to monitor a folder. I have not used the folderWatcher in .NET because multiple files can be added to the folder simultaneously and folderWatcher can sometimes miss them. Basically, I am checking the folder for a file that starts and ends with certain characters. The timer is checking the folder every 10 seconds.
My issue: my program will read the same file multiple times. I need to set a condition or have a listener check if the file has already been read to ignore it.
The problem is I'm not sure how to go about this, can anyone shed some light on the best way to maybe implement a listener that will check if I have read this file and ignore it and move onto the next file, please?
I couldn't find another thread on here that helped me with the answer I am looking for.
Basicly, you sould keep somewhere (maybe in a text file) the last scan date and can check the creation time of files.
void ReadFiles()
{
try
{
DateTime lastScanDate = GetLastScanDate();
SetLastScanDate();
foreach (string filePath in System.IO.Directory.GetFiles(#"C:\Users\cozogul\Desktop\test"))
{
System.IO.FileInfo fi = new System.IO.FileInfo(filePath);
if (fi.CreationTime >= lastScanDate)
{
//read file
}
else
{
//Don't read file.
}
}
}
catch (Exception ex)
{
//Log your error
}
}
DateTime GetLastScanDate()
{
if (System.IO.File.Exists(#"C:\Users\cozogul\Desktop\test\datefile.txt"))
{
using (System.IO.FileStream fs = new System.IO.FileStream(#"C:\Users\cozogul\Desktop\test\datefile.txt", System.IO.FileMode.Open))
{
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
string dateString = System.Text.Encoding.UTF8.GetString(buffer);
DateTime date = Convert.ToDateTime(dateString);
return date;
}
}
//Will read all files.
else
return DateTime.MinValue;
}
public void SetLastScanDate()
{
using (System.IO.FileStream fs = new System.IO.FileStream(#"C:\Users\cozogul\Desktop\test\datefile.txt", System.IO.FileMode.Create))
{
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(DateTime.Now.ToString());
fs.Write(buffer, 0, buffer.Length);
}
}
Or you can keep filenames in a file or a database table to check a file is before read.
Thanks Coskun
That is a good option and it does work.
For simplicity i went a different route, I add the file names to a list then check the list pre-execution, if the list does not contain that file name it executes. I go on to count the file names in the list and output the total on each pass to a text field that tell me how many files i ignored.
I am trying to delete a folder but am getting the following error message:
The process cannot access the file .it is being used by another process.
string target_dir="D:\\projectpath\\page";
if (Directory.Exists(target_dir))
Directory.Delete(target_dir, false);
How can I resolve this error?
It looks like the file is locked by some other process. This could happen if when reading/writing to it you forgot to dispose the stream reader/writer and you leaked the unmanaged handler to the file.
For example if you used the following code to read from the file:
StreamReader reader = new StreamReader(fileName);
string contents = reader.ReadToEnd();
and you never release the reader, the file will be locked. The proper way is to wrap IDisposable resources such as Streams and StreamReaders in using statements:
using (StreamReader reader = new StreamReader(fileName))
{
string contents = reader.ReadToEnd();
}
If on the other hand the file is locked by some other external process to your application then there's very little you could do about it, other than killing this process.
I think on the surface, your problem should be apparent: the file is in use by something else, so you can't delete the directory it resides in. If there was a way to "force delete" the file, it could cause other programs to crash. I'd recommend catching the error and either logging it or displaying it to the user, so they can decide if they really want to delete the in-use file.
If you MUST delete the file, you could take a look at:
Using C#, how does one figure out what process locked a file?
And once you know what the process is, you can then kill it, which should free up the file. Again, this isn't a good practice and should only be used in exceptional circumstances.
To delete the diectory you must have the correct Permissions.
var target_dir = "D:\\projectpath\page";
var isWriteAccess = false;
try
{
var collection = Directory.GetAccessControl(target_dir)
.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
if (collection.Cast<FileSystemAccessRule>().Any(rule => rule.AccessControlType == AccessControlType.Allow))
{
isWriteAccess = true;
}
}
catch (UnauthorizedAccessException ex)
{
isWriteAccess = false;
}
catch (Exception ex)
{
isWriteAccess = false;
}
if (!isWriteAccess)
{
MessageBox.Show("no access to directory.");
// Handle here close and kill the blocking process
}
else
{
Directory.Delete(target_dir, false);
}
}
HI,
I would like to use the file system as a lock between two processes, on windows xp.
i.e. given a file name "file_lock", a process acquires the lock by trying to create
the file "file_lock" if it doesn't already exist. If already exists, fails to get the lock.
i.e.
FileStream fs=new FileStream("c:\\file_lock, FileMode.CreateNew);
Will this work? Is file creation if file doesn't already exist atomic?
Thanks!
Yes it will work. But not as well as a Mutex for many reasons including:
What if the user doesn't have access to create that file?
When your app crashes, the system cleans up Mutex locks. It won't delete your file for you.
Why introduce the overhead and risk of disk IO unnecessarily? (and I'm not sure if this is possible, but while the file is open, a user can rename or move it, right?)
It's more code.
As the question has been tagged as C#, this answer no longer applies, but I would like to leave it in case it would be helpful for others in the future.
If you're using Java, you could use java.nio.channels.FileLock.
To use it, do something like this:
import java.io.RandomAccessFile;
import java.nio.FileLock;
...
RandomAccessFile raf = new RandomAccessFile(file, "rw");
FileLock lock = raf.getChannel().tryLock(0L, Long.MAX_VALUE, false);
if (lock != null && lock.isValid()) {
// You've acquired the lock!
else {
// You did not acquire the lock
raf.close();
}
Note: This protects against access from other processes, but not other threads. You'll need to use your own internal synchronization for that (locking on raf would probably work).
If you want to use the file as a sync lock i suggest you the next procedure.
Check for the file lock/exists
If file is locked the other process is working
If file doesn't exists or have no lock you can adquire it
Open the file adquiring the lock
This code can help you checking for the lock.
public static bool isFileLocked(string filename)
{
if (!File.Exists(filename)) throw new FileNotFoundException("File not found!", filename);
FileStream fs = null;
try
{
fs = File.Open(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
return false;
}
catch (IOException)
{
return true;
}
catch (Exception)
{
throw;
}
finally
{
if (fs != null)
{
fs.Close();
fs = null;
}
}
}
HTH!
This question already has answers here:
Is there a way to check if a file is in use?
(20 answers)
Closed 6 years ago.
Is there a way to find if a file is already open or not?
protected virtual bool IsFileinUse(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();
}
return false;
}
As #pranay rana, but we need to make sure we close our file handle:
public bool IsFileInUse(string path)
{
if (string.IsNullOrEmpty(path))
throw new ArgumentException("'path' cannot be null or empty.", "path");
try {
using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read)) { }
} catch (IOException) {
return true;
}
return false;
}
If you mean that you want to check if a file is open before you try to open it, then no. (At least not without going low level and examine every file handle that is open in the system.)
Besides, the information would be old when you get it. Even if the test would return that the file is not open, it could have been opened before you have a chance to use the return value.
So, the proper way to handle the situation is to try to open the file, and handle any error than may occur.
Agreed. I would create a designated class which wraps the open file logic or at least the test (IsFileAvailable). This will allow you to place the exception management with a class specifically responsible and make it reusable. You may even apply further logic, such as testing the file size to see if the file is being written to etc, to give a more detailed response. It will also make your consuming code much cleaner.