为什么有时在监视文件/目录的更改时,它不将标志更改为true

本文关键字:标志 true 监视 文件 为什么 | 更新日期: 2023-09-27 18:07:12

在构造函数中,我调用WatchDirectory方法:

private void WatchDirectory()
        {
            FileSystemWatcher watcher = new FileSystemWatcher();
            watcher.Path = userVideosDirectory;
            watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size;
            watcher.Filter = "*.mp4";
            watcher.Changed += new FileSystemEventHandler(OnChanged);
            watcher.EnableRaisingEvents = true;
        }

事件OnChanged:

private void OnChanged(object source, FileSystemEventArgs e)
    {
        try
        {
            var info = new FileInfo(e.FullPath);
            fileforupload = info.FullName;
            if (e.ChangeType == WatcherChangeTypes.Changed)
            {
                var theSize = info.Length;
                label2.BeginInvoke((Action)(() =>
                {
                    label2.Text = theSize.ToString();
                }));
            }
            dirchanged = true;
        } 
        catch (Exception ee)
        {
            string err = ee.ToString();
        }
    }

然后我使用while循环来检查dirchange标志何时为真:

                    WatchDirectory();
                    while (dirchanged == false)
                    {
                        if (dirchanged == true)
                        {
                            Youtube_Uploader youtubeupload = new 
                                            Youtube_Uploader(fileforupload);
                            break;
                        }
                    }

问题是,有时它永远不会改变dirchangedtrue上的OnChanged事件。不知道为什么。它似乎触发了OnChanged事件,但有时它不执行dirchanged = true;

因此在while循环内,dirchanged标志始终保持false

我现在添加了一个新方法,我称之为isfilellocked:

protected virtual bool IsFileLocked(FileInfo file)
        {
            FileStream stream = null;
            try
            {
                stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
            }
            catch (IOException)
            {
                return true;
            }
            finally
            {
                if (stream != null)
                    stream.Close();
            }
            return false;
        }

我在OnChanged:

事件中使用它
private void OnChanged(object source, FileSystemEventArgs e)
        {
            try
            {
                var info = new FileInfo(e.FullPath);
                fileforupload = info.FullName;
                IsFileLocked(info);
                if (e.ChangeType == WatcherChangeTypes.Changed)
                {
                    var theSize = info.Length;
                    label2.BeginInvoke((Action)(() =>
                    {
                        label2.Text = theSize.ToString();
                    }));
                }
                dirchanged = true;
            }
            catch (Exception ee)
            {
                string err = ee.ToString();
            }
        }

在方法isfilellocked我得到异常:

进程无法访问文件"C:'Users'bout0_000'Videos'My Great Game - My Great Capture - 2015-08-10 14-22-52.mp4",因为该文件正在被其他进程使用。

我正在使用创建文件的外部程序,并且由于程序仍在创建文件,因此监视器无法访问它。所以我在这里有一个冲突,从一方面我想知道什么时候文件准备好完成创建,但在另一方面我不能知道,因为外部程序仍在处理它。

那么我如何才能发现外部程序何时完成对文件的处理并且文件准备好了呢?

这是while语句的全部代码:

if (request.QueryString[0] == "stop")
                    {
                        dirchanged = false; 
                        StartRecrod();                        
                        result = "Recording stopped and preparing the file to be shared on youtube";
                        WatchDirectory();
                        while (dirchanged == false)
                        {
                            if (dirchanged == true)
                            {
                                string ttttt = "ok";
                                break;
                            }
                        }
                    }

我添加了一个字符串ttttt只是为了测试。当使用断点时,有时会到达字符串ttttt,有时不会。

在我的程序中,当我触摸我的android屏幕时,它发送命令到pc web服务器,它到达这里,但while循环和标志改变有些问题,有时它确实输入while和IF并执行字符串ttttt,有时它没有。

这就是我现在对await:

所做的
TaskCompletionSource<bool> sy;
        public async void SendResponse(HttpListenerRequest request)
        {
            string result = "";
            string key = request.QueryString.GetKey(0);
            if (key == "cmd")
            {
                if (request.QueryString[0] == "nothing")
                {
                    return "Connection Success";
                }
                if (request.QueryString[0] == "start")
                {
                    StartRecrod();
                    result = "Recording started";
                }
                if (request.QueryString[0] == "stop")
                {
                    dirchanged = false;
                    StartRecrod();
                    result = "Recording stopped and preparing the file to be shared on youtube";
                    sy = new TaskCompletionSource<bool>();
                    WatchDirectory();
                    await sy.Task;
                    Youtube_Uploader youtubeupload = new Youtube_Uploader(fileforupload);

                }
            }
            else
            {
                result = "Nothing have been done";
            }
            if (Youtube_Uploader.fileuploadedsuccess != null && Youtube_Uploader.fileuploadedsuccess != "")
            {
                result = Youtube_Uploader.fileuploadedsuccess;
            }
            return result;
        }

