Как создать временный файл с Cocoa?

Несколько лет назад, когда я работал с C#, я мог легко создать временный файл и получить его имя с помощью этой функции:

Path.GetTempFileName();

Эта функция создаст файл с уникальным именем во временном каталоге и вернет полный путь к этому файлу.

В Cocoa API самое близкое, что я могу найти, это:

NSTemporaryDirectory

Я пропустил что-то очевидное или нет встроенного способа сделать это?


person lfalin    schedule 19.10.2008    source источник
comment
Предостережение при использовании этого C# API: он имеет пространство имен всего 65 тыс. файлов и выдает исключение, как только оно будет исчерпано. У нас такое случалось в продакшне — не все программы усердно очищают свои временные файлы.   -  person fzwo    schedule 25.12.2016


Ответы (11)



[Примечание: это относится к iPhone SDK, а не к Mac OS SDK]

Насколько я могу судить, этих функций нет в SDK (файл unistd.h значительно урезан по сравнению со стандартным файлом Mac OS X 10.5). Я бы использовал что-то вроде:

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

Не самый красивый, но функциональный

person Ben Gottlieb    schedule 19.10.2008
comment
Это имеет то же состояние гонки, что и mktemp(3): разделение создания имени файла и создания временного файла открывает окно уязвимости. Используйте mkstemp(3), как предлагает Грэм Ли. - person Chris Hanson; 19.10.2008
comment
Извините, я был в режиме iPhone; mkstemp(3), предложенный оригинальным плакатом, хорош, но не будет работать на iPhone. - person Ben Gottlieb; 19.10.2008
comment
На iPhone каждое приложение имеет собственное поддерево файловой системы. NSTemporaryDirectory() возвращает что-то в комплекте приложения. Вы по-прежнему соревнуетесь с собой и со всем остальным, у кого есть разрешение на запись в ваш каталог tmp, но я думаю, что это только привилегированные процессы. - person Ken; 19.10.2008
comment
@ Кен, где спрашивающий сказал, что они были на iPhone? - person ; 20.10.2008
comment
Нигде, кроме как в этом ответе, который мы комментируем. :-) Я отвечал на вышесказанное. Отсутствие mkstemp на телефоне не такая большая проблема, как на Mac. - person Ken; 20.10.2008
comment
Это не удается при одновременном вызове из более чем одного потока. Я не знаю, насколько точен метод (в документации об этом ничего не сказано), но у меня случилось так, что мои NSOperations вызывались слишком быстро, и файлы получали одинаковые имена. Мое решение состояло в том, чтобы добавить адрес NSOperations к имени файла, поскольку они обязательно будут отличаться: [NSString stringWithFormat: @%d_%.0f.%@, self, [NSDate timeInterv... - person Christian Beer; 27.01.2011
comment
..или просто используйте NSUUID, т.е. NSString *uuidString = [[NSUUID UUID] UUIDString]; - person Jay; 24.03.2017

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;
}

ССЫЛКА :::: http://developer.apple.com/library/ios/#samplecode/SimpleURLConnections/Introduction/Intro.html#//apple_ref/doc/uid/DTS40009245 см. файл :::AppDelegate.m

person muzz    schedule 29.11.2011

Я создал чистое решение Cocoa с помощью категории на NSFileManager, которая использует комбинацию NSTemporary() и глобального уникального идентификатора.

Вот заголовочный файл:

@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: для создания файла.

person Philipp    schedule 22.10.2010

Если вы нацелены на iOS 6.0 или Mac OS X 10.8 или выше:

NSString *tempFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
person fzwo    schedule 15.07.2014

Свифт 5 и Свифт 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

Или, альтернативно, oneliner Ssswift:

let prefix = "blah"
let url2 = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("\(prefix)-\(UUID())")
print(url2)
person Bart van Kuik    schedule 03.07.2015
comment
Этот код больше не работает, но эквивалентная версия еще проще: URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("\(prefix)-\(UUID())") - person Ssswift; 14.06.2017
comment
Спасибо @Ssswift обновил ответ немного более подробным образом. - person Bart van Kuik; 16.06.2017

Вы можете использовать mktemp, чтобы получить временную имя файла.

person Giao    schedule 19.10.2008
comment
В mktemp(3) есть состояние гонки, лучше использовать mkstemp(3). - person ; 19.10.2008

Современный способ сделать это — url(for:in:appropriateFor:create:) от FileManager.

С помощью этого метода вы можете указать SearchPathDirectory, чтобы точно сказать, какой временный каталог, который вы хотите. Например, .cachesDirectory будет сохраняться между запусками (насколько это возможно) и будет сохранено в пользовательской библиотеке, а .itemReplacementDirectory будет находиться на том же томе, что и целевой файл.

person Ssswift    schedule 16.06.2017

Вы можете использовать от NSTask до uuidgen, чтобы получить уникальное имя файла, а затем добавить его к строке из NSTemporaryDirectory(). Это не будет работать на Cocoa Touch. Хотя это немного затянуто.

person alextgordon    schedule 19.10.2008
comment
Использование NSTask для выполнения uuidgen немного излишне, если все, что вам нужно, это UUID. - person dreamlax; 18.10.2012
comment
Обратите внимание, что в версии 10.8+ есть класс NSUUID для создания UUID без выхода из земли какао: developer.apple.com/library/ios/documentation/Foundation/ - person Jay; 14.03.2014

Добавление к @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;
}
person SwiftArchitect    schedule 07.07.2014

Не используйте устаревшие API, такие как NSTemporaryDirectory, вместо этого получите правильный URL от FileManager.

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

Вам все равно придется создать каталог.

person Erik Aigner    schedule 29.04.2020