如何在c#中自动删除tempfiles ?

时间:2021-03-09 09:18:57

What are a good way to ensure that a tempfile is deleted if my application closes or crashes? Ideally I would like to obtain a tempfile, use it and then forget about it.

如果我的应用程序关闭或崩溃,有什么好方法可以确保一个tempfile被删除?理想情况下,我希望获得一个tempfile,然后使用它,然后忘记它。

Right now I keep a list of my tempfiles and delete them with an eventhandler that triggers on Application.ApplicationExit.

现在,我保留了我的tempfiles列表,并使用一个eventhandler删除它们,它在Application.ApplicationExit上触发。

Is there a better way?

有更好的方法吗?

9 个解决方案

#1


67  

Nothing is guaranteed if the process is killed prematurely, however, I use "using" to do this..

如果这个过程被提前终止,没有什么是可以保证的。

using System;
using System.IO;
sealed class TempFile : IDisposable
{
    string path;
    public TempFile() : this(System.IO.Path.GetTempFileName()) { }

    public TempFile(string path)
    {
        if (string.IsNullOrEmpty(path)) throw new ArgumentNullException("path");
        this.path = path;
    }
    public string Path
    {
        get
        {
            if (path == null) throw new ObjectDisposedException(GetType().Name);
            return path;
        }
    }
    ~TempFile() { Dispose(false); }
    public void Dispose() { Dispose(true); }
    private void Dispose(bool disposing)
    {
        if (disposing)
        {
            GC.SuppressFinalize(this);                
        }
        if (path != null)
        {
            try { File.Delete(path); }
            catch { } // best effort
            path = null;
        }
    }
}
static class Program
{
    static void Main()
    {
        string path;
        using (var tmp = new TempFile())
        {
            path = tmp.Path;
            Console.WriteLine(File.Exists(path));
        }
        Console.WriteLine(File.Exists(path));
    }
}

Now when the TempFile is disposed or garbage-collected the file is deleted (if possible). You could obviously use this as tightly-scoped as you like, or in a collection somewhere.

现在,当TempFile被处理或垃圾收集时,文件将被删除(如果可能的话)。您可以很明显地使用它作为您喜欢的严格限定作用域,或者在某个地方的集合中使用。

#2


44  

Consider using the FileOptions.DeleteOnClose flag:

考虑使用FileOptions。DeleteOnClose国旗:

using (FileStream fs = new FileStream(Path.GetTempFileName(),
       FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None,
       4096, FileOptions.RandomAccess | FileOptions.DeleteOnClose))
{
    // temp file exists
}

// temp file is gone

#3


18  

You could P/Invoke CreateFile and pass the FILE_FLAG_DELETE_ON_CLOSE flag. This tells Windows to delete the file once all handles are closed. See also: Win32 CreateFile docs.

您可以P/调用CreateFile并传递FILE_FLAG_DELETE_ON_CLOSE标志。这告诉Windows在关闭所有句柄后删除该文件。参见:Win32 CreateFile文档。

#4


4  

I would use the .NET TempFileCollection class, as it's built-in, available in old versions of .NET, and implements the IDisposable interface and thus cleans up after itself if used e.g. in conjunction with the "using" keyword.

我将使用。net TempFileCollection类,因为它是内置的,可以在. net的旧版本中使用,并实现IDisposable interface,因此如果使用的话,也会自动清理。

Here's an example that extracts text from an embedded resource (added via the projects property pages -> Resources tab as described here: How to embed a text file in a .NET assembly?, then set to "EmbeddedResource" in the embedded file's property settings).

