4

読み取りアクセスでファイルを開き、その後のファイルへの読み取り|書き込み|削除ファイル共有アクセスを許可しています(ファイルを追跡します)。処理中にファイルが削除された場合、ファイルが削除保留中であることを検出する方法はありますか (「ファイル」セクションhttp://msdn.microsoft.com/en-us/library/aa363858(v=VS.85).aspxを参照) 。 ? 外部プロセス (所有プロセス) が削除を発行した場合、所有プロセスのロジックに干渉しないように、できるだけ早くハンドルを閉じてファイルを削除できるようにしたいと考えています。

私は C# を使用していますが、保留中の削除を検出する方法がありません。ファイルは FileStream オブジェクトを使用して開かれました。C#または他のウィンドウ関数で削除を検出する方法はありますか?

4

5 に答える 5

2

Windows API 関数GetFileInformationByHandleExを使用して、開いているファイルの保留中の削除を検出できます。2 番目の引数は、関数が返す情報の種類を指定できる列挙値です。FileStandardInfo (1) 値により、DeletePending ブール値を含むFILE_STANDARD_INFO構造が返されます。

デモンストレーション ユーティリティを次に示します。

using System;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;

internal static class Native
{
    [DllImport("kernel32.dll", SetLastError = true)]
    public extern static bool GetFileInformationByHandleEx(IntPtr  hFile,
                                                           int     FileInformationClass,
                                                           IntPtr  lpFileInformation,
                                                           uint    dwBufferSize);

    public struct FILE_STANDARD_INFO
    {
        public long AllocationSize;
        public long EndOfFile;
        public uint NumberOfLinks;
        public byte DeletePending;
        public byte Directory;
    }
    public const int FileStandardInfo = 1;
}

internal static class Program
{
    public static bool IsDeletePending(FileStream fs)
    {
        IntPtr buf = Marshal.AllocHGlobal(4096);
        try
        {
            IntPtr handle = fs.SafeFileHandle.DangerousGetHandle();
            if (!Native.GetFileInformationByHandleEx(handle,
                                                     Native.FileStandardInfo,
                                                     buf,
                                                     4096))
            {
                Exception ex = new Exception("GetFileInformationByHandleEx() failed");
                ex.Data["error"] = Marshal.GetLastWin32Error();
                throw ex;
            }
            else
            {
                Native.FILE_STANDARD_INFO info = Marshal.PtrToStructure<Native.FILE_STANDARD_INFO>(buf);
                return info.DeletePending != 0;
            }
        }
        finally
        {
            Marshal.FreeHGlobal(buf);
        }
    }

    public static int Main(string[] args)
    {
        TimeSpan MAX_WAIT_TIME = TimeSpan.FromSeconds(10);

        if (args.Length == 0)
        {
            args = new string[] { "deleteme.txt" };
        }

        for (int i = 0; i < args.Length; ++i)
        {
            string filename = args[i];
            FileStream fs = null;

            try
            {
                fs = File.Open(filename,
                               FileMode.CreateNew,
                               FileAccess.Write,
                               FileShare.ReadWrite | FileShare.Delete);

                byte[] buf = new byte[4096];
                UTF8Encoding utf8 = new UTF8Encoding(false);

                string text = "hello world!\r\n";
                int written = utf8.GetBytes(text, 0, text.Length, buf, 0);
                fs.Write(buf, 0, written);
                fs.Flush();

                Console.WriteLine("{0}: created and wrote line", filename);

                DateTime t0 = DateTime.UtcNow;
                for (;;)
                {
                    Thread.Sleep(16);
                    if (IsDeletePending(fs))
                    {
                        Console.WriteLine("{0}: detected pending delete", filename);
                        break;
                    }
                    if (DateTime.UtcNow - t0 > MAX_WAIT_TIME)
                    {
                        Console.WriteLine("{0}: timeout reached with no delete", filename);
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("{0}: {1}", filename, ex.Message);
            }
            finally
            {
                if (fs != null)
                {
                    Console.WriteLine("{0}: closing", filename);
                    fs.Dispose();
                }
            }
        }
        return 0;
    }
}
于 2019-02-12T19:21:56.723 に答える
0

ファイルが十分に小さい場合、アプリケーションはファイル自体ではなく、ファイルのコピーを処理できます。また、所有しているプロセスが元のファイルを削除したかどうかをアプリケーションが知る必要がある場合は、ファイルにFileSystemWatcher(FSW) を設定します。ファイルが消えると、FSW は処理を中断するフラグを設定できます。

private bool _fileExists = true;

public void Process(string pathToOriginalFile, string pathToCopy)
{
    File.Copy(pathToOriginalFile, pathToCopy);

    FileSystemWatcher watcher = new FileSystemWatcher();
    watcher.Path = pathToOriginalFile;
    watcher.Deleted += new FileSystemEventHandler(OnFileDeleted);

    bool doneProcessing = false;
    watcher.EnableRaisingEvents = true;

    while(_fileExists && !doneProcessing)
    {
        // process the copy here
    }

    ...
}

private void OnFileDeleted(object source, FileSystemEventArgs e)
{
    _fileExists = false;
}
于 2010-09-08T01:05:58.467 に答える
0

いいえ、これを行うクリーンな方法はありません。他のプロセスがファイルを開いたり変更したりすることに懸念がある場合は、oplocks が役に立ちます。しかし、削除処理が削除に設定されたときの通知を探しているだけの場合、これを行うための簡単な方法はありません (ファイル システム フィルターの構築、API のフックなどはアプリケーションにとって恐ろしいものです)。非常に正当な理由なしでやっている)。

于 2010-09-08T01:19:23.790 に答える
0

FileSystemWatcher はおそらく最も近いものですが、「保留中」の削除を検出できません。ファイルが削除されると、FileSystemWatcher でイベントが発生し、ファイル処理を適切に中断するハンドラーをアタッチできます。ファイルを開くときに取得したロック (またはロックの欠如) により、ファイルがまったく削除される可能性がある場合、それが発生したときに読み取り専用の FileStream を閉じるだけで、ファイル システムに影響を与えることはありません。

ファイル ウォッチャーの基本的な手順は、ファイル ウォッチャーを作成し、FileInfo オブジェクトのインスタンスをコンストラクターに渡すことです。FileInfo は、ファイルのパスとファイル名を文字列として渡すだけでインスタンス化するだけで安価に作成できます。次に、その NotifyFilter を、このファイルで監視するファイル システム変更のタイプに設定します。最後に、プロセスのイベント ハンドラーを OnDeleted イベントにアタッチします。このイベント ハンドラーはおそらく、メイン プロセスが読み取れる場所にビット フラグを設定し、FileStream を閉じるだけの簡単なものです。次にストリームを操作しようとすると、例外が発生します。それをキャッチし、フラグを読み取り、それが設定されている場合は、ファイル操作を適切に停止します。ファイル処理を別のワーカー スレッドに配置することもできます。

于 2010-09-07T16:39:58.960 に答える
0

別のシグナリング メカニズムを使用します。(主にフラグが使用されているため、すべてのファイルアクセスは閉じた外部プログラムからではなく、あなたの制御下にあると仮定しています。)

私が考えることができるこれらの境界内の唯一の「解決策」は、ファイルアクセスのポーリングであり、返される例外 (存在する場合) を確認します。おそらくもっとトリッキーなことがあります (win32 ファイル API よりも低いレベルで?!?) が、これはすでに「uhg パス」をたどっています :-)

于 2010-09-07T22:59:13.110 に答える