Доступ к временному каталогу в Swift

Я пытался получить доступ к временному каталогу в Swift. В Objective-C я мог бы использовать следующий код для этого:

- (NSString *)tempDirectory {

    NSString *tempDirectoryTemplate =
    [NSTemporaryDirectory() stringByAppendingPathComponent:@"XXXXX"];
    const char *tempDirectoryTemplateCString = [tempDirectoryTemplate fileSystemRepresentation];
    char *tempDirectoryNameCString           = (char *)malloc(strlen(tempDirectoryTemplateCString) + 1);
    strcpy(tempDirectoryNameCString, tempDirectoryTemplateCString);
    char *result                             = mkdtemp(tempDirectoryNameCString);
    if (!result) {
        return nil;
    }
    NSString *tempDirectoryPath = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:tempDirectoryNameCString length:strlen(result)];
    free(tempDirectoryNameCString);
    return tempDirectoryPath;
}

Однако я немного запутался в преобразовании типов и кастингах из Objective-C в Swift, например const char * или CMutablePointer<CChar>. Есть ли какие-либо документы, на которые я должен смотреть?

Спасибо.

Ответ 1

Как насчет чего-то типа:

func createTempDirectory() -> String? {
    let tempDirectoryTemplate = NSTemporaryDirectory().stringByAppendingPathComponent("XXXXX")

    let fileManager = NSFileManager.defaultManager()

    var err: NSErrorPointer = nil
    if fileManager.createDirectoryAtPath(tempDirectoryTemplate, withIntermediateDirectories: true, attributes: nil, error: err) {
        return tempDirectoryTemplate
    } else {
        return nil
    }
}

Он не отвечает на ваш вопрос о char *, но он чище...

Ссылка NSFileManager здесь.

Также проверьте этот вопрос SO относительно уникальных имен.

Ответ 2

версия Swift 2.1:

func createTempDirectory() -> String? {

    let tempDirURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent("XXXXXX")

    do {
        try NSFileManager.defaultManager().createDirectoryAtURL(tempDirURL, withIntermediateDirectories: true, attributes: nil)
    } catch {
        return nil
    }

    return tempDirURL.absoluteString
}

Ответ 3

версия Swift 3

func createTempDirectory() -> String? {

    guard let tempDirURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("myTempFile.xxx") else {
        return nil
    }

    do {
        try FileManager.default.createDirectory(at: tempDirURL, withIntermediateDirectories: true, attributes: nil)
    } catch {
        return nil
    }

    return tempDirURL.absoluteString
}

Ответ 4

Прямой перевод вашего кода Objective-C в Swift будет:

func tempDirectory()->String! {
    let tempDirectoryTemplate = NSTemporaryDirectory()  + "XXXXX"
    var tempDirectoryTemplateCString = tempDirectoryTemplate.fileSystemRepresentation().copy()
    let result : CString = reinterpretCast(mkdtemp(&tempDirectoryTemplateCString))
    if !result {
        return nil
    }
    let fm = NSFileManager.defaultManager()
    let tempDirectoryPath = fm.stringWithFileSystemRepresentation(result, length: Int(strlen(result)))
    return tempDirectoryPath
}

В качестве исходного кода используется тот же метод mkdtemp() BSD. Этот метод создает имя каталога из шаблона, который, как гарантируется, не существует в то время, когда вызывается метод.

Благодаря Nate Cook, который понял, что reinterpretCast() может использоваться для обработки UnsafePointer<CChar>, возвращаемого mkdtemp(), как CString, так что его можно передать в stringWithFileSystemRepresentation(), см. Работа со строками C в Swift или: Как преобразовать UnsafePointer <CChar> в CString.


Начиная с Xcode 6 beta 6, reinterpretCast() больше не требуется, и выше код может быть упрощен до

func tempDirectory()->String! {
    let tempDirectoryTemplate = NSTemporaryDirectory()  + "XXXXX"
    var tempDirectoryTemplateCString = tempDirectoryTemplate.fileSystemRepresentation()
    let result = mkdtemp(&tempDirectoryTemplateCString)
    if result == nil {
        return nil
    }
    let fm = NSFileManager.defaultManager()
    let tempDirectoryPath = fm.stringWithFileSystemRepresentation(result, length: Int(strlen(result)))
    return tempDirectoryPath
}

Ответ 5

Свифт 3 и выше

Я думаю, что хороший способ сделать это в Swift с расширением на FileManager. Это должно создать уникальную временную папку и вернуть вам URL.

extension FileManager{

    func createTemporaryDirectory() throws -> URL {
        let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString)

        try createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
        return url
    }
}