【问题标题】:Create temporary file from DB, open it with associated program and delete it afterwards从数据库创建临时文件,用相关程序打开它,然后将其删除
【发布时间】:2013-03-08 22:27:47
【问题描述】:

我正在用 C# 编写一个 Windows 窗体应用程序,我需要在安装在客户端电脑。

用户关闭显示程序后,文件应立即删除。

我尝试了几种创建和打开文件的方法,但还没有找到金蛋。

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);
}

在上面的方法中,我得到一个 IOException,在最后一行 (FileStream open = ...) 指出“该进程无法访问文件 'xxx',因为它正被另一个进程使用”。

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);
}

在这种方法中,我还收到一个 IOException,指出“进程无法访问文件 'xxx',因为它正在被另一个进程使用”在最后一行 (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);
        }
    }

【问题讨论】:

    标签: c# database blob filestream


    【解决方案1】:

    好的,在评论之后,这是第二个可行的方法:

    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);,现在可以使用了。

    This question 是我用于您的 p.WaitForExit 问题的参考。我建议在您的应用程序中的不同线程上启动它,否则您的应用程序将在检查线程退出时挂起(在 Windows 中变为白色/灰色并告诉您它没有响应)。如果您正在使用 wpf,您可以做一些事情,例如使视觉效果无效,或者重绘您的 GUI 以便您仍然可以使用它,但是这些操作很麻烦并且会消耗大量 CPU。

    【讨论】:

    • 如果我在第一种方法中这样做,文件会在打开之前立即被删除,因为FileOption
    • 然后在您的第一个方法中,将FileOptions.DeleteOnClose 放在create.Close() 之后的FileStream 中,从第一个FileStream 中删除DeleteOnClose。这样,当您关闭进程时,它应该删除该文件。
    • File.Open 没有将FileOption 作为参数,我看不到如何使用new FileStream 显示文件。
    • 我已经用一个工作示例编辑了我的答案。我必须自己在方法中设置路径,因为它不是全局变量。
    • 谢谢,但是p.HasExited好像和p.WaitForExit有同样的问题,有没有办法检查文件是否被锁定?
    【解决方案2】:

    几件事。

    首先,如果这是在 winforms 应用程序的主 UI 线程中运行,则使用任一解决方案,您的应用程序都将变得无响应。

    其次,这两种解决方案都依赖于从几个不同的应用程序中优雅退出。这是有风险的。

    如果外部进程未能正确清理文件句柄,您的解决方案将导致无限递归。取决于 Process.HasExited,我也会感到不舒服,因为我已经看到许多关于此属性可靠性的线程。

    我建议使用相对于您的应用程序的临时目录,并在应用程序退出和启动时清理该目录(以防您自己的应用程序无法正常退出)。

    【讨论】:

    • 感谢您的积分。我在打开文件时已经创建了一个单独的线程。
    猜你喜欢
    • 2017-08-21
    • 2018-11-09
    • 1970-01-01
    • 1970-01-01
    • 2017-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多