0

クライアント pc にインストールされている関連プログラムで、ドキュメント/ファイル (.doc、.pdf、.xlsx、.tiff など) をユーザーに開く必要がある Windows フォーム アプリケーション i C# を作成しています。

ユーザーが表示しているプログラムを閉じるとすぐに、ファイルを削除する必要があります。

ファイルを作成して開くためのオプションをいくつか試しましたが、まだ金の卵が見つかりません。

public static void databaseFileRead(string file_name, byte[] file)
{
    path = file_name;
    int file_size_int = file.Length;
    FileStream create = new FileStream(@path, FileMode.Create, FileAccess.ReadWrite, FileShare.Read, file_size_int, FileOptions.DeleteOnClose);
    create.Write(file, 0, file_size_int);
    FileStream open = File.Open(@path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
}

上記の方法で、最後の行 ( ) で「別のプロセスによって使用されているため、プロセスはファイル 'xxx' にアクセスできません」という IOException を取得していますFileStream open = ...

public static void databaseFileRead(string file_name, byte[] file)
{
    path = file_name;
    int file_size_int = file.Length;
    FileStream create = File.OpenWrite(@path);
    var attributes = File.GetAttributes(@path);
    File.SetAttributes(@path, attributes | FileAttributes.ReadOnly|FileAttributes.Temporary);
    create.Close();
    Process p = Process.Start(@path);
    p.WaitForExit();
    File.Delete(@path);
}

また、このメソッドでは、「別のプロセスで使用されているため、プロセスはファイル 'xxx' にアクセスできません」という IOException も取得しています(最後の行 ( File.Delete(@path);) は、ファイルがまだ使用されていることを意味します)。これは正しくあります。p.WaitForExit();OpenOfficeなどのすべてのプログラムを待っているわけではないようです...

で作成したファイルをFileOptions.DeleteOnClose外部プログラムで開いて表示することはできますか? もしそうなら、どのように?

私は、ファイルが使用されなくなるとすぐに Windows がファイルを削除するという考えが気に入っています。

ファイルがユーザーのハード ドライブから自動的に消えることが重要です。最適なオプションは、ストリームまたは同等のファイルからファイルを読み取って開くことです。しかし、私が読んだ限り、これは不可能です...

解決済み:

closeIfReadyただし、例外をキャッチして、ファイルが解放されるまでメソッドを再度呼び出す方法が適切かどうかはわかりません...

   public static void databaseFileRead(string file_name, byte[] file)
    {
        var path = file_name;
        int file_size_int = file.Length;
        if (File.Exists(path))
        {
            File.Delete(path);
        }
        FileStream create = File.OpenWrite(path);
        create.Write(file, 0, file_size_int);
        var attributes = File.GetAttributes(path);
        File.SetAttributes(path, attributes | FileAttributes.Temporary);
        create.Close();
        Process p = Process.Start(path);

        while (!p.HasExited)
        {
            Thread.Sleep(500);
        }
        closeIfReady(path);
    }

    static void closeIfReady(string path)
    {
        try
        { File.Delete(@path); }
        catch
        {
            Thread.Sleep(1000);
            closeIfReady(path);
        }
    }
4

2 に答える 2

3

OK、コメントの後、ここに2番目の方法があります:

void Method2(string file_name, byte[] file)
{
    var path = file_name;
    int file_size_int = file.Length;
    if (File.Exists(path))
    {
        File.Delete(path);
    }
    FileStream create = File.OpenWrite(path);
    var attributes = File.GetAttributes(path);
    File.SetAttributes(path, attributes | FileAttributes.Temporary);
    create.Close();
    Process p = Process.Start(path);

    while (!p.HasExited)  
    {
        Thread.Sleep(100);  
    }

    File.Delete(path);
}

最初に if File.Exists/File.Delete を厳密に必要とするわけではありません。私のデバッグ用に必要だっただけです。ただし、ファイルが削除される前に誰かがアプリケーションを終了した場合は、そこに残しておくことをお勧めします。再作成を試みます。

ただし、この方法の問題点は次 File.SetAttributes(@path, attributes | FileAttributes.ReadOnly|FileAttributes.Temporary);のとおりです。ファイルは読み取り専用で作成されているため、File.Delete で削除することはできません。Windowsエクスプローラーでは、管理者がいる場合はこれを気にしません。そのため、そこから削除できますが、C#はファイル属性を気にします。その行をに変更したところFile.SetAttributes(@path, attributes | FileAttributes.Temporary);、動作するようになりました。

この質問は、p.WaitForExit の問題で使用したリファレンスです。アプリケーションの別のスレッドでこれを開始することをお勧めします。そうしないと、スレッドが終了したことを確認している間にアプリがハングするためです (ウィンドウで白/灰色に変わり、応答していないことがわかります)。wpf を使用している場合はビジュアルを無効にしたり、引き続き使用できるように GUI を再描画したりできますが、これらはハッキーであり、多くの CPU を消費する可能性があります。

于 2013-03-20T00:45:27.140 に答える
0

いくつかのこと。

まず、これが winforms アプリのメイン UI スレッドで実行されている場合、アプリケーションはどちらのソリューションを使用しても応答しなくなります。

第 2 に、どちらのソリューションも、複数の異なるアプリケーションからの正常な終了に依存しています。これは危険です。

外部プロセスがファイル ハンドルを適切にクリーンアップできない場合、ソリューションは無限再帰を引き起こします。このプロパティの信頼性に関する多くのスレッドを見てきたため、Process.HasExited に依存することにも不快感を覚えます。

アプリケーションに関連する一時ディレクトリを使用し、アプリケーションの終了と開始の両方でそのディレクトリをクリーンアップすることをお勧めします (独自のアプリケーションが正常に終了しない場合に備えて)。

于 2013-03-27T21:36:48.897 に答える