【问题标题】:Is there a safer way to create a directory if it does not exist?如果目录不存在,是否有更安全的方法来创建目录?
【发布时间】:2023-03-28 22:55:02
【问题描述】:

如果目录不存在,我发现了这种创建目录的方法。但它看起来有点不稳定,我担心这可能会在 1000 次尝试中出错。

if(![[NSFileManager defaultManager] fileExistsAtPath:bundlePath]) {
    [[NSFileManager defaultManager] createDirectoryAtPath:bundlePath withIntermediateDirectories:YES attributes:nil error:NULL];
}

只有这个笨拙的方法 fileExistsAtPath 还查找文件而不仅仅是目录。但对我来说,危险的事情是:如果出现问题怎么办?我该怎么办?什么是保证目录被创建并且仅在目录不存在时才被创建的最佳实践?

我知道文件系统操作从来都不是安全的。设备可能会在它开始将钻头从 A 铲到 B 的那一刻突然失去电池电量。或者它可能会偶然发现一个坏钻头并挂起一秒钟。也许在极少数情况下,即使没有目录,它也会返回 YES。简单地说:我不信任文件系统操作。

我怎样才能让它绝对安全?

【问题讨论】:

    标签: ios objective-c filesystems nsfilemanager nsdocumentdirectory


    【解决方案1】:

    您实际上可以跳过if,尽管Apple 的文档说该目录不得存在,但只有在您传递withIntermediateDirectories:NO 时才是正确的

    这归结为一个电话。下一步是捕获任何错误:

    NSError * error = nil;
    [[NSFileManager defaultManager] createDirectoryAtPath:bundlePath
                              withIntermediateDirectories:YES
                                               attributes:nil
                                                    error:&error];
    if (error != nil) {
        NSLog(@"error creating directory: %@", error);
        //..
    }
    

    如果目录已经存在,这将不会导致错误。

    【讨论】:

    • 太棒了!如果出现错误怎么办?尝试再试一次有意义吗? (至少几次......?如果这没有帮助怎么办?)
    • 如果出现错误我不知道该怎么办。这取决于你想得到多花哨。您可以查找特定错误并以不同方式处理它们,或者尝试创建不同的路径。也许让用户选择一个不同的?
    • @Sven:我看不出它对逻辑有何影响?
    • Cocoa 错误处理通常不保证错误指针在成功时为NULL,只是在失败时填充。
    【解决方案2】:

    对于 Swift 3.0

    do {
        try FileManager.default.createDirectory(atPath: folder, withIntermediateDirectories: true, attributes: nil)
    } catch {
        print(error)
    }
    

    【讨论】:

      【解决方案3】:

      斯威夫特 4.2

      let fileManager = FileManager.default
      let documentsURL =  fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
      
      let imagesPath = documentsURL.appendingPathComponent("Images")
      do
      {
          try FileManager.default.createDirectory(atPath: imagesPath.path, withIntermediateDirectories: true, attributes: nil)
      }
      catch let error as NSError
      {
          NSLog("Unable to create directory \(error.debugDescription)")
      }
      

      【讨论】:

        【解决方案4】:

        Swift 5.0

        let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
        let documentsDirectory = paths[0]
        let docURL = URL(string: documentsDirectory)!
        let dataPath = docURL.appendingPathComponent("MyFolder")
        if !FileManager.default.fileExists(atPath: dataPath.absoluteString) {
            do {
                try FileManager.default.createDirectory(atPath: dataPath.absoluteString, withIntermediateDirectories: true, attributes: nil)
            } catch {
                print(error.localizedDescription);
            }
        }
        

        【讨论】:

          【解决方案5】:
          NSFileManager *fileManager= [NSFileManager defaultManager]; 
          if(![fileManager fileExistsAtPath:directory isDirectory:&isDir])
              if(![fileManager createDirectoryAtPath:directory withIntermediateDirectories:YES attributes:nil error:NULL])
                  NSLog(@"Error: Create folder failed %@", directory);
          

          来自一个 SO 主题 here

          创建目录后,您可以刷新文件系统,然后检查新创建的目录是否存在。这可能是矫枉过正,但你永远不能有太多矫枉过正。

          【讨论】:

          • “刷新文件系统”是什么意思?
          • dontWatchMyProfile:写入磁盘(或在本例中为 FLASH 存储)通常首先写入速度更快的 RAM,然后在性能和负载允许的情况下提交到主存储。刷新该缓存或“同步”命令系统“立即写入缓存的全部内容”。正如OP所说,这在断电时很重要。我几乎没有关于 iPhone 和相关设备上的文件 IO 的信息,但这里存在一个希望相关的 SO 线程:stackoverflow.com/questions/459537/…
          • 在第二行和第三行之间你应该添加这样的注释: // 在这里,我们切换进程,其他人可以使用我们刚刚传递给 fileExistsAtPath:isDirectory 的名称创建一个文件: - 所以这个检查真的不值得做。
          【解决方案6】:

          在 swift 2 中是这样的:

          do {
              try NSFileManager.defaultManager().createDirectoryAtPath(pathURL.absoluteString, withIntermediateDirectories: true, attributes: nil)
          } catch {
              print(error)
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-08-01
            • 2011-05-12
            • 1970-01-01
            相关资源
            最近更新 更多