Наблюдатель файловой системы и большие файлы

var fsw = new FileSystemWatcher(sPath, "*.PPF");
fsw.NotifyFilter = NotifyFilters.FileName;
fsw.IncludeSubdirectories = true;
fsw.Created += FswCreated;
fsw.EnableRaisingEvents = true;

static void FswCreated(object sender, FileSystemEventArgs e)
{
  string sFile = e.FullPath;
  string[] arrLines = File.ReadAllLines(sFile);
}

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


person NickD    schedule 29.09.2010    source источник


Ответы (5)


Решение найдено в stackoverflow и немного изменено.

static bool IsFileLocked(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();
    }

    //file is not locked
    return false;
}

static void FswCreated(object sender, FileSystemEventArgs e)
{
    string sFile = e.FullPath;

    Console.WriteLine("processing file : " + sFile);

    // Wait if file is still open
    FileInfo fileInfo = new FileInfo(sFile);
    while(IsFileLocked(fileInfo))
    {
        Thread.Sleep(500);
    }

    string[] arrLines = File.ReadAllLines(sFile);
}
person NickD    schedule 29.09.2010
comment
спасибо за оформление моей статьи. Где я могу найти правильный формат для моих будущих вопросов? - person NickD; 03.10.2010
comment
Отлично, но если файл доступен только для чтения, произойдет сбой. Вы можете не открывать файл с режимом доступа FileAccess.Read. - person electricalbah; 31.01.2014
comment
Обратите внимание, что ReadAllLines все еще может завершиться ошибкой, когда другой поток открывает файл между тестом и чтением. - person Emond Erno; 15.09.2014
comment
Будет ли FileAccess.Read блокироваться, если он все еще записывает файл? - person tofutim; 18.10.2015

Используйте класс DelayedFileSystemWatcher.cs http://blogs.msdn.com/b/ahamza/archive/2006/02/06/526222.aspx

а потом этот код. Проверьте обработчик событий PrintFileSystemEventHandler. Он пытается прочитать файл в файловом потоке, и если выдается какая-либо ошибка ioerror, он предполагает, что файл все еще читается, поэтому он ждет некоторое время (2 секунды в этом примере), а затем пытается снова. Проверьте метку CONVERSION:

static void Main(string[] args)
    {
        DelayedFileSystemWatcher dfw = new DelayedFileSystemWatcher(@"C:\\Test", "*.*");
        dfw.Changed += new FileSystemEventHandler(Program.FileSystemEventHandlerMethod);
        dfw.Created += new FileSystemEventHandler(Program.FileSystemEventHandlerMethod);
        dfw.Deleted += new FileSystemEventHandler(Program.FileSystemEventHandlerMethod);
        dfw.Error += new ErrorEventHandler(Program.ErrorEventHandlerMethod);
        dfw.Renamed += new RenamedEventHandler(Program.RenamedEventHandlerMethod);

        dfw.IncludeSubdirectories = true;
        dfw.ConsolidationInterval = 1000;
        dfw.EnableRaisingEvents = true;
        Console.WriteLine("Press \'q\' to quit the sample.");
        while (Console.Read() != 'q') ;
        //System.Threading.Thread.Sleep(60000);
        dfw.Dispose();
    }
    private static void FileSystemEventHandlerMethod(object sender, FileSystemEventArgs e)
    {
        PrintFileSystemEventHandler(e);
        System.Console.WriteLine();
    }

    private static void ErrorEventHandlerMethod(object sender, ErrorEventArgs e)
    {
        System.Console.WriteLine(e.GetException().Message);
        System.Console.WriteLine();
    }

    private static void RenamedEventHandlerMethod(object sender, RenamedEventArgs e)
    {
        PrintRenamedEventHandler(e);
        System.Console.WriteLine();
    }

    private static void PrintFileSystemEventHandler(FileSystemEventArgs e)
    {

    CONVERSION:
        try
        {

            if (e.ChangeType != WatcherChangeTypes.Deleted)
            {
                if (!isFolder(e.FullPath) && isFile(e.FullPath))
                {
                    FileStream fs = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.None);
                    fs.Close();
                }

            }
            System.Console.WriteLine(e.Name + " " + e.FullPath + " " + e.ChangeType);

        }
        catch (System.IO.IOException)
        {
            Console.WriteLine("There was an IOException error or File is still copying. Retrying in 2 seconds...");
            System.Threading.Thread.Sleep(2000);
            goto CONVERSION;
        }



        //System.Console.WriteLine(e.Name);
        //System.Console.WriteLine(e.FullPath);
        //System.Console.WriteLine(e.ChangeType);
    }

    private static bool isFolder(string strPath)
    {

        bool isFolderExist = false;
        try
        {
            isFolderExist = Directory.Exists(strPath);
        }
        catch
        {
            isFolderExist = false;
        }
        return isFolderExist;
    }

    private static bool isFile(string strPath)
    {

        bool isFileExist = false;
        try
        {
            isFileExist = File.Exists(strPath);
        }
        catch
        {
            isFileExist = false;
        }
        return isFileExist;
    }


    private static void PrintRenamedEventHandler(RenamedEventArgs e)
    {
        PrintFileSystemEventHandler(e);
        System.Console.WriteLine(e.OldName);
        System.Console.WriteLine(e.OldFullPath);
    }

У меня нет ссылки на проект. но это поможет.

person Thakur    schedule 29.09.2010
comment
Я вижу там goto :) - person Menelaos Vergis; 24.04.2014
comment
ссылка не работает. - person Nick Acosta; 30.01.2021

Я поддерживаю решение, принятое Шаем Эрлихменом. Но, тем не менее, а) вы можете не открывать файл с режимом доступа FileAccess.Read, если это файл только для чтения

б) Некоторые программы во время загрузки имеют какое-то забавное расширение, и когда оно будет завершено, расширение изменится, и хотя файл будет завершен, у вас будет исключение «файл не найден».

Так что обрабатывайте исключения, а также подписывайтесь на событие file.renamed

person electricalbah    schedule 31.01.2014

Насколько я знаю, вы не получите уведомление после завершения копирования, вы можете реализовать механизм повторной попытки.
Если вы получите нарушение сдвига, просто включите таймер, чтобы повторить операцию через X секунд.
Вторая попытка должна быть после X*2 секунды и т. д. (конечно, с некоторыми ограничениями).

person Shay Erlichmen    schedule 29.09.2010

Просто в своем fswCreated поспите около 1/2 секунды с Thread.Sleep(500), если это возможно. Это должно дать вам время, необходимое компьютеру для завершения записи файла.

Конечно, для более медленных жестких дисков этого времени может быть достаточно.

person Richard J. Ross III    schedule 29.09.2010
comment
это не сработает, если файл очень большой, например, в ГБ. решение состоит в том, чтобы попытаться прочитать файл в файловом потоке и обработать исключение io с помощью Thread.Sleep, а затем снова попытаться прочитать файл, проверьте мой ответ ниже - person Thakur; 29.09.2010