ASP.NET 计划删除临时文件

发布于 2024-09-01 12:14:41 字数 145 浏览 8 评论 0 原文

问题:我有一个 ASP.NET 应用程序,它可以创建临时 PDF 文件(供用户下载)。 现在,许多用户在很多天内都可以创建许多 PDF,这会占用大量磁盘空间。

安排删除超过 1 天/8 小时的文件的最佳方法是什么? 最好在 asp.net 应用程序本身中...

Question: I have an ASP.NET application which creates temporary PDF files (for the user to download).
Now, many users over many days can create many PDFs, which take much disk space.

What's the best way to schedule deletion of files older than 1 day/ 8 hours ?
Preferably in the asp.net application itselfs...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

林空鹿饮溪 2024-09-08 12:14:41

对于需要创建的每个临时文件,记下会话中的文件名:

// create temporary file:
string fileName = System.IO.Path.GetTempFileName();
Session[string.Concat("temporaryFile", Guid.NewGuid().ToString("d"))] = fileName;
// TODO: write to file

接下来,将以下清理代码添加到 global.asax:

<%@ Application Language="C#" %>
<script RunAt="server">
    void Session_End(object sender, EventArgs e) {
        // Code that runs when a session ends. 
        // Note: The Session_End event is raised only when the sessionstate mode
        // is set to InProc in the Web.config file. If session mode is set to StateServer 
        // or SQLServer, the event is not raised.

        // remove files that has been uploaded, but not actively 'saved' or 'canceled' by the user
        foreach (string key in Session.Keys) {
            if (key.StartsWith("temporaryFile", StringComparison.OrdinalIgnoreCase)) {
                try {
                    string fileName = (string)Session[key];
                    Session[key] = string.Empty;
                    if ((fileName.Length > 0) && (System.IO.File.Exists(fileName))) {
                        System.IO.File.Delete(fileName);
                    }
                } catch (Exception) { }
            }
        }

    }       
</script>

更新:我现在准确地使用新的 (改进)方法比上述方法。新的一项涉及 HttpRuntime.Cache 并检查文件是否超过 8 小时。如果有人感兴趣的话我会把它发布在这里。这是我的新 global.asax.cs

using System;
using System.Web;
using System.Text;
using System.IO;
using System.Xml;
using System.Web.Caching;

public partial class global : System.Web.HttpApplication {
    protected void Application_Start() {
        RemoveTemporaryFiles();
        RemoveTemporaryFilesSchedule();
    }

    public void RemoveTemporaryFiles() {
        string pathTemp = "d:\\uploads\\";
        if ((pathTemp.Length > 0) && (Directory.Exists(pathTemp))) {
            foreach (string file in Directory.GetFiles(pathTemp)) {
                try {
                    FileInfo fi = new FileInfo(file);
                    if (fi.CreationTime < DateTime.Now.AddHours(-8)) {
                        File.Delete(file);
                    }
                } catch (Exception) { }
            }
        }
    }

    public void RemoveTemporaryFilesSchedule() {
        HttpRuntime.Cache.Insert("RemoveTemporaryFiles", string.Empty, null, DateTime.Now.AddHours(1), Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, delegate(string id, object o, CacheItemRemovedReason cirr) {
            if (id.Equals("RemoveTemporaryFiles", StringComparison.OrdinalIgnoreCase)) {
                RemoveTemporaryFiles();
                RemoveTemporaryFilesSchedule();
            }
        });
    }
}

For each temporary file that you need to create, make a note of the filename in the session:

// create temporary file:
string fileName = System.IO.Path.GetTempFileName();
Session[string.Concat("temporaryFile", Guid.NewGuid().ToString("d"))] = fileName;
// TODO: write to file

Next, add the following cleanup code to global.asax:

<%@ Application Language="C#" %>
<script RunAt="server">
    void Session_End(object sender, EventArgs e) {
        // Code that runs when a session ends. 
        // Note: The Session_End event is raised only when the sessionstate mode
        // is set to InProc in the Web.config file. If session mode is set to StateServer 
        // or SQLServer, the event is not raised.

        // remove files that has been uploaded, but not actively 'saved' or 'canceled' by the user
        foreach (string key in Session.Keys) {
            if (key.StartsWith("temporaryFile", StringComparison.OrdinalIgnoreCase)) {
                try {
                    string fileName = (string)Session[key];
                    Session[key] = string.Empty;
                    if ((fileName.Length > 0) && (System.IO.File.Exists(fileName))) {
                        System.IO.File.Delete(fileName);
                    }
                } catch (Exception) { }
            }
        }

    }       
</script>

