使用swift的临时文件路径

tml*_*len 18 macos cocoa swift

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

Cod*_*ent 33

苹果公司一直在努力摆脱路径的束缚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])
Run Code Online (Sandbox Code Playgroud)

斯威夫特2:

let directory = NSTemporaryDirectory()
let fileName = NSUUID().UUIDString

let fullURL = NSURL.fileURLWithPathComponents([directory, fileName])
Run Code Online (Sandbox Code Playgroud)


Mar*_*n R 22

这里是使用一个可能的方法mkstemp()夫特3和更高版本.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)))
}
Run Code Online (Sandbox Code Playgroud)

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)))
}
Run Code Online (Sandbox Code Playgroud)

  • @tmlen:是的,否则你有文件描述符泄漏.或者,使用`let fh = NSFileHandle(fileDescriptor:fd,closeOnDealloc:true)`创建一个文件句柄来传输所有权.解除分配文件句柄后,将关闭fd. (3认同)
  • 好的。我认为您应该使用 `mkstemp` 作为示例而不是 `mktemp`,因为它通常更安全。 (2认同)

Chr*_*ick 11

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

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

通过该链接,我们将看到以下内容:

您可以使用此方法创建新的临时目录。要做到这一点,指定FileManager.SearchPathDirectory.itemReplacementDirectorydirectory参数,userDomainMaskdomain参数,并为一个URLurl它确定了返回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.
}
Run Code Online (Sandbox Code Playgroud)

(注意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)/"
Run Code Online (Sandbox Code Playgroud)

似乎NSTemporaryDirectory()总是返回当前用户临时目录路径,而FileManager's每次调用时url(for:appropriateFor:create)都会返回一个新的临时子目录。例如,以下是url(for:in:appropriateFor:create:)从 Swift REPL连续调用返回的目录:

  • 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 文章似乎表明该FileManager方法url(for:in:appropriateFor:create:)旨在将文件暂存到更永久的位置(例如上面示例中的用户桌面)时使用,但我不明白为什么它不能' 也不能用于简单地获取一个唯一的子目录,当您完成它时将自动删除该子目录,并且您不必担心文件会被写入同一临时目录的其他进程意外破坏。

  • 感谢您的分析。像这样的答案使得SO*成为获得答案的地方。 (2认同)

mz2*_*mz2 6

一款受UUID Swift 2回答启发的Swift 3单线程:

let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString)
Run Code Online (Sandbox Code Playgroud)


boh*_*rna 5

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

public extension FileManager {

    func temporaryFileURL(fileName: String = UUID().uuidString) -> URL? {
        return URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent(fileName)
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

let tempURL = FileManager.default.temporaryFileURL()
let tempJPG = FileManager.default.temporaryFileURL(fileName: "temp.jpg")
Run Code Online (Sandbox Code Playgroud)