【问题标题】:How do I create a temporary file with Cocoa?如何使用 Cocoa 创建临时文件?
【发布时间】:2010-09-17 23:11:30
【问题描述】:

几年前,当我使用 C# 时,我可以轻松地创建一个临时文件并使用此函数获取其名称:

Path.GetTempFileName();

此函数将在临时目录中创建一个具有唯一名称的文件,并返回该文件的完整路径。

在 Cocoa API 中,我能找到的最接近的是:

NSTemporaryDirectory

我是否遗漏了一些明显的东西,或者没有内置的方法可以做到这一点?

【问题讨论】:

  • 使用该 C# API 时要注意:它的命名空间只有 65k 个文件,一旦用完就会抛出异常。这在我们的生产环境中发生过 - 并非所有程序都会认真清理它们的临时文件。

标签: objective-c cocoa file-io


【解决方案1】:

一个安全的方法是使用mkstemp(3)

【讨论】:

  • 不完全是“with Cocoa”...更像是“with POSIX”
【解决方案2】:

[注意:这适用于 iPhone SDK,而不是 Mac OS SDK]

据我所知,SDK 中不存在这些功能(与标准 Mac OS X 10.5 文件相比,unistd.h 文件大幅缩减)。我会使用类似的东西:

[NSTemporaryDirectory() stringByAppendingPathComponent: [NSString stringWithFormat: @"%.0f.%@", [NSDate timeIntervalSinceReferenceDate] * 1000.0, @"txt"]];

不是最漂亮,但实用

【讨论】:

  • 这与 mktemp(3) 具有相同的竞争条件:将文件名的创建与临时文件的创建分开会打开一个漏洞窗口。按照 Graham Lee 的建议使用 mkstemp(3)。
  • 对不起,我在 iPhone 模式下;原始海报建议的 mkstemp(3) 很好,但它不适用于 iPhone。
  • 在 iPhone 上,每个应用程序都有自己的文件系统子树。 NSTemporaryDirectory() 在应用程序包中返回一些东西。您仍然与自己竞争,并与其他任何对您的 tmp 目录具有写入权限的东西竞争,但我认为这只是特权进程。
  • @Ken 提问者说他​​们在 iPhone 上的哪个位置?
  • 当从多个线程“同时”调用时会失败。我不知道该方法的粒度有多细(文档没有详细说明),但对我来说,我的 NSOperations 被调用得太快并且文件的名称相同。我的解决方案是将 NSOperations 地址添加到文件名中,因为它们肯定会有所不同: [NSString stringWithFormat: @"%d_%.0f.%@", self, [NSDate timeInterv...
【解决方案3】:

Apple 提供了一种访问临时目录和为临时文件创建唯一名称的绝佳方式。

- (NSString *)pathForTemporaryFileWithPrefix:(NSString *)prefix
{
    NSString *  result;
    CFUUIDRef   uuid;
    CFStringRef uuidStr;

    uuid = CFUUIDCreate(NULL);
    assert(uuid != NULL);

    uuidStr = CFUUIDCreateString(NULL, uuid);
    assert(uuidStr != NULL);

    result = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@-%@", prefix, uuidStr]];
    assert(result != nil);

    CFRelease(uuidStr);
    CFRelease(uuid);

    return result;
}

LINK :::: http://developer.apple.com/library/ios/#samplecode/SimpleURLConnections/Introduction/Intro.html#//apple_ref/doc/uid/DTS40009245 见文件 :::AppDelegate.m

【讨论】:

    【解决方案4】:

    我通过 NSFileManager 上的类别创建了一个纯 Cocoa 解决方案,该类别使用 NSTemporary() 和全球唯一 ID 的组合。

    这里是头文件:

    @interface NSFileManager (TemporaryDirectory)
    
    -(NSString *) createTemporaryDirectory;
    
    @end
    

    以及实现文件:

    @implementation NSFileManager (TemporaryDirectory)
    
    -(NSString *) createTemporaryDirectory {
     // Create a unique directory in the system temporary directory
     NSString *guid = [[NSProcessInfo processInfo] globallyUniqueString];
     NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:guid];
     if (![self createDirectoryAtPath:path withIntermediateDirectories:NO attributes:nil error:nil]) {
      return nil;
     }
     return path;
    }
    
    @end
    

    这会创建一个临时目录,但可以很容易地调整为使用createFileAtPath:contents:attributes: 而不是createDirectoryAtPath: 来创建文件。

    【讨论】:

      【解决方案5】:

      如果面向 iOS 6.0 或 Mac OS X 10.8 或更高版本:

      NSString *tempFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
      

      【讨论】:

        【解决方案6】:

        Swift 5 和 Swift 4.2

        import Foundation
        
        func pathForTemporaryFile(with prefix: String) -> URL {
            let uuid = UUID().uuidString
            let pathComponent = "\(prefix)-\(uuid)"
            var tempPath = URL(fileURLWithPath: NSTemporaryDirectory())
            tempPath.appendPathComponent(pathComponent)
            return tempPath
        }
        
        let url = pathForTemporaryFile(with: "blah")
        print(url)
        // file:///var/folders/42/fg3l5j123z6668cgt81dhks80000gn/T/johndoe.KillerApp/blah-E1DCE512-AC4B-4EAB-8838-547C0502E264
        

        或者 Ssswift 的 oneliner:

        let prefix = "blah"
        let url2 = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("\(prefix)-\(UUID())")
        print(url2)
        

        【讨论】:

        • 此代码不再有效,但等效版本更简单:URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("\(prefix)-\(UUID())")
        • 感谢@Ssswift 以更详细的方式更新了答案。
        【解决方案7】:

        您可以使用mktemp 来获取临时文件名。

        【讨论】:

        • mktemp(3) 中存在竞态条件,最好使用 mkstemp(3)。
        【解决方案8】:

        执行此操作的现代方法是FileManager's url(for:in:appropriateFor:create:)

        使用此方法,您可以指定SearchPathDirectory 来准确说明您想要什么样的临时目录。例如,.cachesDirectory 将在运行之间保持(尽可能)并保存在用户的库中,而.itemReplacementDirectory 将与目标文件位于同一卷上。

        【讨论】:

          【解决方案9】:

          不要使用像 NSTemporaryDirectory 这样的遗留 API,而是从 FileManager 获取正确的 URL

          let tmpURL = FileManager
              .default
              .temporaryDirectory
              .appendingPathComponent(UUID().uuidString)
          

          您仍然需要创建目录。

          【讨论】:

            【解决方案10】:

            您可以使用NSTaskuuidgen 来获取唯一的文件名,然后将其附加到来自NSTemporaryDirectory() 的字符串中。这不适用于 Cocoa Touch。虽然有点啰嗦。

            【讨论】:

            【解决方案11】:

            添加到@Philipp:

            - (NSString *)createTemporaryFile:(NSData *)contents {
                // Create a unique file in the system temporary directory
                NSString *guid = [[NSProcessInfo processInfo] globallyUniqueString];
                NSString *path = [NSTemporaryDirectory() stringByAppendingPathComponent:guid];
                if(![self createFileAtPath:path contents:contents attributes:nil]) {
                    return nil;
                }
                return path;
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-05-16
              • 1970-01-01
              • 1970-01-01
              • 2014-09-26
              • 1970-01-01
              • 2011-05-19
              • 2010-10-04
              • 1970-01-01
              相关资源
              最近更新 更多