【问题标题】:Merge folders with NSFileManager, overwrite only existing files使用 NSFileManager 合并文件夹,仅覆盖现有文件
【发布时间】:2013-10-03 23:57:48
【问题描述】:

基本上我正在寻找一种将文件系统中的两个文件夹与可可 API 合并的方法:

我有一个包含文件和子文件夹的文件夹,我想将它们复制到文件系统中的不同位置。
在我的目标路径中,已经存在一个同名文件夹,其中也可能包含文件和文件夹。

现在我想用我的源文件夹的新内容覆盖目标文件夹(或其子文件夹)中的现有文件(如果它们具有相同的名称)。
其余的文件我想保持不变。

sourcefolder
   |
   - file1
   - subfolder
       - file2


destinationfolder
   |
   - file3
   - subfolder
       - file2
       - file4


resultingfolder
   |
   - file1
   - file3
   - subfolder
       - file2      <-- version from source folder
       - file4

我该怎么做? 非常感谢您的帮助!

【问题讨论】:

    标签: ios macos cocoa nsfilemanager


    【解决方案1】:

    我到处寻找,但一无所获。所以我想出了自己的解决方案,利用NSDirectoryEnumerator。这应该适用于图表(覆盖旧文件)。希望对您有所帮助。

    - (void)mergeContentsOfPath:(NSString *)srcDir intoPath:(NSString *)dstDir error:(NSError**)err {
    
        NSLog(@"- mergeContentsOfPath: %@\n intoPath: %@", srcDir, dstDir);
    
        NSFileManager *fm = [NSFileManager defaultManager];
        NSDirectoryEnumerator *srcDirEnum = [fm enumeratorAtPath:srcDir];
        NSString *subPath;
        while ((subPath = [srcDirEnum nextObject])) {
    
            NSLog(@" subPath: %@", subPath);
            NSString *srcFullPath =  [srcDir stringByAppendingPathComponent:subPath];
            NSString *potentialDstPath = [dstDir stringByAppendingPathComponent:subPath];
    
            // Need to also check if file exists because if it doesn't, value of `isDirectory` is undefined.
            BOOL isDirectory = ([[NSFileManager defaultManager] fileExistsAtPath:srcFullPath isDirectory:&isDirectory] && isDirectory);
    
            // Create directory, or delete existing file and move file to destination
            if (isDirectory) {
                NSLog(@"   create directory");
                [fm createDirectoryAtPath:potentialDstPath withIntermediateDirectories:YES attributes:nil error:err];
                if (err && *err) {
                    NSLog(@"ERROR: %@", *err);
                    return;
                }
            }
            else {
                if ([fm fileExistsAtPath:potentialDstPath]) {
                    NSLog(@"   removeItemAtPath");
                    [fm removeItemAtPath:potentialDstPath error:err];
                    if (err && *err) {
                        NSLog(@"ERROR: %@", *err);
                        return;
                    }
                }
    
                NSLog(@"   moveItemAtPath");
                [fm moveItemAtPath:srcFullPath toPath:potentialDstPath error:err];
                if (err && *err) {
                    NSLog(@"ERROR: %@", *err);
                    return;
                }
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      查看文件管理器方法,而不是使用默认文件管理器,使用 alloc/init 创建自己的文件管理器,设置委托并使用委托方法。

      【讨论】:

      • 感谢您的建议!我也刚刚发现自己还有其他方法可以更干净地做到这一点。我将编辑我的答案。
      【解决方案3】:

      Swift 3 中的解决方案

      let merger = FoldersMerger(actionType: .copy, conflictResolution: .keepSource)
      merger.merge(atPath: sourceFolder, toPath: destinationFolder)
      
      
      class FoldersMerger {
      
          enum ActionType { case move, copy }
          enum ConflictResolution { case keepSource, keepDestination }
      
          private let fileManager = FileManager()
          private var actionType: ActionType!
          private var conflictResolution: ConflictResolution!
          private var deleteEmptyFolders: Bool!
      
          init(actionType: ActionType = .move, conflictResolution: ConflictResolution = .keepDestination, deleteEmptyFolders: Bool = false) {
              self.actionType = actionType
              self.conflictResolution = conflictResolution
              self.deleteEmptyFolders = deleteEmptyFolders
          }
      
          func merge(atPath: String, toPath: String) {
              let pathEnumerator = fileManager.enumerator(atPath: atPath)
      
              var folders: [String] = [atPath]
      
              while let relativePath = pathEnumerator?.nextObject() as? String {
      
                  let subItemAtPath = URL(fileURLWithPath: atPath).appendingPathComponent(relativePath).path
                  let subItemToPath = URL(fileURLWithPath: toPath).appendingPathComponent(relativePath).path
      
                  if isDir(atPath: subItemAtPath) {
      
                      if deleteEmptyFolders! {
                         folders.append(subItemAtPath)
                      }
      
                      if !isDir(atPath: subItemToPath) {
                          do {
                              try fileManager.createDirectory(atPath: subItemToPath, withIntermediateDirectories: true, attributes: nil)
                              NSLog("FoldersMerger: directory created: %@", subItemToPath)
                          }
                          catch let error {
                              NSLog("ERROR FoldersMerger: %@", error.localizedDescription)
                          }
                      }
                      else {
                          NSLog("FoldersMerger: directory %@ already exists", subItemToPath)
                      }
                  }
                  else {
      
                      if isFile(atPath:subItemToPath) && conflictResolution == .keepSource {
                          do {
                              try fileManager.removeItem(atPath: subItemToPath)
                              NSLog("FoldersMerger: file deleted: %@", subItemToPath)
                          }
                          catch let error {
                              NSLog("ERROR FoldersMerger: %@", error.localizedDescription)
                          }
                      }
      
                      do {
                          try fileManager.moveItem(atPath: subItemAtPath, toPath: subItemToPath)
                          NSLog("FoldersMerger: file moved from %@ to %@", subItemAtPath, subItemToPath)
                      }
                      catch let error {
                          NSLog("ERROR FoldersMerger: %@", error.localizedDescription)
                      }
                  }
              }
      
              if deleteEmptyFolders! {
                  folders.sort(by: { (path1, path2) -> Bool in
                      return path1.characters.split(separator: "/").count < path2.characters.split(separator: "/").count
                  })
                  while let folderPath = folders.popLast() {
                      if isDirEmpty(atPath: folderPath) {
                          do {
                              try fileManager.removeItem(atPath: folderPath)
                              NSLog("FoldersMerger: empty dir deleted: %@", folderPath)
                          }
                          catch {
                              NSLog("ERROR FoldersMerger: %@", error.localizedDescription)
                          }
                      }
                  }
              }
          }
      
          private func isDir(atPath: String) -> Bool {
              var isDir: ObjCBool = false
              let exist = fileManager.fileExists(atPath: atPath, isDirectory: &isDir)
              return exist && isDir.boolValue
          }
      
          private func isFile(atPath: String) -> Bool {
              var isDir: ObjCBool = false
              let exist = fileManager.fileExists(atPath: atPath, isDirectory: &isDir)
              return exist && !isDir.boolValue
          }
      
          private func isDirEmpty(atPath: String) -> Bool {
              do {
                  return try fileManager.contentsOfDirectory(atPath: atPath).count == 0
              }
              catch _ {
                  return false
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2014-01-08
        • 2015-11-30
        • 2011-09-02
        • 2021-01-09
        • 1970-01-01
        • 1970-01-01
        • 2016-04-22
        • 1970-01-01
        • 2021-12-05
        相关资源
        最近更新 更多