Swift 工具类:处理临时文件

Posted SwiftGG翻译组

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift 工具类:处理临时文件相关的知识,希望对你有一定的参考价值。

译者:小袋子;校对:numbbbbb,Yousanflics;定稿:Forelax

我经常需要在某些操作中创建临时文件,每次都很繁琐:必须有合适的临时目录,确保文件名是唯一的,最后还不能忘记在操作完成之后删除文件。

实际上,“创建”是一个错误的说法,因为创建工作通常是由我使用的 API 负责的 — 而我只是提供了一个指向目的位置的 URL。举个例子,假设你的应用提供了一个分享 PDF 文件的功能。你需要创建一个 UIGraphicsPDFRenderer对象来生成 PDF,然后调用 writePDF 方法并传入临时文件的 URL 生成 PDF 文件,最后在 ios 分享列表(share sheet)中分享它。

为了使这个操作更加简便,我最近写了一个简单的 Swift 工具类。你可以这样使用:

1、选择一个文件名来初始化 TemporaryFile
   let tmp = try TemporaryFile(creatingTempDirectoryForFilename: "report.pdf")
这样就新建了一个唯一的临时目录。正如我前面提到的,这是个空目录,TemporaryFile 并不会创建任何文件。更确切地说,它只是提供了一个可以安全创建很多文件的目录,并且不用担心命名冲突。

2、TemporaryFile有两个属性,directoryURL 是创建的临时目录 URL。fileURL 是目录中的文件 URL,即初始化时指定的文件名:

print(tmp.directoryURL.path)
///var/folders/v8/tft1q…/T/-8DC6DD131DC1
print(tmp.fileURL.path)
///var/folders/v8/tft1q…/T/-8DC6DD131DC1/report.pdf

再次强调一下,该 URL 对应的文件暂时还不存在——你必须自己创建文件,通常来说可以把 URL 传入其他 API 来生成文件:

let renderer = UIGraphicsPDFRenderer(...)
try renderer.writePDF(to: tmp.fileURL) { context in
   // 编写代码
   // ...
}

你可以在目录中创建不同名字的文件,但是 TemporaryFile 类型目前只能用来存储单一的文件 URL。如果能够支持多文件 URL 的存储,那就会更好用了。

3、创建文件后,TemporaryFile 的值被应用中使用该文件的对象所持有(例如,创建文件函数的调用者)。当该对象完成后并且不再需要该文件时,可以调用DeleTeDirectory方法删除临时目录,包括其中的所有文件:

// 例如将 temp 文件传给 UIActivityController 用以分享
// ...
// 当你完成后, 调用 deleteDirectory
try tmp.deleteDirectory()

我曾考虑到让这个步骤自动化 — 你可以创建 TemporaryFile 类,然后在 deinitializer 中调用 deleteDirectory。最后我放弃了,因为这种行为可能让类型的使用者感到困惑。如果能够添加一个初始化标志位来配置删除行为就好了。

代码

以下是完整代码 (Swift 4.0):

import Foundation
/// 临时目录中临时文件的包装(Wrapper)。目录是为文件而特别创建的,因此不再需要文件时,可以安全地删除该文件。
///
/// 在你不再需要文件时,调用 `deleteDirectory`
struct TemporaryFile {
   let directoryURL: URL
   let fileURL: URL
   /// 删除临时目录和其中的所有文件。
   let deleteDirectory: () throws -> Void
   /// 使用唯一的名字来创建临时目录,并且使用 `fileURL` 目录中名为 `filename` 的文件来初始化接收者。
   ///
   /// - 注意: 这里不会创建文件!
   init(creatingTempDirectoryForFilename filename: String) throws {
       let (directory, deleteDirectory) = try FileManager.default
           .urlForUniqueTemporaryDirectory()
       self.directoryURL = directory
       self.fileURL = directory.appendingPathComponent(filename)
       self.deleteDirectory = deleteDirectory
   }
}
extension FileManager {
   /// 创建一个有唯一名字的临时目录并返回 URL。
   ///
   /// - 返回:目录 URL 的 tuple 以及删除函数。
   ///   完成后调用函数删除目录。
   ///
   /// - 注意: 在应用退出后,不应该存在依赖的临时目录。
   func urlForUniqueTemporaryDirectory(preferredName: String? = nil) throws
       -> (url: URL, deleteDirectory: () throws -> Void)
   
{
       let basename = preferredName ?? UUID().uuidString
       var counter = 0
       var createdSubdirectory: URL? = nil
       repeat {
           do {
               let subdirName = counter == 0 ? basename : "\(basename)-\(counter)"
               let subdirectory = temporaryDirectory
                   .appendingPathComponent(subdirName, isDirectory: true)
               try createDirectory(at: subdirectory, withIntermediateDirectories: false)
               createdSubdirectory
= subdirectory
           } catch CocoaError.fileWriteFileExists {
               // 捕捉到文件已存在的错误,并使用其他名字重试。
               // 其他错误传播到调用方。
               counter += 1
           }
       } while createdSubdirectory == nil
       let directory = createdSubdirectory!
       let deleteDirectory: () throws -> Void = {
           try self.removeItem(at: directory)
       }
       return (directory, deleteDirectory)
   }
}

本文由 SwiftGG 翻译组翻译,已经获得作者翻译授权,最新文章请访问 http://swift.gg。


以上是关于Swift 工具类:处理临时文件的主要内容,如果未能解决你的问题,请参考以下文章

solr分布式索引实战分片配置读取:工具类configUtil.java,读取配置代码片段,配置实例

如何使用 Swift 使用此代码片段为 iOS 应用程序初始化 SDK?

elasticsearch代码片段,及工具类SearchEsUtil.java

获取一个临时文件和对中文文件名字进行编码的工具类

swift常用代码片段

swift 代码片段