简体   繁体   English

ASP.NET计划删除临时文件

[英]ASP.NET Schedule deletion of temporary files

Question: I have an ASP.NET application which creates temporary PDF files (for the user to download). 问题:我有一个ASP.NET应用程序,可以创建临时PDF文件(供用户下载)。 Now, many users over many days can create many PDFs, which take much disk space. 现在,许多用户在很多天内都可以创建许多PDF,这需要占用大量磁盘空间。

What's the best way to schedule deletion of files older than 1 day/ 8 hours ? 安排删除超过1天/ 8小时的文件的最佳方法是什么? Preferably in the asp.net application itselfs... 最好是在asp.net应用程序本身...

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: 接下来,将以下清理代码添加到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. 新的涉及HttpRuntime.Cache并检查文件是否超过8小时。 I'll post it here if anyones interested. 如果有兴趣的话,我会在这里发布。 Here's my new global.asax.cs : 这是我的新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();
            }
        });
    }
}

Try using Path.GetTempPath() . 尝试使用Path.GetTempPath() It will give you a path to a windows temp folder. 它将为您提供一个Windows临时文件夹的路径。 Then it will be up to windows to clean up :) 然后它将由Windows清理:)

You can read more about the method here http://msdn.microsoft.com/en-us/library/system.io.path.gettemppath.aspx 你可以在这里阅读更多关于这个方法的信息http://msdn.microsoft.com/en-us/library/system.io.path.gettemppath.aspx

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. 最好的方法是创建一个批处理文件,由Windows任务调度程序以您想要的间隔调用它。

OR 要么

you can create a windows service with the class above 您可以使用上面的类创建一个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)

}

}

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. 请注意,您也可以在pageLoad中调用此类,它不会影响处理时间,因为处理是在另一个线程中。 Just remove the do-while and the Thread.Join(). 只需删除do-while和Thread.Join()。

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 | ref: MSDN | How to: Notify an Application When an Item Is Removed from the Cache 如何:从缓存中删除项目时通知应用程序

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. 然后创建一个删除旧文件夹的简单页面或httphandler。 You could call this page at intervals using a Windows schedule or other cron job. 您可以使用Windows计划或其他cron作业定期调用此页面。

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

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. 当会话结束时,应该在global.asax中引发Session_End事件。 Iterate all the files in the list and remove them. 迭代列表中的所有文件并将其删除。

    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. 上面的代码将删除临时目录中超过8小时前创建或修改的文件。

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. 正如Fredrik Johansson建议的那样,您可以在会话结束时删除用户创建的文件。 Better is to work with an extra directory based on the session ID of the user in you temp directory. 更好的方法是根据临时目录中用户的会话ID使用额外的目录。 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.
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM