FileSystemWatcher C# - нет доступа к файлу, потому что он используется другим процессом - PullRequest
1 голос
/ 07 мая 2020

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

Вот мой код:

private FileSystemWatcher _watcher;

public MainWindow()
{
    try
    {
        InitializeComponent();

        GetFiles();

        //Task.Factory.StartNew(() => GetFiles())
        //   .ContinueWith(task =>
        //   {
        //   }, System.Threading.CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
    }
    catch(Exception ex)
    {
        //..
    }
}

public bool GetFiles()
{
    _watcher = new FileSystemWatcher(Globals.iniFilesPath, "*.ini");
    _watcher.Created += FileCreated;
    _watcher.IncludeSubdirectories = false;
    _watcher.EnableRaisingEvents = true;
    return true;
}

private void FileCreated(object sender, FileSystemEventArgs e)
{
    try
    {
        string fileName = Path.GetFileNameWithoutExtension(e.FullPath);

        if (!String.IsNullOrEmpty(fileName))
        {
            string[] content = File.ReadAllLines(e.FullPath);
            string[] newStringArray = content.Select(s => s.Substring(s.LastIndexOf('=') + 1)).ToArray();

            ChargingStationFile csf = new Product
            {
                Quantity = Convert.ToDecimal(newStringArray[1]),
                Amount = Convert.ToDecimal(newStringArray[2]),
                Price = Convert.ToDecimal(newStringArray[3]),
                FileName = fileName
            };

            ProductController.Instance.Save(csf);
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Если я запустил этот код с CTRL + F5 Я получил это сообщение:

enter image description here

Но если я go с F5 (режим отладки), чем я получаю это, а не эту ошибку о невозможности доступа к процессу, и элемент успешно сохранен. Это меня действительно сбивает с толку ..

Стоит ли избавляться от watcher? или что-то вроде того? Может я что-то здесь упускаю? enter image description here

Я впервые использую FileSystemWatcher, я совершенно не понимаю, что здесь что-то не так ..

PS Я обнаружил, что эта строка вызывает исключение:

string[] content = File.ReadAllLines(e.FullPath);

почему?

Спасибо, ребята

Ура

Ответы [ 2 ]

1 голос
/ 07 мая 2020

File.ReadAllLines() не может получить доступ к файлу, когда он открыт для записи в другом приложении, но вместо этого вы можете использовать FileStream и StreamReader.

Замените string[] content = File.ReadAllLines(e.FullPath); следующим кодом, и вы сможете читать содержимое файла независимо от того, открыт ли он в другом приложении:

List<string> content = new List<string>();
using (FileStream stream = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (StreamReader sr = new StreamReader(stream))
{
    while (!sr.EndOfStream)
        content.Add(sr.ReadLine());
}
0 голосов
/ 07 мая 2020

Как упоминается в этот ответ:

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

Итак, вам нужно дождаться окончания копирования файла. Согласно этот другой ответ :

Из документации для FileSystemWatcher:

Событие OnCreated возникает, как только файл создается. Если файл копируется или передается в отслеживаемый каталог, событие OnCreated будет вызвано немедленно, за ним последуют одно или несколько событий OnChanged.

Таким образом, обходным путем для вашего случая будет создание список строк, содержащих пути к файлам, которые не могут быть прочитаны в обработчике метода Created, и повторно обработать эти пути в событии Changed объекта FileSystemWatcher (прочтите комментарии в коде):

public partial class MainWindow : Window {
    private FileSystemWatcher _watcher;

    public MainWindow() {
        try {
            InitializeComponent();

            GetFiles();
        } catch (Exception ex) {
            MessageBox.Show($"Exception: {ex.Message}");
        }
    }

    private bool GetFiles() {
        _watcher = new FileSystemWatcher(@"C:\TestFolder", "*.ini");
        _watcher.Created += FileCreated;
        _watcher.Changed += FileChanged; // add this.
        _watcher.IncludeSubdirectories = false;
        _watcher.EnableRaisingEvents = true;
        return true;
    }

    // this field is new, and contains the paths of the files that could not be read in the Created method handler. 
    private readonly IList<string> _waitingForClose = new List<string>();

    private void FileChanged(object sender, FileSystemEventArgs e) {
        if (_waitingForClose.Contains(e.FullPath)) {
            try {
                string[] content = File.ReadAllLines(e.FullPath);
                string[] newStringArray = content.Select(s => s.Substring(s.LastIndexOf('=') + 1)).ToArray();

                MessageBox.Show($"On FileChanged: {string.Join(" --- ", newStringArray)}");

                // Again, process the data from the file to saving in the database.

                // removing the path, so as not to reprocess the file..
                _waitingForClose.Remove(e.FullPath);
            } catch (Exception ex) {
                MessageBox.Show($"Exception on FileChanged: {ex.Message} - {e.FullPath}");
            }
        }
    }

    private void FileCreated(object sender, FileSystemEventArgs e) {
        try {
            string fileName = Path.GetFileNameWithoutExtension(e.FullPath);

            if (!String.IsNullOrEmpty(fileName)) {
                string[] content = File.ReadAllLines(e.FullPath);
                string[] newStringArray = content.Select(s => s.Substring(s.LastIndexOf('=') + 1)).ToArray();

                MessageBox.Show($"On FileCreated: {string.Join(" --- ", newStringArray)}");

                // process the data from the file to saving in the database.
            }
        } catch (Exception ex) {
            // if the method fails, add the path to the _waitingForClose variable
            _waitingForClose.Add(e.FullPath);
            //MessageBox.Show($"Exception on FIleCreated: {ex.Message} - {e.FullPath}");
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...