文章
· 7 hr 前 阅读大约需 2 分钟

临时文件与单例:自我清理

我曾多次遇到一种模式,即我需要使用临时文件/文件夹,并在稍后的某个时候将其清理掉。

在这种情况下,自然是遵循"Robust Error Handling and Cleanup in ObjectScript "中的模式,使用 try/catch/pseudo-finally 或注册对象来管理析构函数中的清理工作。%Stream.File*也有一个 "RemoveOnClose "属性,您可以对其进行设置,但要小心使用,因为您可能会不小心删除一个重要文件,而且这个标志会在调用%Save()时被重置,因此您需要在重置后将其设回 1。

不过,有一个棘手的情况——假设你需要临时文件在外部堆栈级别中继续存在。例如:

ClassMethod MethodA()
{
    Do ..MethodB(.filename)
    // Do something else with the filename
}

ClassMethod MethodB(Output filename)
{
    // Create a temp file and set filename to the file's name
    Set filename = ##class(%Library.File).TempFilename()
    
    //... and probably do some other stuff
}

你总是可以传递 RemoveOnClose 设置为 1 的 %Stream.File* 对象,但我们在这里讨论的其实只是临时文件。

这就是 "单例(Singleton)"概念的由来。我们在IPM %IPM.General.Singleton 中有一个基本实现,你可以扩展它以满足不同的使用情况。一般行为和使用模式如下

  • 在较高的堆栈层中,调用该类的 %Get(),可以获得一个实例,在较低的堆栈层中调用 %Get() 也可以获得该实例。
  • 当对象在使用它的最高堆栈层中退出作用域时,将运行清理代码。

这比 % 变量更好一些,因为你不需要去检查它是否被定义,而且它还能通过一些深层对象技巧,在较低的堆栈层级上存活下来。

关于临时文件,IPM 也有一个临时文件管理器单例。解决这个问题的方法是:

ClassMethod MethodA()
{
    Set tempFileManager = ##class(%IPM.Utils.TempFileManager).%Get()
    Do ..MethodB(.filename)
    // Do something else with the filename
    // The temp file is cleaned up automatically when tempFileManager goes out of scope
}

ClassMethod MethodB(Output filename)
{
    Set tempFileManager = ##class(%IPM.Utils.TempFileManager).%Get()
    // Create a temp file and set filename to the file's name
    Set filename = tempFileManager.GetTempFileName(".md")
    
    //... and probably do some other stuff
}
讨论 (0)1
登录或注册以继续