UPDATE: I'm now accually using a new (improved) method than the one described above. The new one involves HttpRuntime.Cache and checking that the files are older than 8 hours. I'll post it here if anyones interested. Here's my new global.asax.cs:

using System;
using System.Web;
using System.Text;
using System.IO;
using System.Xml;
using System.Web.Caching;

public partial class global : System.Web.HttpApplication {
    protected void Application_Start() {
        RemoveTemporaryFiles();
        RemoveTemporaryFilesSchedule();
    }

    public void RemoveTemporaryFiles() {
        string pathTemp = "d:\\uploads\\";
        if ((pathTemp.Length > 0) && (Directory.Exists(pathTemp))) {
            foreach (string file in Directory.GetFiles(pathTemp)) {
                try {
                    FileInfo fi = new FileInfo(file);
                    if (fi.CreationTime < DateTime.Now.AddHours(-8)) {
                        File.Delete(file);
                    }
                } catch (Exception) { }
            }
        }
    }

    public void RemoveTemporaryFilesSchedule() {
        HttpRuntime.Cache.Insert("RemoveTemporaryFiles", string.Empty, null, DateTime.Now.AddHours(1), Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, delegate(string id, object o, CacheItemRemovedReason cirr) {
            if (id.Equals("RemoveTemporaryFiles", StringComparison.OrdinalIgnoreCase)) {
                RemoveTemporaryFiles();
                RemoveTemporaryFilesSchedule();
            }
        });
    }
}
半岛未凉 2024-09-08 12:14:41

尝试使用Path.GetTempPath()。它将为您提供 Windows 临时文件夹的路径。然后将由 Windows 来清理:)

您可以在此处阅读有关该方法的更多信息 http://msdn.microsoft.com/en-us/library/system.io.path.gettemppath.aspx

Try using Path.GetTempPath(). It will give you a path to a windows temp folder. Then it will be up to windows to clean up :)

You can read more about the method here http://msdn.microsoft.com/en-us/library/system.io.path.gettemppath.aspx

愿得七秒忆 2024-09-08 12:14:41

最好的方法是创建一个批处理文件,Windows 任务计划程序会按照您想要的时间间隔调用该文件。

或者

您可以使用上面的类创建一个 Windows 服务。

public class CleanUpBot
{

public bool KeepAlive;

private Thread _cleanUpThread;

public void Run()
{

_cleanUpThread = new Thread(StartCleanUp);

}

private void StartCleanUp()
{

do

{

// HERE THE LOGIC FOR DELETE FILES

_cleanUpThread.Join(TIME_IN_MILLISECOND);

}while(KeepAlive)

}

}

请注意,您也可以在 pageLoad 中调用此类,并且它不会影响处理时间,因为处理是在另一个线程中进行的。只需删除 do-while 和 Thread.Join() 即可。

The Best way is to create a batch file which it be called by the windows task scheduler one at the interval that you want.

OR

you can create a windows service with the class above

public class CleanUpBot
{

public bool KeepAlive;

private Thread _cleanUpThread;

public void Run()
{

_cleanUpThread = new Thread(StartCleanUp);

}

private void StartCleanUp()
{

do

{

// HERE THE LOGIC FOR DELETE FILES

_cleanUpThread.Join(TIME_IN_MILLISECOND);

}while(KeepAlive)

}

}

Notice that you can also call this class at the pageLoad and it wont affect the process time because the treatment is in another thread. Just remove the do-while and the Thread.Join().

哥,最终变帅啦 2024-09-08 12:14:41

你如何存储文件?如果可能,您可以采用一个简单的解决方案,其中所有文件都存储在以当前日期和时间命名的文件夹中。
然后创建一个简单的页面或 httphandler 来删除旧文件夹。您可以使用 Windows 计划或其他 cron 作业定期调用此页面。

How do you store the files? If possible, you could just go with a simple solution, where all files are stored in a folder named after the current date and time.
Then create a simple page or httphandler that will delete old folders. You could call this page at intervals using a Windows schedule or other cron job.

℡Ms空城旧梦 2024-09-08 12:14:41

在 Appication_Start 上创建一个计时器,并安排计时器每 1 小时调用一次方法,并刷新超过 8 小时或 1 天或您需要的任何持续时间的文件。

Create a timer on Appication_Start and schedule the timer to call a method on every 1 hours and flush the files older than 8 hours or 1 day or whatever duration you need.

且行且努力 2024-09-08 12:14:41

我有点同意德克在回答中所说的内容。

这个想法是,您将文件放置到的临时文件夹是一个固定的已知位置,但我略有不同...

  1. 每次创建文件时,都会将文件名添加到会话对象中的列表中(假设没有) t 数千,如果有,当此列表达到给定上限时,执行下一位)

  2. 当会话结束时,应在 global.asax 中引发 Session_End 事件。迭代列表中的所有文件并删除它们。

