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

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

Path.GetTempFileName();

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

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

NSTemporaryDirectory

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

Предупреждение при использовании этого C# API: у него есть пространство имен только из 65k файлов, и при его исчерпании будет выдано исключение. Это случилось с нами в производственной среде - не все программы старательно очищают свои временные файлы.

fzwo 25.12.2016 12:18
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
43
1
40 212
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

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

В mktemp (3) есть состояние гонки, лучше использовать mkstemp (3).

user23743 19.10.2008 05:38
Ответ принят как подходящий

Безопасный способ - использовать мкстемп (3).

Не совсем "с Какао" ... больше похоже на "с POSIX"

Ben Leggiero 02.03.2019 02:16

[Примечание. Это относится к 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), как предлагает Грэм Ли.

Chris Hanson 19.10.2008 07:54

Извините, я был в режиме iPhone; mkstemp (3), как было предложено на исходном плакате, подходит, но не работает на iPhone.

Ben Gottlieb 19.10.2008 15:44

На iPhone каждое приложение имеет собственное поддерево файловой системы. NSTemporaryDirectory () возвращает что-то в пакете приложений. Вы все еще гоняетесь против себя и против всего, у кого есть разрешение на запись в ваш tmp-каталог, но я думаю, что это только привилегированные процессы.

Ken 19.10.2008 22:07

@ Кен, где спрашивающий сказал, что они были на iPhone?

user23743 20.10.2008 02:21

Нигде, кроме этого ответа, который мы комментируем. :-) Я отвечал на вышесказанное. Отсутствие mkstemp на телефоне - не такая большая проблема на телефоне, как на Mac.

Ken 20.10.2008 14:34

Это не удается при вызове «одновременно» из более чем одного потока. Я не знаю, насколько детализирован этот метод (документация не сообщает подробностей об этом), но для меня случилось так, что мои NSOperations были вызваны слишком быстро, и файлы получили те же имена. Мое решение заключалось в том, чтобы добавить адрес NSOperations к имени файла, поскольку они обязательно будут отличаться: [NSString stringWithFormat: @ "% d _%. 0f.% @", Self, [NSDate timeInterv ...

Christian Beer 27.01.2011 14:53

..или просто используйте NSUUID, т.е. NSString *uuidString = [[NSUUID UUID] UUIDString];

Jay 24.03.2017 10:03

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

Использование NSTask для выполнения uuidgen немного излишне, если вам нужен только UUID.

dreamlax 18.10.2012 04:54

Обратите внимание, что 10.8+ имеет класс NSUUID для создания UUID без выхода из зоны Какао: developer.apple.com/library/ios/documentation/Foundation/…

Jay 14.03.2014 23:47

Я создал чистое решение какао посредством категории на 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]];

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

Или, в качестве альтернативы, oneliner Ssswift:

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

Этот код больше не работает, но эквивалентная версия еще проще: URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("\(prefix)-\(‌​UUID())")

Ssswift 14.06.2017 22:40

Спасибо, @Ssswift обновил ответ более подробным образом.

Bart van Kuik 16.06.2017 08:59

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

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

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

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

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

Другие вопросы по теме