2013-09-27 121 views
6

基本上我在找一種與可可API文件系統合併兩個文件夾:合併文件夾用的NSFileManager,只覆蓋現有文件

我有一個包含文件和子文件夾,這是我想要的文件夾複製到文件系統中的其他位置。
在我的目標路徑中,同名文件夾已經存在,它也可能包含文件和文件夾。

現在我想用我的源文件夾的新內容覆蓋目標文件夾(或其子文件夾)內的現有文件,如果它們具有相同的名稱。
我想保留所有其他文件不變。

sourcefolder 
    | 
    - file1 
    - subfolder 
     - file2 


destinationfolder 
    | 
    - file3 
    - subfolder 
     - file2 
     - file4 


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

我該怎麼做? 非常感謝您的幫助!

回答

7

我到處搜索,但什麼也沒找到。所以我想出了我自己的解決方案,利用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; 
      } 
     } 
    } 
} 
+0

溶液中的''enumeratorAtPath方法工作那麼大。 –

+0

你真棒!爲我節省了大量的時間:) – jj080808

1

看文件管理方法和,而不是使用默認的文件管理器,創建你自己與分配/初始化,設置一個委託,並使用委託方法。

+0

感謝您的建議!我還發現自己還有其他方法可以更乾淨地做到這一點。我會編輯我的答案。 – Hlung

2

在夫特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 
     } 
    } 
}