简体   繁体   English

使用swift的临时文件路径

[英]Temporary file path using swift

How to get a unique temporary file path using Swift/Cocoa on OS X? 如何在OS X上使用Swift / Cocoa获取唯一的临时文件路径? Cocoa does not seem to provide a function for this, only NSTemporaryDirectory() which returns the path of the temporary directory. Cocoa似乎没有为此提供函数,只有NSTemporaryDirectory()返回临时目录的路径。 Using the BSD mktemp function requires a mutable C-string as argument. 使用BSD mktemp函数需要一个可变的C字符串作为参数。

Apple has been trying to move away from path-as-string and into NSURL . Apple一直在试图摆脱“as-string”和“ NSURL Here's one way: 这是一种方式:

Swift 3: 斯威夫特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: 斯威夫特2:

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

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

Here is a possible method to use mkstemp() from Swift 3 and later. 这是一种使用Swift 3及更高版本的mkstemp()的可能方法。 URL methods are used to convert between URL instances and C strings representing the file system path: 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)))
}

Older code for Swift 2: 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)))
}

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

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

Use a GUID (Globally Unique Identifier): 使用GUID(全球唯一标识符):

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

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

I like the idea of this article: NSTemporary​Directory - NSHipster 我喜欢这篇文章的想法: NSTemporary Directory - NSHipster

This uses the NSTemporaryDirectory() for the temporary folder and ProcessInfo.processInfo.globallyUniqueString to generate a unique string. 这使用临时文件夹的NSTemporaryDirectory()ProcessInfo.processInfo.globallyUniqueString来生成唯一的字符串。

Swift 4: 斯威夫特4:

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

Swift3 Swift3

I came here looking for something like boost::filesystem::unique_path() 我来这里寻找类似boost :: filesystem :: unique_path()的东西

So I made this extension to the URL class. 所以我对URL类做了这个扩展。

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

Usage: 用法:

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

FileManager extension in Swift to get a temporary file URL. Swift中的FileManager扩展来获取临时文件URL。 You can pass your own file name and extension, if needed. 如果需要,您可以传递自己的文件名和扩展名。

public extension FileManager {

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

Usage: 用法:

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

Although NSTemporaryDirectory() does indeed return a temporary directory path for the current user, the documentation includes the following caveat: 虽然NSTemporaryDirectory()确实为当前用户返回了临时目录路径, 但文档包含以下警告:

See the FileManager method url(for:in:appropriateFor:create:) for the preferred means of finding the correct temporary directory. 有关查找正确临时目录的首选方法,请参阅FileManager方法url(for:in:appropriateFor:create:)

Following that link, we are presented with the following: 在该链接之后,我们将看到以下内容:

You can use this method to create a new temporary directory. 您可以使用此方法创建新的临时目录。 To do so, specify FileManager.SearchPathDirectory.itemReplacementDirectory for the directory parameter, userDomainMask for the domain parameter, and a URL for the url parameter which determines the volume of the returned URL. 为此,请为directory参数指定FileManager.SearchPathDirectory.itemReplacementDirectory ,为domain参数指定userDomainMask ,并为url参数指定URL,以确定返回的URL的卷。

For example, the following code results in a new temporary directory with a path in the form of /private/var/folders/d0/h37cw8ns3h1bfr_2gnwq2yyc0000gn/T/TemporaryItems/Untitled/ : 例如,以下代码生成一个新的临时目录,其路径形式为/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. } 

(Note the the create parameter is ignored when creating a temporary directory.) (注意, create临时目录时会忽略create参数。)

So what exactly is the difference between these two approaches? 那么这两种方法究竟有什么区别呢? Well, here's what I get when I call the two different methods from the Swift REPL : 好吧,这是我从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)/"

It appears that NSTemporaryDirectory() will always return the temporary directory path for the current user whereas FileManager 's url(for:appropriateFor:create) will return a new temporary subdirectory each time it is called. 似乎NSTemporaryDirectory()将始终返回当前用户临时目录路径,而FileManagerurl(for:appropriateFor:create) NSTemporaryDirectory() url(for:appropriateFor:create)将在每次调用时返回一个新的临时子目录。 For example, here are the directories returned by consecutive calls to url(for:in:appropriateFor:create:) from the Swift REPL: 例如,以下是从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)/

And here are the directories returned by consecutive calls to the same method from a Swift Playground: 以下是从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)/

The NSHipster article on temporary files seems to suggest that the FileManager method url(for:in:appropriateFor:create:) is intended to be used when staging a file to be moved to a more permanent location (such as the user's desktop in the example above), but I don't see why it couldn't also be used to simply get a unique subdirectory that will automatically be removed when you're done with it and where you shouldn't have to worry about files getting accidentally clobbered by other processes writing to the same temporary directory. 关于临时文件NSHipster文章似乎暗示了在将文件移动到更永久的位置(例如示例中的用户桌面)时,将使用FileManager方法url(for:in:appropriateFor:create:) properFor url(for:in:appropriateFor:create:)上面),但我不明白为什么它也不能用于简单地获得一个独特的子目录,当你完成它时会自动被删除,你不必担心文件被意外破坏写入同一临时目录的其他进程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM