Это решение, которое может быть излишним для некоторых пользователей. Я создал новый статический класс, который имеет событие, которое запускается только тогда, когда файл заканчивает копирование.
Пользователь регистрирует файлы, которые они хотели бы посмотреть, позвонив по номеру FileAccessWatcher.RegisterWaitForFileAccess(filePath)
. Если файл еще не просматривается, запускается новая задача, которая повторно проверяет файл, чтобы узнать, можно ли его открыть. Каждый раз, когда он проверяет, он также считывает размер файла. Если размер файла не увеличивается в заданное время (5 минут в моем примере), цикл завершается.
Когда цикл выходит из файла, доступного или с момента ожидания, запускается событие FileFinishedCopying
.
public class FileAccessWatcher
{
// this list keeps track of files being watched
private static ConcurrentDictionary<string, FileAccessWatcher> watchedFiles = new ConcurrentDictionary<string, FileAccessWatcher>();
public static void RegisterWaitForFileAccess(string filePath)
{
// if the file is already being watched, don't do anything
if (watchedFiles.ContainsKey(filePath))
{
return;
}
// otherwise, start watching it
FileAccessWatcher accessWatcher = new FileAccessWatcher(filePath);
watchedFiles[filePath] = accessWatcher;
accessWatcher.StartWatching();
}
/// <summary>
/// Event triggered when the file is finished copying or when the file size has not increased in the last 5 minutes.
/// </summary>
public static event FileSystemEventHandler FileFinishedCopying;
private static readonly TimeSpan MaximumIdleTime = TimeSpan.FromMinutes(5);
private readonly FileInfo file;
private long lastFileSize = 0;
private DateTime timeOfLastFileSizeIncrease = DateTime.Now;
private FileAccessWatcher(string filePath)
{
this.file = new FileInfo(filePath);
}
private Task StartWatching()
{
return Task.Factory.StartNew(this.RunLoop);
}
private void RunLoop()
{
while (this.IsFileLocked())
{
long currentFileSize = this.GetFileSize();
if (currentFileSize > this.lastFileSize)
{
this.lastFileSize = currentFileSize;
this.timeOfLastFileSizeIncrease = DateTime.Now;
}
// if the file size has not increased for a pre-defined time limit, cancel
if (DateTime.Now - this.timeOfLastFileSizeIncrease > MaximumIdleTime)
{
break;
}
}
this.RemoveFromWatchedFiles();
this.RaiseFileFinishedCopyingEvent();
}
private void RemoveFromWatchedFiles()
{
FileAccessWatcher accessWatcher;
watchedFiles.TryRemove(this.file.FullName, out accessWatcher);
}
private void RaiseFileFinishedCopyingEvent()
{
FileFinishedCopying?.Invoke(this,
new FileSystemEventArgs(WatcherChangeTypes.Changed, this.file.FullName, this.file.Name));
}
private long GetFileSize()
{
return this.file.Length;
}
private bool IsFileLocked()
{
try
{
using (this.file.Open(FileMode.Open)) { }
}
catch (IOException e)
{
var errorCode = Marshal.GetHRForException(e) & ((1 << 16) - 1);
return errorCode == 32 || errorCode == 33;
}
return false;
}
}
Пример использования:
// register the event
FileAccessWatcher.FileFinishedCopying += FileAccessWatcher_FileFinishedCopying;
// start monitoring the file (put this inside the OnChanged event handler of the FileSystemWatcher
FileAccessWatcher.RegisterWaitForFileAccess(fileSystemEventArgs.FullPath);
Ручка FileFinishedCopyingEvent:
private void FileAccessWatcher_FileFinishedCopying(object sender, FileSystemEventArgs e)
{
Console.WriteLine("File finished copying: " + e.FullPath);
}
возможный дубликат из [Есть ли способ проверить, используется ли файл?] (http://stackoverflow.com/questions/876473/is-there-a-way-to-check-if-a-file-is-in -use) –
Этот код имеет простую ошибку с 'File.Create (fileName)'. Ответы отсутствуют. Нет необходимости ждать закрытия. – usr