【问题标题】:Temporary file path using swift使用swift的临时文件路径
【发布时间】:2015-09-18 17:09:17
【问题描述】:

如何在 OS X 上使用 Swift/Cocoa 获取唯一的临时文件路径? Cocoa 似乎没有为此提供函数,只有 NSTemporaryDirectory() 返回临时目录的路径。使用 BSD mktemp 函数需要一个可变的 C 字符串作为参数。

【问题讨论】:

    标签: macos swift cocoa


    【解决方案1】:

    Apple 一直在尝试从 path-as-string 转移到 NSURL。这是一种方法:

    斯威夫特 3:

    let directory = NSTemporaryDirectory()
    let fileName = NSUUID().uuidString
    
    // This returns a URL? even though it is an NSURL class method
    let fullURL = NSURL.fileURL(withPathComponents: [directory, fileName])
    

    斯威夫特 2:

    let directory = NSTemporaryDirectory()
    let fileName = NSUUID().UUIDString
    
    let fullURL = NSURL.fileURLWithPathComponents([directory, fileName])
    

    【讨论】:

      【解决方案2】:

      这是在 Swift 3 及更高版本中使用mkstemp() 的可能方法。 URL 方法 用于在 URL 实例和表示文件系统路径的 C 字符串之间进行转换:

      // The template string:
      let template = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("file.XXXXXX") as NSURL
      
      // Fill buffer with a C string representing the local file system path. 
      var buffer = [Int8](repeating: 0, count: Int(PATH_MAX))
      template.getFileSystemRepresentation(&buffer, maxLength: buffer.count)
      
      // Create unique file name (and open file):
      let fd = mkstemp(&buffer)
      if fd != -1 {
      
          // Create URL from file system string:
          let url = URL(fileURLWithFileSystemRepresentation: buffer, isDirectory: false, relativeTo: nil)
          print(url.path)
      
      } else {
          print("Error: " + String(cString: strerror(errno)))
      }
      

      Swift 2 的旧代码:

      // The template string:
      let template = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent("file.XXXXXX")
      
      // Fill buffer with a C string representing the local file system path. 
      var buffer = [Int8](count: Int(PATH_MAX), repeatedValue: 0)
      template.getFileSystemRepresentation(&buffer, maxLength: buffer.count)
      
      // Create unique file name (and open file):
      let fd = mkstemp(&buffer)
      if fd != -1 {
      
          // Create URL from file system string:
          let url = NSURL(fileURLWithFileSystemRepresentation: buffer, isDirectory: false, relativeToURL: nil)
          print(url.path!)
      
      } else {
          print("Error: " + String(strerror(errno)))
      }
      

      【讨论】:

      • 不错。我认为您应该使用mkstemp 作为示例而不是mktemp,因为它通常更安全。
      • 还需要close文件描述符fd from mkstemp?
      • @tmlen:是的,否则你有文件描述符泄漏。或者,使用let fh = NSFileHandle(fileDescriptor: fd, closeOnDealloc: true) 创建文件句柄以转移所有权。当文件句柄被释放时,fd 将被关闭。
      【解决方案3】:

      虽然NSTemporaryDirectory() 确实为当前用户返回了一个临时目录路径,但the documentation 包含以下警告:

      请参阅FileManager 方法url(for:in:appropriateFor:create:),了解查找正确临时目录的首选方法。

      在该链接之后,我们会看到以下内容:

      您可以使用此方法创建一个新的临时目录。为此,请为directory 参数指定FileManager.SearchPathDirectory.itemReplacementDirectory,为domain 参数指定userDomainMask,并为url 参数指定一个URL,该参数确定返回的URL 的数量。

      例如,以下代码生成一个新的临时目录,其路径为/private/var/folders/d0/h37cw8ns3h1bfr_2gnwq2yyc0000gn/T/TemporaryItems/Untitled/

      let desktop = URL(fileURLWithPath: "/Users/jappleseed/Desktop/")
      
      do {
         let temporaryDirectory = try FileManager.default.url(
             for: .itemReplacementDirectory,
             in: .userDomainMask,
             appropriateFor: desktop,
             create: true
         )
      
         print(temporaryDirectory)
      } catch {
         // Handle the error.
      }
      

      (注意create参数在创建临时目录时会被忽略。)

      那么这两种方法到底有什么区别呢?好吧,这就是我从Swift REPL 调用两种不同方法时得到的结果:

      1> import Foundation
      
      2> NSTemporaryDirectory() 
      $R0: String = "/var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/"
      
      3> let desktop = URL(fileURLWithPath: "/Users/chris/Desktop/") 
      desktop: URL = "file:///Users/chris/Desktop/"
      
      4> let temporaryDirectory = try FileManager.default.url( 
      5.     for: .itemReplacementDirectory, 
      6.     in: .userDomainMask, 
      7.     appropriateFor: desktop, 
      8.     create: true 
      9. )
      temporaryDirectory: URL = "file:///var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20repl_swift)/"
      

      似乎NSTemporaryDirectory() 将始终为当前用户返回 临时目录路径,而FileManagerurl(for:appropriateFor:create) 将返回一个 临时子目录每个它被称为时间。例如,以下是从 Swift REPL 连续调用 url(for:in:appropriateFor:create:) 返回的目录:

      • file:///var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20repl_swift)/
      • file:///var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20repl_swift%202)/
      • file:///var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20repl_swift%203)/

      以下是从 Swift Playground 连续调用同一方法返回的目录:

      • file:///var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20Xcode)/
      • file:///var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20Xcode%202)/
      • file:///var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20Xcode%203)/

      NSHipster article on temporary files 似乎表明FileManager 方法url(for:in:appropriateFor:create:) 旨在用于将文件移动到更永久的位置(例如上面示例中的用户桌面),但我不明白为什么它也不能用于简单地获取一个唯一的子目录,当你完成它时会自动删除它,你不应该担心文件会被其他进程意外破坏写入相同的临时目录。

      【讨论】:

      • 感谢您的分析。像这样的答案使 SO 成为获得答案的地方。
      • @mojuba 很高兴您发现它有帮助! ☺️
      【解决方案4】:

      UUID based Swift 2 answer 启发的 Swift 3 单线:

      let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString)
      

      【讨论】:

        【解决方案5】:

        Swift 中的 FileManager 扩展来获取临时文件 URL。如果需要,您可以传递自己的文件名和扩展名。

        public extension FileManager {
        
            func temporaryFileURL(fileName: String = UUID().uuidString) -> URL? {
                return URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent(fileName)
            }
        }
        

        用法:

        let tempURL = FileManager.default.temporaryFileURL()
        let tempJPG = FileManager.default.temporaryFileURL(fileName: "temp.jpg")
        

        【讨论】:

          【解决方案6】:

          使用 GUID(全局唯一标识符):

          let directory :NSString = "directory"
          let randomName = NSProcessInfo().globallyUniqueString
          let path = directory.stringByAppendingPathComponent(randomName)
          

          目录/3B635E49-813A-4324-B4B8-56279B42BEAB-36687-0002D962615DAE5F

          【讨论】:

            【解决方案7】:

            我喜欢这篇文章的想法:NSTemporary​Directory - NSHipster

            这将NSTemporaryDirectory() 用于临时文件夹并使用ProcessInfo.processInfo.globallyUniqueString 生成唯一字符串。

            斯威夫特 4:

            func uniqueTempFolderURL() -> URL
            {
                let folderName = ProcessInfo.processInfo.globallyUniqueString
                return URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent(folderName)
            }
            

            【讨论】:

              【解决方案8】:

              Swift3

              我来这里是为了寻找 boost::filesystem::unique_path() 之类的东西

              所以我对 URL 类做了这个扩展。

              extension URL {
                  func appendingUniquePathComponent(pathExtension: String? = nil) -> URL {
                      var pathComponent = UUID().uuidString
                      if let pathExtension = pathExtension {
                          pathComponent += ".\(pathExtension)"
                      }
                      return appendingPathComponent(pathComponent)
                  }
              }
              

              用法:

              let url0 = URL(fileURLWithPath: "/tmp/some/dir")
              let url1 = url0.appendingUniquePathComponent(pathExtension: "jpg")
              print("url1: \(url1)")
              // url1: file:///tmp/some/dir/936324FF-EEDB-410E-AD09-E24D5EB4A24F.jpg
              

              【讨论】:

              • 在这里添加NSTemporaryDirectory() 这是最好的答案
              猜你喜欢
              • 2012-04-11
              • 1970-01-01
              • 1970-01-01
              • 2019-12-24
              • 2018-01-21
              • 1970-01-01
              • 1970-01-01
              • 2012-08-19
              • 2013-10-08
              相关资源
              最近更新 更多