Много лет назад, когда я работал с C#, я мог легко создать временный файл и получить его имя с помощью этой функции:
Path.GetTempFileName();
Эта функция создаст файл с уникальным именем во временном каталоге и вернет полный путь к этому файлу.
В API Какао самое близкое, что я могу найти, это:
NSTemporaryDirectory
Я упускаю что-то очевидное или нет встроенного способа сделать это?





Вы можете использовать mktemp, чтобы получить временное имя файла.
В mktemp (3) есть состояние гонки, лучше использовать mkstemp (3).
Безопасный способ - использовать мкстемп (3).
Не совсем "с Какао" ... больше похоже на "с POSIX"
[Примечание. Это относится к iPhone SDK, а не к Mac OS SDK]
Насколько я могу судить, этих функций нет в SDK (файл unistd.h значительно урезан по сравнению со стандартным файлом Mac OS X 10.5). Я бы использовал что-то вроде:
[NSTemporaryDirectory() stringByAppendingPathComponent: [NSString stringWithFormat: @"%.0f.%@", [NSDate timeIntervalSinceReferenceDate] * 1000.0, @"txt"]];
Не самый красивый, но функциональный
Это имеет то же состояние гонки, что и mktemp (3): разделение создания имени файла и создания временного файла открывает окно уязвимости. Используйте mkstemp (3), как предлагает Грэм Ли.
Извините, я был в режиме iPhone; mkstemp (3), как было предложено на исходном плакате, подходит, но не работает на iPhone.
На iPhone каждое приложение имеет собственное поддерево файловой системы. NSTemporaryDirectory () возвращает что-то в пакете приложений. Вы все еще гоняетесь против себя и против всего, у кого есть разрешение на запись в ваш tmp-каталог, но я думаю, что это только привилегированные процессы.
@ Кен, где спрашивающий сказал, что они были на iPhone?
Нигде, кроме этого ответа, который мы комментируем. :-) Я отвечал на вышесказанное. Отсутствие mkstemp на телефоне - не такая большая проблема на телефоне, как на Mac.
Это не удается при вызове «одновременно» из более чем одного потока. Я не знаю, насколько детализирован этот метод (документация не сообщает подробностей об этом), но для меня случилось так, что мои NSOperations были вызваны слишком быстро, и файлы получили те же имена. Мое решение заключалось в том, чтобы добавить адрес NSOperations к имени файла, поскольку они обязательно будут отличаться: [NSString stringWithFormat: @ "% d _%. 0f.% @", Self, [NSDate timeInterv ...
..или просто используйте NSUUID, т.е. NSString *uuidString = [[NSUUID UUID] UUIDString];
Вы можете использовать от NSTask до uuidgen, чтобы получить уникальное имя файла, а затем добавить его в строку из NSTemporaryDirectory(). Это не будет работать с Cocoa Touch. Хотя это немного многословно.
Использование NSTask для выполнения uuidgen немного излишне, если вам нужен только UUID.
Обратите внимание, что 10.8+ имеет класс NSUUID для создания UUID без выхода из зоны Какао: developer.apple.com/library/ios/documentation/Foundation/…
Я создал чистое решение какао посредством категории на 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: для создания файла.
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
Добавление в @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;
}
Если вы настроили таргетинг на iOS 6.0 или Mac OS X 10.8 или выше:
NSString *tempFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
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)
Этот код больше не работает, но эквивалентная версия еще проще: URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("\(prefix)-\(UUID())")
Спасибо, @Ssswift обновил ответ более подробным образом.
Современный способ сделать это - FileManagerurl(for:in:appropriateFor:create:).
С помощью этого метода вы можете указать SearchPathDirectory, чтобы точно сказать, какой именно временный каталог вам нужен. Например, .cachesDirectory будет сохраняться между запусками (насколько это возможно) и будет сохранен в библиотеке пользователя, в то время как .itemReplacementDirectory будет на том же томе, что и целевой файл.
Не используйте устаревшие API, такие как NSTemporaryDirectory, получите правильный URL вместо FileManager.
let tmpURL = FileManager
.default
.temporaryDirectory
.appendingPathComponent(UUID().uuidString)
Вам все равно придется создать каталог.
Предупреждение при использовании этого C# API: у него есть пространство имен только из 65k файлов, и при его исчерпании будет выдано исключение. Это случилось с нами в производственной среде - не все программы старательно очищают свои временные файлы.