I sort of agree with whats said in the answer by dirk.

The idea being that the temp folder in which you drop the files to is a fixed known location however i differ slightly ...

  1. Each time a file is created add the filename to a list in the session object (assuming there isn't thousands, if there is when this list hits a given cap do the next bit)

  2. when the session ends the Session_End event should be raised in global.asax should be raised. Iterate all the files in the list and remove them.

沧笙踏歌 2024-09-08 12:14:41
    private const string TEMPDIRPATH = @"C:\\mytempdir\";
    private const int DELETEAFTERHOURS = 8;

    private void cleanTempDir()
    {
        foreach (string filePath in Directory.GetFiles(TEMPDIRPATH))
        {
            FileInfo fi = new FileInfo(filePath);
            if (!(fi.LastWriteTime.CompareTo(DateTime.Now.AddHours(DELETEAFTERHOURS * -1)) <= 0)) //created or modified more than x hours ago? if not, continue to the next file
            {
                continue;
            }

            try
            {
                File.Delete(filePath);
            }
            catch (Exception)
            {
                //something happened and the file probably isn't deleted. the next time give it another shot
            }
        }
    }

上面的代码将删除 temp 目录中超过 8 小时前创建或修改的文件。

不过我建议使用另一种方法。正如 Fredrik Johansson 所建议的,您可以在会话结束时删除用户创建的文件。更好的方法是根据临时目录中用户的会话 ID 使用额外的目录。当会话结束时,您只需删除为用户创建的目录即可。

    private const string TEMPDIRPATH = @"C:\\mytempdir\";
    string tempDirUserPath = Path.Combine(TEMPDIRPATH, HttpContext.Current.User.Identity.Name);
    private void removeTempDirUser(string path)
    {
        try
        {
            Directory.Delete(path);
        }
        catch (Exception)
        {
            //an exception occured while deleting the directory.
        }
    }
    private const string TEMPDIRPATH = @"C:\\mytempdir\";
    private const int DELETEAFTERHOURS = 8;

    private void cleanTempDir()
    {
        foreach (string filePath in Directory.GetFiles(TEMPDIRPATH))
        {
            FileInfo fi = new FileInfo(filePath);
            if (!(fi.LastWriteTime.CompareTo(DateTime.Now.AddHours(DELETEAFTERHOURS * -1)) <= 0)) //created or modified more than x hours ago? if not, continue to the next file
            {
                continue;
            }

            try
            {
                File.Delete(filePath);
            }
            catch (Exception)
            {
                //something happened and the file probably isn't deleted. the next time give it another shot
            }
        }
    }

The code above will remove the files in the temp directory that are created or modified more than 8 hours ago.

However I would suggest to use another approach. As Fredrik Johansson suggested, you can delete the files created by the user when the session ends. Better is to work with an extra directory based on the session ID of the user in you temp directory. When the session ends you simply delete the directory created for the user.

    private const string TEMPDIRPATH = @"C:\\mytempdir\";
    string tempDirUserPath = Path.Combine(TEMPDIRPATH, HttpContext.Current.User.Identity.Name);
    private void removeTempDirUser(string path)
    {
        try
        {
            Directory.Delete(path);
        }
        catch (Exception)
        {
            //an exception occured while deleting the directory.
        }
    }
找个人就嫁了吧 2024-09-08 12:14:41

使用缓存到期通知触发文件删除:

    private static void DeleteLater(string path)
    {
        HttpContext.Current.Cache.Add(path, path, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, 8, 0, 0), CacheItemPriority.NotRemovable, UploadedFileCacheCallback);
    }

    private static void UploadedFileCacheCallback(string key, object value, CacheItemRemovedReason reason)
    {
        var path = (string) value;
        Debug.WriteLine(string.Format("Deleting upladed file '{0}'", path));
        File.Delete(path);
    }

参考:MSDN |如何:从缓存中删除项目时通知应用程序

Use the cache expiry notification to trigger file deletion:

    private static void DeleteLater(string path)
    {
        HttpContext.Current.Cache.Add(path, path, null, Cache.NoAbsoluteExpiration, new TimeSpan(0, 8, 0, 0), CacheItemPriority.NotRemovable, UploadedFileCacheCallback);
    }

    private static void UploadedFileCacheCallback(string key, object value, CacheItemRemovedReason reason)
    {
        var path = (string) value;
        Debug.WriteLine(string.Format("Deleting upladed file '{0}'", path));
        File.Delete(path);
    }

ref: MSDN | How to: Notify an Application When an Item Is Removed from the Cache

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文