Вопрос по filestream, filesystemwatcher, c# – FileStream и FileSystemWatcher в C #, странная проблема «процесс не может получить доступ к файлу»

2

У меня есть эта сложная кодовая база, которая прослушивает события FileCreated в определенной папке. Когда файл создан (который также включает перемещение файла в эту папку), я хочу прочитать этот файл и что-то с ним сделать. Это работает для первого файла, но выдает исключение после всех остальных попыток. В режиме отладки (с VisualStudio) будет сгенерирована ошибка, но если я просто нажму «продолжить» ... то будет работать (без ошибки).

Я разместил упрощенный код, который демонстрирует проблему.

Например, вы запускаете приложение, нажимаете кнопку «Пуск», а затем «создаете новый текстовый файл»

Выход:

Working

Если вы затем создаете 2ed-файл точно таким же образом, результат будет следующим:

Broken: The process cannot access the file 'C:\TestFolder\New Text Document (2).txt' because it is being used by another process.
Working, after breaking

Посмотрев на мой код, вы увидите, что вышеприведенный набор распечаток подразумевает, что сначала было сгенерировано исключение «невозможно получить доступ к файлу», но выполнение того же вызова в операторе catch неожиданно работает.

Это не имеет никакого смысла для меня, так как файл явно не используется ничем другим (я только что создал его) .. и он все равно работает секунду спустя ....

Ниже мой код

XAML:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" >
    <StackPanel>
        <Button Click="Button_Click"  Content="Start"/>
    </StackPanel>
</Window>

Код позади:

using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;


namespace WpfApplication1
{ 
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            test();
        }


        String Folder = @"C:\TestFolder";

        private void test()
        {
            FileSystemWatcher watch = new FileSystemWatcher(Folder);
            watch.Created += new FileSystemEventHandler(FileCreated);
            watch.EnableRaisingEvents = true;

            Process.Start(Folder);
        }

        private void FileCreated(object sender, FileSystemEventArgs fsEvent)
        {

            if (File.Exists(fsEvent.FullPath))
            {

                // Thread.Sleep(1000);// Sleeping for 1 second seems to prevent the error from happening...?
                // If i am debugging, and pause on exceptions... then it also suddenly works (similar to the Sleep above)
                try
                {

                    FileStream fs = new FileStream(fsEvent.FullPath, FileMode.Open); 
                    Console.WriteLine("Working");
                    fs.Close();
                }
                catch (IOException ex)
                {
                    Console.WriteLine("Broken: " + ex.Message);
                    try
                    {                        
                        FileStream fs = new FileStream(fsEvent.FullPath, FileMode.Open);
                        Console.WriteLine("Working, after breaking");
                        fs.Close();

                    }
                    catch(IOException ex2)
                    {                        
                        FileStream fs = new FileStream(fsEvent.FullPath, FileMode.Open);
                        Console.WriteLine("really broken: " + ex2.Message);
                        fs.Close();
                    }
                }


            }
        }
    }
}

Ваш Ответ

3   ответа
1

спечение. Большинство из них настроены на сканирование файлов при создании по умолчанию.

+1 за интересную идею в любом случае. (им также не нравится, когда мы отключаем антивирус на работе: P) 00jt
Возможно, но это все еще не объясняет, почему это работает один раз, а затем терпит неудачу. 00jt
Очень хороший момент, но даже с правилами исключений (отключение редко используется в рабочей среде), я видел, что эти блокировки возникают, если вы обращаетесь к файлу сразу после его закрытия. EventHorizon
8

которое вы описываете начиная с .NET 1.0, и никогда не пытался выяснить, почему это происходит. Похоже, что ОС или .NET иногда (?) Блокируют файл на короткое время после того, как вы вызвали close и dispose.

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

Что он делает, так это устанавливает эксклюзивную блокировку на файл. В случае неудачи он может подождать до 10 секунд, пока файл не закроется, прежде чем сдаться

    public static bool IsFileClosed(string filepath, bool wait)
    {
        bool        fileClosed = false;
        int         retries = 20;
        const int   delay = 500; // Max time spent here = retries*delay milliseconds

        if (!File.Exists(filepath))
            return false;

        do
        {
            try 
            {
                // Attempts to open then close the file in RW mode, denying other users to place any locks.
                FileStream fs = File.Open(filepath, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
                fs.Close();
                fileClosed = true; // success
            }
            catch (IOException) {}

            if (!wait) break;

            retries --;

            if (!fileClosed)
                Thread.Sleep( delay );
        }
        while (!fileClosed && retries > 0);

        return fileClosed;
    }
+1 Я мог бы попробовать это ... мой простой "сон (1000)", кажется, работает отлично прямо сейчас. 00jt
3

FileCreated событие вызывается и пытается обработать файл до того, как он будет полностью записан на диск.

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

+1. Но есть идеи, почему это будет работать для первого созданного файла, а не для других файлов впоследствии? 00jt
Не уверен ... Ответ будет зависеть от того, какой механизм используется для создания файлов. Brendan Green

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