使用swift的临时文件路径

nom7f22z  于 2023-04-28  发布在  Swift
关注(0)|答案(9)|浏览(138)

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

hfsqlsce

hfsqlsce1#

苹果一直在尝试从path-as-string转向NSURL。这里有一个方法:

Swift 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])
ki0zmccv

ki0zmccv2#

下面是在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)))
}
piah890a

piah890a3#

虽然NSTemporaryDirectory()确实返回当前用户的临时目录路径,但the documentation包含以下警告:
请参阅FileManager方法url(for:in:appropriateFor:create:),了解查找正确临时目录的首选方法。
在该链接之后,我们将看到以下内容:
可以使用此方法创建新的临时目录。为此,请为directory参数指定FileManager.SearchPathDirectory.itemReplacementDirectory,为domain参数指定userDomainMask,为url参数指定一个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.
}

(Note创建临时目录时忽略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:)旨在暂存要移动到更永久位置的文件时使用(例如上述示例中的用户桌面)但我不明白为什么它不能也被用来简单地获得一个独特的子目录,将自动删除时,你做了它和你应该'不必担心文件会被其他进程写入同一个临时目录而意外地损坏。

4dbbbstv

4dbbbstv4#

Swift 3的一个灵感来自UUID based Swift 2 answer

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

fwzugrvs5#

在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")
pxyaymoc

pxyaymoc6#

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

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

目录/3B 635 E49 - 813 A-4324-B4 B8 - 56279 B42 BEAB-36687- 0002 D962615 DAE 5 F

xpcnnkqh

xpcnnkqh7#

我喜欢这篇文章的想法:NSTemporary​Directory - NSHipster
这将使用NSTemporaryDirectory()作为临时文件夹,并使用ProcessInfo.processInfo.globallyUniqueString生成唯一字符串。
Swift 4:

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

py49o6xq8#

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
2nbm6dog

2nbm6dog9#

只是我的两分钱,比较iOS和MacOS(沙盒)
验证码:

let tmp_path1 = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first
let tmp_path2 = NSTemporaryDirectory()

print("\n--\n", tmp_path1!, "\n", tmp_path2)

我们得到:

> -- MacOs /Users/ingconti/Library/Containers/com.ingconti.ZipArchiveDebugAppMacOs/Data/Library/Caches
> /var/folders/40/8w6s0bsn4d55d9cjf16sjz440000gp/T/com.ingconti.ZipArchiveDebugAppMacOs/
> 
> 
> iOS simulator 
> /Users/ingconti/Library/Developer/CoreSimulator/Devices/3AC9CBFC-5535-4213-9394-523DA82B4637/data/Containers/Data/Application/82EFDDFA-D541-4791-B76F-D754116F43C9/Library/Caches
> /Users/ingconti/Library/Developer/CoreSimulator/Devices/3AC9CBFC-5535-4213-9394-523DA82B4637/data/Containers/Data/Application/82EFDDFA-D541-4791-B76F-D754116F43C9/tmp/
> 
> iOS 
> /var/mobile/Containers/Data/Application/9F9EA2D1-7CCD-48B3-85C1-957FDF0D1925/Library/Caches
> /private/var/mobile/Containers/Data/Application/9F9EA2D1-7CCD-48B3-85C1-957FDF0D1925/tmp/
> 
> or something similar on Your machine

指出:最好让iOS / macOS自己使用并回收空间,所以我真的更喜欢坚持使用内置解决方案。
如果临时的意思是“不需要时删除”,最好还是让苹果这样做。如果你开始建立自己的逻辑:a)你必须记住手动申请空间b)苹果APIS有更好的机会保持稳定,你的解决方案手工构建一个文件夹可以停止工作(它'发生了什么事,一个macOS应用程序,如果我的沙盒出来时)
如果你需要广告独特的名字,si非常不同,在这些情况下,你可以使用建议的解决方案添加例如:

let uuid = UUID().uuidString

相关问题