如何在OS X上使用Swift / Cocoa获取唯一的临时文件路径?
Cocoa似乎没有为此提供函数,只有NSTemporaryDirectory()
返回临时目录的路径。使用BSD mktemp
函数需要一个可变的C字符串作为参数。
答案 0 :(得分:29)
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])
Swift 2:
let directory = NSTemporaryDirectory()
let fileName = NSUUID().UUIDString
let fullURL = NSURL.fileURLWithPathComponents([directory, fileName])
答案 1 :(得分:20)
以下是从 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)))
}
答案 2 :(得分:5)
受UUID based Swift 2 answer启发的Swift 3单线游戏:
let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString)
答案 3 :(得分:4)
使用GUID(全球唯一标识符):
let directory :NSString = "directory"
let randomName = NSProcessInfo().globallyUniqueString
let path = directory.stringByAppendingPathComponent(randomName)
目录/ 3B635E49-813A-4324-B4B8-56279B42BEAB-36687-0002D962615DAE5F
答案 4 :(得分:3)
我喜欢这篇文章的想法:NSTemporaryDirectory - NSHipster
这会使用NSTemporaryDirectory()
作为临时文件夹,使用ProcessInfo.processInfo.globallyUniqueString
生成唯一字符串。
func uniqueTempFolderURL() -> URL
{
let folderName = ProcessInfo.processInfo.globallyUniqueString
return URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent(folderName)
}
答案 5 :(得分:1)
我来这里寻找像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
答案 6 :(得分:1)
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")
答案 7 :(得分:0)
尽管NSTemporaryDirectory()
确实为当前用户返回了一个临时目录路径,但the documentation包括以下警告:
有关查找正确的临时目录的首选方法,请参见
FileManager
方法url(for:in:appropriateFor:create:)
。
通过该链接,我们看到以下内容:
您可以使用此方法创建一个新的临时目录。为此,请为
directory
参数指定FileManager.SearchPathDirectory.itemReplacementDirectory
,为domain
参数指定userDomainMask
,并为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()
将始终为当前用户返回 临时目录路径,而FileManager
的{{1}}将返回 new < / em>每次调用临时子目录。例如,以下是从Swift REPL连续调用url(for:appropriateFor:create)
返回的目录:
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)/
这是从Swift Playground连续调用同一方法返回的目录:
file:///var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20repl_swift%203)/
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)/
NSHipster article on temporary files似乎建议将file:///var/folders/n_/0_9q7d2d1ls5v9kx599y_tj00000gn/T/TemporaryItems/(A%20Document%20Being%20Saved%20By%20Xcode%203)/
方法FileManager
用于暂存文件以将文件移至更永久的位置(例如用户桌面)中。上面的示例),但是我不明白为什么不能同时使用它来简单地获得一个唯一的子目录,该子目录在使用完该子目录后也将自动删除,并且您不必担心文件意外被破坏通过其他过程写入同一临时目录。