【问题标题】:ASP.NET Schedule deletion of temporary filesASP.NET 计划删除临时文件
【发布时间】:2011-02-19 10:53:30
【问题描述】:

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

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

【问题讨论】:

    标签: c# asp.net vb.net scheduled-tasks temporary-files


    【解决方案1】:

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

        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 | How to: Notify an Application When an Item Is Removed from the Cache

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 我认为在临时目录或 ASP.NET 用户具有写入权限的另一个目录中创建基于用户会话 ID 的目录更容易。当会话结束时,只需根据会话 ID 删除用户的整个目录。
      • 我去 sessionid 文件夹。
      • 如果会话保存在内存中并且没有持久化到持久会话存储中,那么当你有一个应用程序回收时就有可能泄漏文件。你会丢失你的内存列表。
      【解决方案3】:

      最好的方法是创建一个批处理文件,由 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()。

      【讨论】:

      • 这些正是我试图避免的事情。首先,windows scheduler 从来都不是一个好主意(在非常许可锁定的环境中,例如在我们的客户那里,它永远不会工作),第二个 windows 服务需要安装程序,我曾经做过一次,老实说,收集的经验这正是我不想再做一次的原因。
      • 如果您不熟悉 windows 安装程序服务,您可以在 pageLoad no 处调用 CleanUpBot 类?在第一行放这样的东西... CleanUp();在这个方法中.... private bool cleanUp() { try { var lastCleanUp = DateTime.Parse(Application["LastCleanUp"].ToString()); } 捕捉(异常){ 应用程序[“LastCleanUp”] = DateTime.Now; } 最后 { new CleanUpBot().Run(lastCleanUp); } }
      【解决方案4】:
          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.
              }
          }
      

      【讨论】:

        【解决方案5】:

        我有点同意 dirk 在回答中所说的话。

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

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

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

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            【解决方案7】:

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

            【讨论】:

            • 不必以当前日期和时间命名文件。文件名是 guid.tostring + ".pdf"。您可以从文件属性中读取文件创建/修改日期。是的,它们都在同一个文件夹中。
            【解决方案8】:

            尝试使用Path.GetTempPath()。它会给你一个 Windows 临时文件夹的路径。然后由windows来清理:)

            你可以在这里http://msdn.microsoft.com/en-us/library/system.io.path.gettemppath.aspx阅读更多关于该方法的信息

            【讨论】:

            • 您是否需要授予 asp.net 工作进程/应用程序池写入 temp 的权限?
            • @James:是的,绝对是(Vista+)。此外,ASP.NET 用户需要对 temp 的读取权限、下载文件和文件枚举权限才能获取目录中的文件列表。
            • PS:Windows 很可能只会在重启时清理临时文件夹。如果服务器不经常崩溃/更新,我希望它不会,那是不够的。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2022-01-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多