c# - 在等待 filesystemwatcher 找到新更改的文件时,您可以让您的程序做其他事情吗?

标签 c# mysql filesystemwatcher

我正在构建一个程序来跟踪目录并在目录中创建新文件时向 mysql 数据库添加一个条目。

我将展示 FileSystemWatcher 的代码,存储实例是一个 mysql 类:

FileSystemWatcher watcher = new FileSystemWatcher
{
    Path = directoryToWatch,
    IncludeSubdirectories = true,
    NotifyFilter = NotifyFilters.Attributes |
                   NotifyFilters.DirectoryName |
                   NotifyFilters.FileName,
    EnableRaisingEvents = true,
    Filter = "*.*"
};

watcher.Created += (OnDirectoryChange);

public void OnDirectoryChange(object sender, FileSystemEventArgs e)
{
    storage.Insert(Settings.Default.added_files, e.Name);
}

这就很清楚了。这是mysql数据库的代码。 CloseConnection 与“OpenConnection”几乎相同,所以我没有复制过来。

public bool OpenConnection()
{
    try
    {
        connection.Open();
        return true;
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

public void Insert(string tablename, string filename, string attractionCode, int number=0)
{
   string query = "INSERT INTO " + tablename + " (FILE_NAME) VALUES('" + filename + "')";

   MySqlCommand cmd = new MySqlCommand(query, connection);

   OpenConnection();
   cmd.ExecuteNonQuery();
   CloseConnection();
}

现在的问题是,当我一次将 20 个文件粘贴到 filesystemwatcher 检查的目录中时,sql 将只处理其中的 18 个。它会抛出“连接已打开”之类的错误。我还在 sql 代码的某处使用了一个 select 语句,例如包含这部分:

MySqlCommand cmd = new MySqlCommand(query, connection);

MySqlDataReader dataReader = cmd.ExecuteReader();

while (dataReader.Read())
{
    list[0].Add(dataReader["id"] + "");
    list[1].Add(dataReader["code"] + "");
    list[2].Add(dataReader["name"] + "");
}

dataReader.Close();

这有时也会引发错误,例如“只能使用一个数据读取器”。

我认为对我来说解决方案是为 filesystemwatcher 处理的所有文件创建某种队列,然后一个接一个地遍历这个队列。但是我该如何处理呢,因为 filesystemwatcher 必须一直监视目录。恐怕在处理队列时可能会遗漏一些文件。有什么用?

最佳答案

借用这个优秀的solution在项目的某处添加此类:

public class BackgroundQueue
{
    private Task previousTask = Task.FromResult(true);
    private object key = new object();
    public Task QueueTask(Action action)
    {
        lock (key)
        {
            previousTask = previousTask.ContinueWith(t => action()
                , CancellationToken.None
                , TaskContinuationOptions.None
                , TaskScheduler.Default);
            return previousTask;
        }
    }

    public Task<T> QueueTask<T>(Func<T> work)
    {
        lock (key)
        {
            var task = previousTask.ContinueWith(t => work()
                , CancellationToken.None
                , TaskContinuationOptions.None
                , TaskScheduler.Default);
            previousTask = task;
            return task;
        }
    }
}

我建议对您的主模块进行以下更改:

// Place this as a module level variable.. so it doesn't go out of scope as long
// as the FileSystemWatcher is running
BackgroundQueue _bq = new BackgroundQueue();

然后进行以下更改以调用队列:

FileSystemWatcher watcher = new FileSystemWatcher
{
    Path = directoryToWatch,
    IncludeSubdirectories = true,
    NotifyFilter = NotifyFilters.Attributes |
                   NotifyFilters.DirectoryName |
                   NotifyFilters.FileName,
    EnableRaisingEvents = true,
    Filter = "*.*"
};

watcher.Created += (OnDirectoryChange);

public void OnDirectoryChange(object sender, FileSystemEventArgs e)
{
     // Using the shorthand lambda syntax
    _bq.QueueTask(() => storage.Insert(Settings.Default.added_files, e.Name));
}

这应该将 FileSystemWatcher 抛出的每个更改排入队列。请记住此 SO Question 中的评论关于 FileSystemWatcher 没有捕获所有内容。

关于c# - 在等待 filesystemwatcher 找到新更改的文件时,您可以让您的程序做其他事情吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49430206/

相关文章:

c# - 派生DataGridView绘图问题。显示黑色区域

c# - 开发 ASP.NET WEB API 服务应用程序

MySQL SELECT WHERE X LIKE a AND NOT LIKE B

PHP - 将多个项目合并为一个

c# - 没有表单的 FileSystemWatcher.SynchronizingObject

node.js - "jest --watch": Error: ENOSPC: System limit for number of file watchers reached, watch

c# - 如何在页面基类中执行Page_Load()?

c# - 我怎样才能一般地转换一个枚举?

python - 加速从 pandas dataframe 到 mysql 的数据插入

c# - FileSystemWatcher 在一段时间后停止引发事件