简体   繁体   中英

FileSystemWatcher C# - cannot access file because it is being used by another process

I'm using FileSystemWatcher to detect directory changes, and after that I read file content and insert it to database.

Here's my code:

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);
    }
}

If I run this code with CTRL+F5 I received this message:

在此处输入图像描述

But If I go with F5 (Debugging mode) than I receive this and not this error about cannot access process and item is sucessfully saved. This is confusing me really..

Should I dispose watcher? or something like that? Maybe I'm missing something here? 在此处输入图像描述

This is first time I'm using FileSystemWatcher, obliviously something is really wrong here..

PS I've found out that this line is causing an exception:

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

how come?

Thanks guys

Cheers

File.ReadAllLines() cannot access the file when it is open for writing in another application but you can use a FileStream and StreamReader instead.

Replace string[] content = File.ReadAllLines(e.FullPath); with the following code and you should be able to read the contents of the file regardless of whether it is open in another application:

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

As mention in this answer:

Most likely what is happening here is that the FileCreated event is being raised and tries to process the file before is has been completely written to disk.

So, you need to wait until the file has finished to copy. According to this other answer :

From the documentation for FileSystemWatcher:

The OnCreated event is raised as soon as a file is created. If a file is being copied or transferred into a watched directory, the OnCreated event will be raised immediately, followed by one or more OnChanged events.

So, a workaround for your case will be to create a list of strings containing the paths of the files that could not be read in the Created method handler, and re-process those paths in the Changed event of the FileSystemWatcher (read the comments in the code):

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}");
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM