【问题标题】:How to move a file and create missing directories in OS X?如何在 OS X 中移动文件并创建丢失的目录?
【发布时间】:2015-12-31 00:35:26
【问题描述】:

我想在 OSX 中将文件移动到另一个目录:

func moveFile(currentPath currentPath: String, targetPath: String) {

let fileManager = NSFileManager.defaultManager()

do { try fileManager.moveItemAtPath(currentPath, toPath: targetPath) }
catch let error as NSError { print(error.description) }

}

一切正常,除了目标目录不存在的情况。我发现.isWritableFileAtPath 可能会有所帮助。

但是,在我声明的函数中,我使用了完整的文件路径(包括文件名)。

如何从路径中拆分文件名或更一般地:如果需要,我如何强制 Swift 在移动文件之前创建目录?

【问题讨论】:

    标签: macos cocoa swift2 nsfilemanager


    【解决方案1】:

    过去我用类似于下面代码的代码解决了这个问题。基本上,您只需检查代表您要创建的文件的父目录的路径中是否存在文件。如果它不存在,则创建它以及路径中不存在的所有文件夹。

    func moveFile(currentPath currentPath: String, targetPath: String) {
        let fileManager = NSFileManager.defaultManager()
        let parentPath = (targetPath as NSString).stringByDeletingLastPathComponent()
        var isDirectory: ObjCBool = false
        if !fileManager.fileExistsAtPath(parentPath, isDirectory:&isDirectory) {
            fileManager.createDirectoryAtPath(parentPath, withIntermediateDirectories: true, attributes: nil)
    
            // Check to see if file exists, move file, error handling
        }
        else if isDirectory {
            // Check to see if parent path is writable, move file, error handling
        }
        else {
            // Parent path exists and is a file, error handling
        }
    }
    

    您可能还想使用 fileExistsAtPath:isDirectory: 变体,以便处理其他错误情况。

    也是如此

    【讨论】:

    • var currentPath 具有误导性,它的字符串包含类似:“/Documents/test.plist”的内容,它包括完整路径和文件名。这就是为什么createDirectoryAtPath 对我不起作用的原因,因为在这种情况下,它会创建一个名为“test.plist”的目录。
    • 我不确定您指的是什么 currentPath var。您会注意到在我的示例代码中我使用了一个名为parentPath 的变量,这是您需要传递给fileExistsAtPath:createDirectoryAtPath:withIntermediateDirectories:attributes: 的变量。对于您提到的路径/Documents/test.plistparentPath 需要为/Documents。您可以使用NSString 上的stringByDeletingLastPathComponent 方法轻松完成此操作。我会将这些细节添加到答案中。
    • 我指的是我的问题中的函数。但是,stringByDeletingLastPathComponent 完成了这项工作。谢谢你的回答!
    【解决方案2】:

    我已将此扩展添加到 FileManager 以实现此目的

    extension FileManager {
    
        func moveItemCreatingIntermediaryDirectories(at: URL, to: URL) throws {
            let parentPath = to.deletingLastPathComponent()
            if !fileExists(atPath: parentPath.path) {
                try createDirectory(at: parentPath, withIntermediateDirectories: true, attributes: nil)
            }
            try moveItem(at: at, to: to)
        }
    
    }
    

    【讨论】:

      【解决方案3】:

      添加这个是因为这个问题在谷歌中弹出,而其他答案使用了一个他们可能不应该在这种情况下使用的 API。

      请务必在 FileExists(atPath:) 文档中注意这一点:

      不建议尝试基于文件系统的当前状态或文件系统上的特定文件来判断行为。这样做可能会导致奇怪的行为或竞争条件。尝试操作(例如加载文件或创建目录)、检查错误并优雅地处理这些错误比尝试提前确定操作是否成功要好得多。有关文件系统竞争条件的更多信息,请参阅安全编码指南中的竞争条件和安全文件操作。

      另外,来自createDirectory(atPath:withIntermediateDirectories:attributes:) 文档:

      返回值

      如果创建了目录,则为 true,如果设置了 createIntermediates 并且目录已存在,则为 true,如果发生错误,则为 false。

      withIntermediateDirectories:参数设置为true的情况下尝试创建一个新目录,如果该目录已经存在,则不会引发错误,因此即使该目录已经存在,您也可以安全地使用它。

      跳过存在性检查,尝试写入目录,然后尝试移动文件:

      
      func moveFile(from currentURL: URL, to targetURL: URL) {
      
          // Get the target directory by removing the file component
          let targetDir = targetURL.deletingLastPathComponent()
      
          do {
              try FileManager.default.createDirectory(at:targetDir, withIntermediateDirectories: true, attributes: nil)
          } catch {
              // Handle errors
          }
          do { 
              try FileManager.default.moveItem(at:currentURL, to: targetURL) }
          catch { 
              // Handle errors
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-04-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多