Ios 将文件夹与NSFileManager合并,仅覆盖现有文件
基本上,我正在寻找一种方法,用cocoa API合并文件系统中的两个文件夹: 我有一个包含文件和子文件夹的文件夹,我想将其复制到文件系统中的其他位置。Ios 将文件夹与NSFileManager合并,仅覆盖现有文件,ios,macos,cocoa,nsfilemanager,Ios,Macos,Cocoa,Nsfilemanager,基本上,我正在寻找一种方法,用cocoa API合并文件系统中的两个文件夹: 我有一个包含文件和子文件夹的文件夹,我想将其复制到文件系统中的其他位置。 在我的目标路径中,已存在同名文件夹,其中可能还包含文件和文件夹 现在,如果目标文件夹(或其子文件夹)中的现有文件同名,我想用源文件夹的新内容覆盖它们。 我想保留的所有其他文件都不动 sourcefolder | - file1 - subfolder - file2 destinationfolder |
在我的目标路径中,已存在同名文件夹,其中可能还包含文件和文件夹 现在,如果目标文件夹(或其子文件夹)中的现有文件同名,我想用源文件夹的新内容覆盖它们。
我想保留的所有其他文件都不动
sourcefolder
|
- file1
- subfolder
- file2
destinationfolder
|
- file3
- subfolder
- file2
- file4
resultingfolder
|
- file1
- file3
- subfolder
- file2 <-- version from source folder
- file4
sourcefolder
|
-文件1
-子文件夹
-文件2
目的文件夹
|
-文件3
-子文件夹
-文件2
-文件4
结果文件夹
|
-文件1
-文件3
-子文件夹
-我到处找,但什么也没找到。因此,我提出了自己的解决方案,利用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;
}
}
}
}
查看文件管理器方法,不要使用默认的文件管理器,而是使用alloc/init创建自己的文件管理器,设置一个委托,然后使用委托方法 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
}
}
}
let merge=FoldersMerger(操作类型:。复制,冲突解决:。keepSource)
merge.merge(atPath:sourceFolder,toPath:destinationFolder)
类折叠器{
枚举操作类型{case move,copy}
枚举冲突解决{case keepSource,keepDestination}
private let fileManager=fileManager()
私有var actionType:actionType!
私有var冲突解决:冲突解决!
私人var deleteEmptyFolders:Bool!
init(actionType:actionType=.move,conflictResolution:conflictResolution=.keepDestination,deleteEmptyFolders:Bool=false){
self.actionType=actionType
self.conflictdolution=冲突解决
self.deleteEmptyFolders=deleteEmptyFolders
}
func合并(atPath:String,toPath:String){
让pathEnumerator=fileManager.enumerator(atPath:atPath)
变量文件夹:[String]=[atPath]
而让relativePath=pathEnumerator?.nextObject()作为?字符串{
让subItemAtPath=URL(fileURLWithPath:atPath).appendingPathComponent(relativePath).path
让subItemToPath=URL(fileURLWithPath:toPath).appendingPathComponent(relativePath).path
if isDir(atPath:子项atPath){
如果删除空文件夹{
文件夹。追加(子项路径)
}
if!isDir(atPath:subItemToPath){
做{
尝试fileManager.createDirectory(路径:subItemToPath,中间目录:true,属性:nil)
NSLog(“FoldersMerger:已创建目录:%@”,子项路径)
}
捕捉错误{
NSLog(“错误文件夹:%@”,错误。本地化描述)
}
}
否则{
NSLog(“FoldersMerger:目录%@已存在”,子项路径)
}
}
否则{
如果isFile(atPath:subItemToPath)&&conflictsolution==.keepSource{
做{
尝试fileManager.removeItem(路径:subItemToPath)
NSLog(“文件夹:文件已删除:%@”,子项路径)
}
捕捉错误{
NSLog(“错误文件夹:%@”,错误。本地化描述)
}
}
做{
尝试fileManager.moveItem(atPath:subItemAtPath,toPath:subItemToPath)
NSLog(“文件夹:文件从%@移动到%@”,子项路径,子项路径)
}
捕捉错误{
NSLog(“错误文件夹:%@”,错误。本地化描述)
}
}
}
如果删除空文件夹{
排序(按:{(路径1,路径2)->Bool-in
返回路径1.characters.split(分隔符:“/”).countBool{
var isDir:ObjCBool=false
let exist=fileManager.fileExists(atPath:atPath,isDirectory:&isDir)
返回exist&&isDir.boolValue
}
私有函数isFile(atPath:String)->Bool{
var isDir:ObjCBool=false
let exist=fileManager.fileExists(atPath:atPath,isDirectory:&isDir)
返回exist&!isDir.boolValue
}
private func isDirEmpty(atPath:String)->Bool{
做{
返回try fileManager.contentsOfDirectory(atPath:atPath).count==0
}
接住{
返回错误
}
}
}
谢谢您的建议!我还发现,还有其他方法可以更干净地做到这一点。我将编辑我的答案。