首页 > 解决方案 > 在不使用进程事件的情况下确定文件何时不再使用

问题描述

除了使用 Process.Exited(){} 事件并测试文件是否被锁定之外,有没有办法确定文件何时不再使用?有没有我们不使用的模式或某些命令可以更好地处理这个问题?

目前,我们在用户的临时文件夹中创建文件,在其默认程序中启动文件(由文件扩展名确定),然后如果有更改则更新文件并在关闭后删除。

这适用于所有单个文件启动。

但是,当在某些程序(如 Gimp、Word 或 Paint.net)中打开第二个或更多文件时,我们会遇到问题。他们打开文件,然后将文件句柄传递给现有进程,关闭作为下面的归档进程创建的初始进程。由于原始进程(文件进程)关闭,Exited 事件过早触发。

如果您将以下代码放入控制台应用程序项目的 Program.cs 并将路径和文件名更改为现有文件。您可以运行它,文件应在其默认查看器/编辑器中打开。可能需要选择默认程序。

我们用 Word 和 GIMP 对此进行了测试,以确保它有效。确保所有 WinWord 进程(或为您决定测试的文件设置为默认程序的任何进程)都已关闭,并在退出事件中使用断点运行程序。您会注意到它仅在程序关闭并且文件未锁定时才会触发。

但是,如果您有 Word 文档或上述任何其他程序,打开然后运行该程序,您会注意到 Exited 事件在打开文档后立即触发。对于 Word 文档,文件被锁定,但对于 GIMP,文件未被锁定。因此,仅在进程退出时确定文件是否被锁定是不够的。

因此,如果它是唯一运行的进程,或者它是保留我们创建的进程的程序,则没有问题。像记事本这样的程序会保留打开每个文件的过程,并且 Exited 事件会按预期触发。

有没有更好的方法来处理这个?

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace ExampleConsole
{
    class Program
    {
        List<FileSystemWatcher> FileWatchers { get; set; } = new List<FileSystemWatcher>();

        static public bool IsFileChanged { get; set; }
        //replace the following with whatever file you prefer, but GIMP, Word, Paint.Net, and FoxIt PDF Editor 
        //are what we have noticed using a single manager processes rather than the process that ran when opening the file.
        static string fileName = "source.gif";
        static string myTempFile = Path.Combine(Path.GetTempPath() + fileName);

        [STAThread]
        static void Main()
        {
            Process fileProcess = Process.Start(new ProcessStartInfo(myTempFile)
            {
                UseShellExecute = true,
                CreateNoWindow = true
            });

            fileProcess.EnableRaisingEvents = true;

            //This is where the issue occurs launching more than 1 Gimp/Word/FoxIt PDF Editor, 
            //the "Exited" Event runs when the process that opened the file closes after handing off to a manager process 
            fileProcess.Exited += (o, args) =>
            {
                if (CheckFileLock(myTempFile))
                {
                    MessageBox.Show("File is locked.");
                }
                else
                {
                    MessageBox.Show("File is not locked.");
                }
                //If the process exits, we read the changes into memory and save to our database.
                if (IsFileChanged)
                {
                    MessageBox.Show("File would be saved.");
                }

                fileProcess?.Dispose();
            };
#if DEBUG
            try
            {
                //...
            }
            finally
            {
                Console.WriteLine("Press enter to close...");
                Console.ReadLine();
            }
#endif

        }

        public static bool CheckFileLock(string filePath)
        {
            try
            {
                using (File.Open(filePath, FileMode.Open)) { }
            }
            catch (IOException e)
            {
                var errorCode = Marshal.GetHRForException(e) & ((1 << 16) - 1);

                return errorCode == 32 || errorCode == 33;
            }

            return false;
        }
    }
}

标签: c#processfilesystemwatchertemporary-filesvirtualfilesystem

解决方案


推荐阅读