这里有一个从嵌入式资源中提取文本的示例(通过projects属性页面-> Resources选项卡添加,如本文所述:如何在.NET程序集中嵌入文本文件?),然后在嵌入式文件的属性设置中设置为“EmbeddedResource”)。

    // Extracts the contents of the embedded file, writes them to a temp file, executes it, and cleans up automatically on exit.
    private void ExtractAndRunMyScript()
    {
        string vbsFilePath;

        // By default, TempFileCollection cleans up after itself.
        using (var tempFiles = new System.CodeDom.Compiler.TempFileCollection())
        {
            vbsFilePath= tempFiles.AddExtension("vbs");

            // Using IntelliSense will display the name, but it's the file name
            // minus its extension.
            System.IO.File.WriteAllText(vbsFilePath, global::Instrumentation.Properties.Resources.MyEmbeddedFileNameWithoutExtension);

            RunMyScript(vbsFilePath);
        }

        System.Diagnostics.Debug.Assert(!File.Exists(vbsFilePath), @"Temp file """ + vbsFilePath+ @""" has not been deleted.");
    }

#5


3  

I'm not primarily a C# programmer, but in C++ I'd use RAII for this. There are some hints on using RAII-like behaviour in C# online, but most seem to use the finalizer — which is not deterministic.

我主要不是一个c#程序员,但是在c++中,我将使用RAII。在c#在线中有一些关于使用raii类行为的提示,但大多数似乎都使用终结器——这不是确定性的。

I think there are some Windows SDK functions to create temporary files, but don't know if they are automatically deleted on program termination. There is the GetTempPath function, but files there are only deleted when you log out or restart, IIRC.

我认为有一些Windows SDK函数可以创建临时文件,但是不知道它们是否会在程序终止时自动删除。有GetTempPath函数,但是只有当您退出或重新启动时,才会删除其中的文件IIRC。

P.S. The C# destructor documentation says you can and should release resources there, which I find a bit odd. If so, you could simply delete the tempfile in the destructor, but again, this might not be completely deterministic.

c#析构函数文档说你可以并且应该在那里释放资源,我觉得这有点奇怪。如果是这样,您可以简单地删除析构函数中的tempfile,但同样,这可能不是完全确定的。

#6


2  

Its nice to see that you want to be responsible, but if the files aren't huge (>50MB) you would be in line with everyone (MS included) in leaving them in the temp directory. Disk space is abundant.

很高兴看到您想要负责,但是如果文件不是很大(>50MB),那么您将与所有人(包括MS)保持一致,将它们留在临时目录中。磁盘空间丰富。

As csl posted, the GetTempPath is the way to go. Users who are short on space will be able to run disk cleanup and your files (along with everyone else's) will be cleaned up.

正如csl所发布的,GetTempPath是前进的道路。空间不足的用户将能够运行磁盘清理,您的文件(以及其他人的文件)将被清理。

#7


2  

I use a more reliable solution:

我使用更可靠的解决方案:

using System.IO;
using System.Reflection;

namespace Konard.Helpers
{
    public static partial class TemporaryFiles
    {
        private const string UserFilesListFilenamePrefix = ".used-temporary-files.txt";
        static private readonly object UsedFilesListLock = new object();

        private static string GetUsedFilesListFilename()
        {
            return Assembly.GetEntryAssembly().Location + UserFilesListFilenamePrefix;
        }

        private static void AddToUsedFilesList(string filename)
        {
            lock (UsedFilesListLock)
            {
                using (var writer = File.AppendText(GetUsedFilesListFilename()))
                    writer.WriteLine(filename);
            }
        }

        public static string UseNew()
        {
            var filename = Path.GetTempFileName();
            AddToUsedFilesList(filename);
            return filename;
        }

        public static void DeleteAllPreviouslyUsed()
        {
            lock (UsedFilesListLock)
            {
                var usedFilesListFilename = GetUsedFilesListFilename();

                if (!File.Exists(usedFilesListFilename))
                    return;

                using (var listFile = File.Open(usedFilesListFilename, FileMode.Open))
                {
                    using (var reader = new StreamReader(listFile))
                    {
                        string tempFileToDelete;
                        while ((tempFileToDelete = reader.ReadLine()) != null)
                        {
                            if (File.Exists(tempFileToDelete))
                                File.Delete(tempFileToDelete);
                        }
                    }
                }

                // Clean up
                using (File.Open(usedFilesListFilename, FileMode.Truncate)) { }
            }
        }
    }
}

Every time you need temporary file use:

每次您需要临时文件使用:

var tempFile = TemporaryFiles.UseNew();

To be sure all temporary files are deleted after application closes or crashes put

确保在应用程序关闭或崩溃后删除所有临时文件

TemporaryFiles.DeleteAllPreviouslyUsed();

at start of the application.

在应用程序开始时。

#8


0  

You could launch a thread on startup that will delete files that exist when they "shouldn't" to recover from your crash.

您可以在启动时启动一个线程,该线程将删除在它们“不应该”时存在的文件,以便从崩溃中恢复。

#9


-2  

If you're building a Windows Forms Application, you can use this code:

如果您正在构建一个Windows窗体应用程序,您可以使用以下代码:

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        File.Delete("temp.data");
    }

#1


67  

Nothing is guaranteed if the process is killed prematurely, however, I use "using" to do this..

如果这个过程被提前终止,没有什么是可以保证的。

using System;
using System.IO;
sealed class TempFile : IDisposable
{
    string path;
    public TempFile() : this(System.IO.Path.GetTempFileName()) { }

    public TempFile(string path)
    {
        if (string.IsNullOrEmpty(path)) throw new ArgumentNullException("path");
        this.path = path;
    }
    public string Path
    {
        get
        {
            if (path == null) throw new ObjectDisposedException(GetType().Name);
            return path;
        }
    }
    ~TempFile() { Dispose(false); }
    public void Dispose() { Dispose(true); }
    private void Dispose(bool disposing)
    {
        if (disposing)
        {
            GC.SuppressFinalize(this);                
        }
        if (path != null)
        {
            try { File.Delete(path); }
            catch { } // best effort
            path = null;
        }
    }
}
static class Program
{
    static void Main()
    {
        string path;
        using (var tmp = new TempFile())
        {
            path = tmp.Path;
            Console.WriteLine(File.Exists(path));
        }
        Console.WriteLine(File.Exists(path));
    }
}

Now when the TempFile is disposed or garbage-collected the file is deleted (if possible). You could obviously use this as tightly-scoped as you like, or in a collection somewhere.

现在,当TempFile被处理或垃圾收集时,文件将被删除(如果可能的话)。您可以很明显地使用它作为您喜欢的严格限定作用域,或者在某个地方的集合中使用。

#2


44  

Consider using the FileOptions.DeleteOnClose flag:

考虑使用FileOptions。DeleteOnClose国旗:

using (FileStream fs = new FileStream(Path.GetTempFileName(),
       FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None,
       4096, FileOptions.RandomAccess | FileOptions.DeleteOnClose))
{
    // temp file exists
}

// temp file is gone

#3


18  

You could P/Invoke CreateFile and pass the FILE_FLAG_DELETE_ON_CLOSE flag. This tells Windows to delete the file once all handles are closed. See also: Win32 CreateFile docs.

您可以P/调用CreateFile并传递FILE_FLAG_DELETE_ON_CLOSE标志。这告诉Windows在关闭所有句柄后删除该文件。参见:Win32 CreateFile文档。

#4


4  

I would use the .NET TempFileCollection class, as it's built-in, available in old versions of .NET, and implements the IDisposable interface and thus cleans up after itself if used e.g. in conjunction with the "using" keyword.

我将使用。net TempFileCollection类,因为它是内置的,可以在. net的旧版本中使用,并实现IDisposable interface,因此如果使用的话,也会自动清理。

Here's an example that extracts text from an embedded resource (added via the projects property pages -> Resources tab as described here: How to embed a text file in a .NET assembly?, then set to "EmbeddedResource" in the embedded file's property settings).

这里有一个从嵌入式资源中提取文本的示例(通过projects属性页面-> Resources选项卡添加,如本文所述:如何在.NET程序集中嵌入文本文件?),然后在嵌入式文件的属性设置中设置为“EmbeddedResource”)。

    // Extracts the contents of the embedded file, writes them to a temp file, executes it, and cleans up automatically on exit.
    private void ExtractAndRunMyScript()
    {
        string vbsFilePath;

        // By default, TempFileCollection cleans up after itself.
        using (var tempFiles = new System.CodeDom.Compiler.TempFileCollection())
        {
            vbsFilePath= tempFiles.AddExtension("vbs");

            // Using IntelliSense will display the name, but it's the file name
            // minus its extension.
            System.IO.File.WriteAllText(vbsFilePath, global::Instrumentation.Properties.Resources.MyEmbeddedFileNameWithoutExtension);

            RunMyScript(vbsFilePath);
        }

        System.Diagnostics.Debug.Assert(!File.Exists(vbsFilePath), @"Temp file """ + vbsFilePath+ @""" has not been deleted.");
    }

#5


3  

I'm not primarily a C# programmer, but in C++ I'd use RAII for this. There are some hints on using RAII-like behaviour in C# online, but most seem to use the finalizer — which is not deterministic.

我主要不是一个c#程序员,但是在c++中,我将使用RAII。在c#在线中有一些关于使用raii类行为的提示,但大多数似乎都使用终结器——这不是确定性的。

I think there are some Windows SDK functions to create temporary files, but don't know if they are automatically deleted on program termination. There is the GetTempPath function, but files there are only deleted when you log out or restart, IIRC.

我认为有一些Windows SDK函数可以创建临时文件,但是不知道它们是否会在程序终止时自动删除。有GetTempPath函数,但是只有当您退出或重新启动时,才会删除其中的文件IIRC。

P.S. The C# destructor documentation says you can and should release resources there, which I find a bit odd. If so, you could simply delete the tempfile in the destructor, but again, this might not be completely deterministic.

c#析构函数文档说你可以并且应该在那里释放资源,我觉得这有点奇怪。如果是这样,您可以简单地删除析构函数中的tempfile,但同样,这可能不是完全确定的。

#6


2  

Its nice to see that you want to be responsible, but if the files aren't huge (>50MB) you would be in line with everyone (MS included) in leaving them in the temp directory. Disk space is abundant.

很高兴看到您想要负责,但是如果文件不是很大(>50MB),那么您将与所有人(包括MS)保持一致,将它们留在临时目录中。磁盘空间丰富。

As csl posted, the GetTempPath is the way to go. Users who are short on space will be able to run disk cleanup and your files (along with everyone else's) will be cleaned up.

正如csl所发布的,GetTempPath是前进的道路。空间不足的用户将能够运行磁盘清理,您的文件(以及其他人的文件)将被清理。

#7


2  

I use a more reliable solution:

我使用更可靠的解决方案:

using System.IO;
using System.Reflection;

namespace Konard.Helpers
{
    public static partial class TemporaryFiles
    {
        private const string UserFilesListFilenamePrefix = ".used-temporary-files.txt";
        static private readonly object UsedFilesListLock = new object();

        private static string GetUsedFilesListFilename()
        {
            return Assembly.GetEntryAssembly().Location + UserFilesListFilenamePrefix;
        }

        private static void AddToUsedFilesList(string filename)
        {
            lock (UsedFilesListLock)
            {
                using (var writer = File.AppendText(GetUsedFilesListFilename()))
                    writer.WriteLine(filename);
            }
        }

        public static string UseNew()
        {
            var filename = Path.GetTempFileName();
            AddToUsedFilesList(filename);
            return filename;
        }

        public static void DeleteAllPreviouslyUsed()
        {
            lock (UsedFilesListLock)
            {
                var usedFilesListFilename = GetUsedFilesListFilename();

                if (!File.Exists(usedFilesListFilename))
                    return;

                using (var listFile = File.Open(usedFilesListFilename, FileMode.Open))
                {
                    using (var reader = new StreamReader(listFile))
                    {
                        string tempFileToDelete;
                        while ((tempFileToDelete = reader.ReadLine()) != null)
                        {
                            if (File.Exists(tempFileToDelete))
                                File.Delete(tempFileToDelete);
                        }
                    }
                }

                // Clean up
                using (File.Open(usedFilesListFilename, FileMode.Truncate)) { }
            }
        }
    }
}

Every time you need temporary file use:

每次您需要临时文件使用:

var tempFile = TemporaryFiles.UseNew();

To be sure all temporary files are deleted after application closes or crashes put

确保在应用程序关闭或崩溃后删除所有临时文件

TemporaryFiles.DeleteAllPreviouslyUsed();

at start of the application.

在应用程序开始时。

#8


0  

You could launch a thread on startup that will delete files that exist when they "shouldn't" to recover from your crash.

您可以在启动时启动一个线程,该线程将删除在它们“不应该”时存在的文件,以便从崩溃中恢复。

#9


-2  

If you're building a Windows Forms Application, you can use this code:

如果您正在构建一个Windows窗体应用程序,您可以使用以下代码:

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        File.Delete("temp.data");
    }