【问题标题】:FileSystemWatcher C# - cannot access file because it is being used by another processFileSystemWatcher C# - 无法访问文件,因为它正被另一个进程使用
【发布时间】:2020-05-06 22:04:19
【问题描述】:

我使用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 运行此代码,我会收到以下消息:

但如果我使用 F5(调试模式),我会收到这个,而不是这个关于无法访问进程和项目已成功保存的错误。这真的让我很困惑..

我应该处置观察者吗?或类似的东西?也许我在这里遗漏了一些东西?

这是我第一次使用 FileSystemWatcher,不知不觉这里出了点问题..

P.S 我发现这行导致异常:

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

怎么来的?

谢谢大家

干杯

【问题讨论】:

  • 我想你可以重温这个答案:stackoverflow.com/a/21739647/2844593
  • @Marlonchosky 我之前已经尝试过该帖子,但下面的代码虽然从未执行,但看起来文件从未准备好,真的很奇怪......
  • 我最近写了一个答案。我希望这会有所帮助!

标签: c# wpf filesystemwatcher system.io.file


【解决方案1】:

File.ReadAllLines() 在打开文件以在另一个应用程序中写入时无法访问该文件,但您可以改用FileStreamStreamReader

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

【讨论】:

    【解决方案2】:

    正如this 回答中提到的:

    这里发生的很可能是 FileCreated 事件是 被提出并尝试在之前处理文件 完全写入磁盘。

    因此,您需要等到文件完成复制。根据this other answer

    来自 FileSystemWatcher 的文档:

    创建文件后立即引发 OnCreated 事件。如果一个文件 正在被复制或传输到监视目录中,OnCreated 事件将立即引发,然后是一个或多个 OnChanged 事件。

    因此,针对您的情况的解决方法是创建一个字符串列表,其中包含无法在 Created 方法处理程序中读取的文件的路径,并在 FileSystemWatcher 的 Changed 事件中重新处理这些路径(读取代码中的 cmets):

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

    【讨论】:

    • 它可以工作,但是如果文件有点重并且复制需要超过一秒钟?你试过@Roxy'Pro
    • 是的,我试过 5MB 的文件,反正我收到的最大文件大概是 100KB,所以这可能会起作用,嗯,关于文件的事情很有趣 -.-
    • 嗯,我有疑问,但如果它对你有用,那就太好了! @Roxy'Pro
    • 我收到了非常小的 ini 文件,只有 3 行的数量、数量、价格,仅此而已.. 应该没问题,很快我会更新我的任务以发布我所做的更改我也会试试你的解决方案!
    • 这是一个很小的文件 :) 对于您的情况,它可以完美运行,但是在未来需要更长时间复制文件的其他情况下,请考虑使用更通用方法的解决方案。无论如何,你找到的方式工作,它只是添加了一行代码,虽然它可以改进@Roxy'Pro
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-05
    • 2011-04-17
    • 1970-01-01
    • 2016-12-24
    • 2013-06-28
    • 2018-03-27
    相关资源
    最近更新 更多