2013-09-27 11 views
6

を上書きし、NSFileManagerとフォルダをマージ基本的に私はココアのAPIでファイルシステム内の2つのフォルダをマージする方法を探しています:だけ既存のファイル

私は私がしたいファイルやサブフォルダを含むフォルダを持っていますファイルシステム内の別の場所にコピーします。
私の目的地のパスには、同じ名前のフォルダが既に存在します。フォルダにはファイルやフォルダも含まれています。

ここでは、同じ名前のソースフォルダの新しいコンテンツで、コピー先のフォルダ(またはそのサブフォルダ)内の既存のファイルを上書きしたいと考えています。
残りのファイルの残りの部分はそのまま残しておきます。

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

ファイルマネージャのメソッドを見て、代わりにデフォルトのファイルマネージャを使用しての、のalloc/initで独自のものを作成し、デリゲートを設定し、デリゲートメソッドを使用します。

+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 
     } 
    } 
} 
関連する問題