Merge folders with NSFileManager, overwrite only existing files

Basically I am looking for a way to merge two folders in a file system using the cocoa API:

I have a folder containing files and subfolders that I want to copy to another location on the file system.
A folder with the same name already exists on my destination path, which may also contain files and folders.

Now I want to overwrite existing files inside the destination folder (or its subfolders) with the new contents of the original folder if they have the same name.
All other files that I want to leave intact.

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

How can i do this? Many thanks for your help!

+6
source share
3 answers

I searched everywhere but found nothing. So I came up with my solution using NSDirectoryEnumerator . This should work on the diagram (overriding old files). Hope this helps.

 - (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; } } } } 
+7
source

Solution in 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 } } } 
+2
source

Look at the file manager methods and instead of using the default file manager, create your own using alloc / init, set the delegate and use the delegate methods.

+1
source

Source: https://habr.com/ru/post/954794/


All Articles