但是有些问题。首先,我在所有的返回中得到错误。

错误2由于'Automatic_Record.Form1.SendResponse(System.Net.HttpListenerRequest)'返回void,返回关键字不能后跟对象表达式

和错误时,我的web服务器:

WebServer ws = new WebServer(SendResponse, "http://+:8098/");

在SendResponse我得到:

错误1 'void Automatic_Record.Form1.SendResponse(System.Net.HttpListenerRequest)'的返回类型错误

当将方法更改为async时,现在会发生此错误。

这是我的WebServer方法,我得到错误时,init它因为它应该得到别的东西然后async:

public WebServer(Func<HttpListenerRequest, string> method, params string[] prefixes)
            : this(prefixes, method) { }
        public void Run()
        {
            ThreadPool.QueueUserWorkItem((o) =>
            {
                Console.WriteLine("Webserver running...");
                try
                {
                    while (_listener.IsListening)
                    {
                        ThreadPool.QueueUserWorkItem((c) =>
                        {
                            var ctx = c as HttpListenerContext;
                            try
                            {
                                string rstr = _responderMethod(ctx.Request);
                                System.Diagnostics.Trace.Write(ctx.Request.QueryString);
                                //ctx.Request.QueryString
                                byte[] buf = Encoding.UTF8.GetBytes(rstr);
                                ctx.Response.ContentLength64 = buf.Length;
                                ctx.Response.OutputStream.Write(buf, 0, buf.Length);
                                System.Data.SqlClient.SqlConnectionStringBuilder builder = new System.Data.SqlClient.SqlConnectionStringBuilder();
                            }
                            catch { } // suppress any exceptions
                            finally
                            {
                                // always close the stream
                                ctx.Response.OutputStream.Close();
                            }
                        }, _listener.GetContext());
                    }
                }
                catch { } // suppress any exceptions
            });
        }

为什么有时在监视文件/目录的更改时,它不将标志更改为true

这段代码很糟糕。是的,dirchanged在while循环中总是为假,因为如果它变为真,你将不再处于while循环中。

此外,您的代码阻止事件发生,这可能会阻止文件监视器事件本身,并且也不是优化安全的。使用适当的同步,下面是一个示例:

TaskCompletionSource<bool> sy;
private void OnChanged(object source, FileSystemEventArgs e)
{
    sy.SetResult(true);
}

等待
sy = new TaskCompletionSource<bool>();
WatchDirectory();
await sy.Task; // or sy.Task.Wait()

(需要在包含该代码的方法上使用async关键字)。

这修复了你之前遇到的所有问题——它不会消耗CPU周期,它继续处理Windows消息,如果编译器选择在寄存器中缓存变量,它也不会中断。

dirchanged可能在计算内部if块后被设置为true。然后,下一个循环将在不运行上传程序的情况下发生。

你有两个主要问题吗?

1)。为什么dirchanged没有被设置为true?

和表面原因…

2)。如何使用FileSystemWatcher仅对可用于编辑的文件进行操作?

FileSystemWatcher是出了名的有点敏感,我同意你的诊断,文件访问可能是罪魁祸首。不可预测的文件访问错误正是我所期望的FileSystemWatcher试图对刚刚修改的文件执行某些操作的情况。你能编辑创建文件的代码吗?如果是这样,我对FileSystemWatcher使用的一种方法是让它只监视虚构文件类型(如".fsw")的文件创建。然后,创建该文件的程序将其重命名为""。只要编辑完成,FileSystemWatcher只有在有文件可用时才会被调用,然后它可以将文件重命名为实际类型。另外,如果您可以编辑创建代码,请确保您正在尽您所能从那里发布文件。我以前见过这种行为,因为我忘记关闭textwwriter。

同时,我将移动

这行
 dirchanged = true;

在try语句之外。既然它肯定不会抛出错误,为什么要把它放在那里?另外,你的catch语句并没有真正进行错误处理。在try语句中出现任何错误,并且在到达dirchanged = true行之前被弹出,而不会被警告这是发生的事情。您是否单独测试过委托代码?有必要改变type =的if语句吗?如果您正在进行故障排除,我会考虑限制try语句内容,或者尽可能将其移到while循环之后。

同样,这对你的while语句来说不是更简单吗?

while (dirchanged == false){}
Youtube_Uploader youtubeupload = new Youtube_Uploader(fileforupload);  

这不是最优雅的解决方案,但是如果你知道创建/编辑文件的程序将很快关闭它,那么一个工作就是简单地等待…

while (dirchanged == false){}
System.Threading.Thread.Sleep(1000);
Youtube_Uploader youtubeupload = new Youtube_Uploader(fileforupload);
编辑:更好的是,而不是一个while语句使用Ben Voigt的TaskCompletionSource的建议。你仍然需要处理被锁定的文件,但你应该能够在"任务"被标记为完成后这样做。