使用NSFileManager合并文件夹,仅覆盖现有文件

时间:2013-09-27 15:46:40

标签: ios macos cocoa nsfilemanager

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

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

现在我想用我的源文件夹的新内容覆盖目标文件夹(或其子文件夹)中的现有文件,如果它们具有相同的名称。
我想要保留的所有其余文件都不会受到影响。

sourcefolder
   |
   - file1
   - subfolder
       - file2


destinationfolder
   |
   - file3
   - subfolder
       - file2
       - file4


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

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

3 个答案:

答案 0 :(得分: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;
            }
        }
    }
}

答案 1 :(得分: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
        }
    }
}

答案 2 :(得分:1)

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