Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用Rx监控项目文件和外部更改文件?_C#_.net_System.reactive - Fatal编程技术网

C# 如何使用Rx监控项目文件和外部更改文件?

C# 如何使用Rx监控项目文件和外部更改文件?,c#,.net,system.reactive,C#,.net,System.reactive,我想重现VisualStudio的行为,它会在外部接触项目文件时通知您,并建议重新加载它 由于需求,我认为反应式是解决该问题的最佳匹配 我正在使用本文中描述的修改过的反应式FileSystemWatcher: 当我从项目中删除或添加文件时,它是这样使用的 OnProjectChanged(new FileChanged(archive.Filename, FileChangeTypes.Deleted, SourceChangeTypes.Project));

我想重现VisualStudio的行为,它会在外部接触项目文件时通知您,并建议重新加载它

由于需求,我认为反应式是解决该问题的最佳匹配

我正在使用本文中描述的修改过的反应式FileSystemWatcher:

当我从项目中删除或添加文件时,它是这样使用的

        OnProjectChanged(new FileChanged(archive.Filename, FileChangeTypes.Deleted, SourceChangeTypes.Project));

        OnProjectChanged(new FileChanged(archive.Filename, FileChangeTypes.Added, SourceChangeTypes.Project));
现在,我可以开始利用这两个流,通过需要对左右持续时间选择器进行微调的连接,我可以检测到应用程序修改了哪个文件:

    private void ObserveProjectModifications(string projectFilePath)
    {
        _observeFolderChanges = FileWatcher.ObserveFolderChanges(Path.GetDirectoryName(projectFilePath), "*.*", TimeSpan.FromMilliseconds(500), IsPartOfProject);

        _observeProjectChanges = Observable.FromEventPattern<ProjectChangedEventHandler, FileChanged>(h => ProjectChanged += h, h => ProjectChanged -= h).Select(pattern => pattern.EventArgs);

        _changes = _observeProjectChanges.Join(_observeFolderChanges, _ => Observable.Never<Unit>(),  _ => Observable.Never<Unit>(), ResultSelector).Where(changed => IsPartOfProject(changed.FullPath));
    }

    private FileChanged ResultSelector(FileChanged fileChanged, FileChanged projectChanged)
    {
        if (Logger.IsDebugEnabled)
        {
            Logger.Debug($"ResultSelector File [{fileChanged.FileChangeType}] {fileChanged.FullPath} # Project [{projectChanged.FileChangeType}] {projectChanged.FullPath}");
        }

        if (fileChanged.FullPath == projectChanged.FullPath)
        {
            if (fileChanged.FileChangeType == projectChanged.FileChangeType)
            {
                if (fileChanged.SourceChangeType != projectChanged.SourceChangeType)
                {
                    return projectChanged;
                }

                return fileChanged;
            }

            return fileChanged;
        }

        return fileChanged;
    }

    private bool IsPartOfProject(string fullPath)
    {
        if (_projectFileManager.ProjectFilePath.Equals(fullPath)) return true;

        return _archives.Values.Any(a => a.Filename.Equals(fullPath));
    }

我的问题是,我还想知道一个文件被外部修改了!任何想法都会非常有用!感谢

不幸的是,FileSystemWatcher没有提供哪个进程修改了文件的信息,因此您在这方面有点运气不佳。我能想到的可能性很少:

忽略标志-当应用程序进行更改时,可以设置标志,并在设置标志时忽略事件。这是最简单的方法,但是如果在设置标志时同时发生一些外部更改,那么您可能会错过这些更改,而且由于您的限制,这些更改变得更加复杂。 标记文件-无论何时更改文件,都会生成guid或类似的guid,用于标记文件。然后,每当触发文件更改时,您都会检查文件属性是否可以存储为真实的文件系统文件属性-例如类似于您在文件资源管理器中详细看到的jpeg元数据,有更多的方法来设置这样的文件属性,如果标签与您拥有的不同或缺少的标签,那么您知道它是外部的-在这里,您还需要注意节流和标签过时等问题 Minifilter文件系统驱动程序-这将是最干净的解决方案,可能与Visual studio使用的非常接近-只是一个猜测。它基本上是一个通用的windows驱动程序,可以监视任何I/O更改。Microsoft创建了名为的参考实现,这是一个监视和记录系统中发生的任何I/O和事务活动的小工具。您不必自己实现驱动程序,因为在github上已经有一个使用这种方法实现的驱动程序。文件系统监视程序提供了哪个进程修改了文件的信息。这里唯一的问题是驱动程序本身需要先安装,然后才能使用,所以您需要管理员特权的安装程序。
目前我所能想到的就是这些。

因此,当您保存它以及其他内容时,当前所有内容的简短部分会通知您。好您可以创建一个标志,表明filewatcher拾取和删除的是我,如果是这样的话,或者关闭watcher,保存并重新打开它。假设您的应用程序保存需要很长时间,同时用户也更改了文件系统中的某些内容,那么您将不会收到通知,因为filewatcher已关闭。关于标志,这是我们对FileChanged所做的,我认为如果您的文件正在保存,它应该被锁定!如果我们在同一个文件上讨论更改,这是正确的;从我的应用程序保存,尝试从windows资源管理器更改。我的意思是,如果关闭FileSystemWatcher,我可能会丢失由Windows Explorer用户修改的项目其他文件的一些信息,这就是为什么使用标志更好的原因。。因为如果file=file我关心的,或者只监视打开的文件,那么可以使用某种形式的结构
        OnProjectChanged(new FileChanged(archive.Filename, FileChangeTypes.Deleted, SourceChangeTypes.Project));

        OnProjectChanged(new FileChanged(archive.Filename, FileChangeTypes.Added, SourceChangeTypes.Project));
    private void ObserveProjectModifications(string projectFilePath)
    {
        _observeFolderChanges = FileWatcher.ObserveFolderChanges(Path.GetDirectoryName(projectFilePath), "*.*", TimeSpan.FromMilliseconds(500), IsPartOfProject);

        _observeProjectChanges = Observable.FromEventPattern<ProjectChangedEventHandler, FileChanged>(h => ProjectChanged += h, h => ProjectChanged -= h).Select(pattern => pattern.EventArgs);

        _changes = _observeProjectChanges.Join(_observeFolderChanges, _ => Observable.Never<Unit>(),  _ => Observable.Never<Unit>(), ResultSelector).Where(changed => IsPartOfProject(changed.FullPath));
    }

    private FileChanged ResultSelector(FileChanged fileChanged, FileChanged projectChanged)
    {
        if (Logger.IsDebugEnabled)
        {
            Logger.Debug($"ResultSelector File [{fileChanged.FileChangeType}] {fileChanged.FullPath} # Project [{projectChanged.FileChangeType}] {projectChanged.FullPath}");
        }

        if (fileChanged.FullPath == projectChanged.FullPath)
        {
            if (fileChanged.FileChangeType == projectChanged.FileChangeType)
            {
                if (fileChanged.SourceChangeType != projectChanged.SourceChangeType)
                {
                    return projectChanged;
                }

                return fileChanged;
            }

            return fileChanged;
        }

        return fileChanged;
    }

    private bool IsPartOfProject(string fullPath)
    {
        if (_projectFileManager.ProjectFilePath.Equals(fullPath)) return true;

        return _archives.Values.Any(a => a.Filename.Equals(fullPath));
    }