Вопрос по filesystemwatcher, .net, c# – FileSystemWatcher - это файл, готовый к использованию

12

Когда файл копируется в папку средства просмотра файлов, как определить, полностью ли файл скопирован и готов к использованию? Потому что я получаю несколько событий во время копирования файла. (Файл копируется с помощью другой программы с использованием File.Copy.)

Ваш Ответ

5   ответов
2

который повторяет доступ к файлу до X раз, сSleep между попытками. Если он никогда не получит доступ, приложение переместится:

private static bool GetIdleFile(string path)
{
    var fileIdle = false;
    const int MaximumAttemptsAllowed = 30;
    var attemptsMade = 0;

    while (!fileIdle && attemptsMade <= MaximumAttemptsAllowed)
    {
        try
        {
            using (File.Open(path, FileMode.Open, FileAccess.ReadWrite))
            {
                fileIdle = true;
            }
        }
        catch
        {
            attemptsMade++;
            Thread.Sleep(100);
        }
    }

    return fileIdle;
}

Это можно использовать так:

private void WatcherOnCreated(object sender, FileSystemEventArgs e)
{
    if (GetIdleFile(e.FullPath))
    {
        // Do something like...
        foreach (var line in File.ReadAllLines(e.FullPath))
        {
            // Do more...
        }
    }
}
0
    private Stream ReadWhenAvailable(FileInfo finfo, TimeSpan? ts = null) => Task.Run(() =>
    {
        ts = ts == null ? new TimeSpan(long.MaxValue) : ts;
        var start = DateTime.Now;
        while (DateTime.Now - start < ts)
        {
            Thread.Sleep(200);
            try
            {
                return new FileStream(finfo.FullName, FileMode.Open);
            }
            catch { }
        }
        return null;
    })
    .Result;

вы можете изменить аспекты этого в соответствии с вашими потребностями.

2

как файл был полностью написан и закрыт.

Решение состоит в том, чтобы использовать временное имя файла и переименовать файл после завершения. Затем следите за событием переименования файла вместо создания или изменения файла.

Это нене работает, если кто-то передает вам файл (например, через FTP или что-то в этом роде) - вы должны знать, что файл готов к использованию, прежде чем вы сможете переименовать его и сказать «готов к использованию :) Tacroy
1

эта проблема не решаема в общем случае. Без предварительного знания об использовании файла вы можетене знаю, закончили ли другие программы работу с файлом.

В вашем конкретном случае вы должны быть в состоянии выяснить, из каких операций состоит File.Copy.

Скорее всего, файл назначения заблокирован во время всей операции. В этом случае вы должны просто попытаться открыть файл и обработать "нарушение режима обмена " исключение.

Вы также можете подождать некоторое время ... - очень ненадежный вариант, но если вы знаете диапазон размеров файлов, у вас может быть разумная задержка, чтобы копирование завершилось.

Вы также можетеизобрести» какая-то система транзакций - то есть создайте другой файл типа "destination_file_name.COPYLOCK» какая программа, которая копирует файл, будет создана перед копированиемdestination_file_name» и удалите потом.

12

лучшее решение, которое я нашел, состояло в том, чтобы постоянно пытаться получить эксклюзивную блокировку файла; во время записи файла попытка блокировки не удастся.этот ответ. Как только файл неЕсли запись больше не выполняется, блокировка будет успешной.

К сожалению, единственный способ сделать это - обернуть try / catch вокруг открытия файла, что заставляет меня съеживаться - необходимость использовать try / catch всегда болезненна. Там просто нетПохоже, что-то обойти это, так чтос тем, что я в конечном итоге использовал.

Изменение кода в этом ответе делает свое дело, поэтому я в итоге использовал что-то вроде этого:

private void WaitForFile(FileInfo file)
{
    FileStream stream = null;
    bool FileReady = false;
    while(!FileReady)
    {
        try
        {
            using(stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None)) 
            { 
                FileReady = true; 
            }
        }
        catch (IOException)
        {
            //File isn't ready yet, so we need to keep on waiting until it is.
        }
        //We'll want to wait a bit between polls, if the file isn't ready.
        if(!FileReady) Thread.Sleep(1000);
    }
}
Вы можете добавить счетчик и прекратить попытки после x неудачных попыток. McGarnagle

Похожие вопросы