iOS开发之OC篇(6)——NSFileManager文件管理器

时间:2022-06-07 21:06:55

版本

Xcode 8.2.1

一、NSHomeDirectory()

“目录(Directories)在现在的操作系统里就是文件夹,而路径(Path)则是包括盘符及一个或多个文件夹。”
iOS每个APP都会有一个沙盒(Sandbox),用于存储该APP所产生的资料内容,如图片、视频、文件夹、plist文件等等。而这个沙盒的路径可由NSHomeDirectory()得到,也叫APP的根目录。根目录下有四个文件/文件夹:
iOS开发之OC篇(6)——NSFileManager文件管理器

  • Documents 目录:Apple官方建议将APP的重要数据保存到这个目录下。因为iTunes备份时包括此目录。
  • MyApp.app 目录:这是APP本身。一般不要对其更改,否则启动时容易崩溃。
  • Library 目录:该目录下有两个子目录:Preferences和Caches;
    • Preferences:包含APP的偏好设置。可用NSUserDefaults类来获取或设置;
    • Caches:APP专用的支持文件,保存APP再次启动过程中需要的信息。
  • tmp 目录:存放临时文件,APP关闭后,该目录下文件将被清除。

    接下来我们小试一把,通过NSHomeDirectory()获取APP的根目录,并对其目录路径搞点小动作。

int main(int argc, char * argv[]) {

//获取根目录
NSString *userPath = NSHomeDirectory();
NSLog(@"path = %@",userPath);

//拼接路径
NSString *newPath = [userPath stringByAppendingFormat:@"%@",@"/test"];
NSLog(@"newPath = %@",newPath);

//添加子路径
NSString *newPath2 = [userPath stringByAppendingPathComponent:@"test"];
NSLog(@"newPath2 = %@",newPath2);

//切割路径x
NSArray *resultPath = [userPath pathComponents];
NSLog(@"resultPath = %@",resultPath);

//再次拼接路径
NSString *newPath1 = [userPath stringByAppendingFormat:@"%@",@"/test/lalala.jpg"];
NSLog(@"newPath1 = %@",newPath1);

//获取文件后缀名
NSString *resultStr = [newPath1 pathExtension];
NSLog(@"resultStr = %@",resultStr);

//删除后缀名
NSString *resultPath1 = [newPath1 stringByDeletingPathExtension];
NSLog(@"resultPath1 = %@",resultPath1);

//删除最后一个子路径
NSString *resultPath2 = [newPath1 stringByDeletingLastPathComponent];
NSLog(@"resultPath2 = %@",resultPath2);
}

收获如下:
iOS开发之OC篇(6)——NSFileManager文件管理器

获取目录路径的方法小结:

//获取根目录
NSString *HomeDir = NSHomeDirectory();

//获取Documents目录
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex:0];

//获取Caches目录
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDir = [paths objectAtIndex:0];

//获取tmp目录
NSString *tmpDir = NSTemporaryDirectory();

//获取APP程序包中资源文件路径(例如图片picture.png)
//mainBundle类方法用于返回本身应用程序包(***.app)的对象。
NSString *imgPath = [[NSBundle mainBundle] pathForResource:@”picture” ofType:@”png”];
UIImage *pictureImg = [[UIImage alloc] initWithContentsOfFile:imgPath];

二、NSFileManager

对于这些文件路径的操作(移动、复制、连接或者删除等等),往往会很杂乱,有时甚至会操作出错。Apple为我们提供一个类,用于管理这些文件(路径),是为——NSFileManager文件管理器。
NSFileManager类支持NSString和NSURL(往后再介绍)作为文件路径。它还拥有一个代理协议NSFileManagerDelegate用来接收各种文件操作的通知,典型功用是当错误发生时可决定是否继续。NSFileManager可以在多个线程中安全调用,但问题是,如果创建了不一样的NSFileManager实例对象,那么代理方法由谁来实现?别担心,苹果早就想好了——NSFileManager类的实例对象为单例。所谓单例,即,不管你用这个类创建了多少个实例对象,这些对象实际上都是同一个(名称虽不同,指针却一样)!下面举例论证:

int main(int argc, char * argv[]) {
//获取文件管理器,单例对象:在整个应用程序当中,只会实例化一个这种类型的对象
NSFileManager *manager = [NSFileManager defaultManager];
NSLog(@"manager指针:%p",manager);
//manager和manager1指针一样,指向同一个对象
NSFileManager *manager1 = [NSFileManager defaultManager];
NSLog(@"manager1指针:%p",manager1);
}

iOS开发之OC篇(6)——NSFileManager文件管理器

前面介绍了获取APP本身的一些目录,下面为了方便查看结果,拷贝操作部分,我们将对桌面目录试验NSFileManager。先在桌面放置一个plist文件,然后右键点“显示简介”,在“位置”那里得到路径。续上代码:

int main(int argc, char * argv[]) {
//获取文件管理器,单例对象:在整个应用程序当中,只会实例化一个这种类型的对象
NSFileManager *manager = [NSFileManager defaultManager];
NSLog(@"manager指针:%p",manager);
//manager和manager1指针一样,指向同一个对象
NSFileManager *manager1 = [NSFileManager defaultManager];
NSLog(@"manager1指针:%p",manager1);

//获取tmp目录
NSString *TmpDir = NSTemporaryDirectory();
//拼接路径
NSString *TestDir = [TmpDir stringByAppendingFormat:@"%@",@"/test"];
//fileExistsAtPath判断此路径是否已经存在
if(![manager fileExistsAtPath:TestDir]) {
//先声明一个NSError指针
NSError *error = nil;
//创建目录----createDirectoryAtPath
[manager createDirectoryAtPath:TestDir //参数1: 创建的目录路径
withIntermediateDirectories:YES //参数2: 是否自动添加缺失的路径
attributes:nil //参数3: 创建文件的附带信息,一般为nil
error:&error]; //参数4: 错误信息;二级指针
//如果存在error,就打印错误信息
if(error) {
NSLog(@"error = %@",error);
}
}

//浅层遍历(遍历根目录第一层文件和文件夹)
NSString *HomeDir = NSHomeDirectory();
NSArray *resultArray = [manager contentsOfDirectoryAtPath:HomeDir error:nil];
for(id obj in resultArray) {
NSLog(@"浅层遍历obj = %@",obj);
}

//深层遍历(遍历tmp路径下的所有文件夹和文件)
NSArray *resultArr1 = [manager subpathsOfDirectoryAtPath:HomeDir error:nil];
for(id obj1 in resultArr1) {
NSLog(@"深层遍历obj = %@",obj1);
}

//创建一个桌面文件夹test
NSString *desDir = @"/Users/tailor/Desktop/test";
if(![manager fileExistsAtPath:desDir]) {
NSError *error = nil;
[manager createDirectoryAtPath:desDir
withIntermediateDirectories:YES
attributes:nil
error:&error];
if(error) {
NSLog(@"error = %@",error);
}
}

//拷贝文件目录
NSString *srcPath = @"/Users/tailor/Desktop/Info.plist";
NSString *dstPath1 = @"/Users/tailor/Desktop/Info1.plist";
if(![manager copyItemAtPath:srcPath toPath:dstPath1 error:nil]) {
NSLog(@"拷贝失败");
}

//移动/剪切
NSString *dstPath2 = @"/Users/tailor/Desktop/test/Info2.plist"; //test必须存在,Info2.plist不存在(还没创建)
if(![manager moveItemAtPath:dstPath1 toPath:dstPath2 error:nil]) {
NSLog(@"移动失败");
}

//删除
if(![manager removeItemAtPath:srcPath error:nil]) {
NSLog(@"删除失败");
}
}

嘿嘿嘿:
iOS开发之OC篇(6)——NSFileManager文件管理器

对于copyItemAtPath: toPath:和moveItemAtPath: toPath:方法的一些操作,本人之前踩了许多坑,现在把它铺平。先来看看官方文档:

Discussion
If srcPath is a file, the method creates a file at dstPath that holds the exact contents of the original file (this includes BSD special files). If srcPath is a directory, the method creates a new directory at dstPath and recursively populates it with duplicates of the files and directories contained in srcPath, preserving all links. The file specified in srcPath must exist, while dstPath must not exist prior to the operation. When a file is being copied, the destination path must end in a filename—there is no implicit adoption of the source filename. Symbolic links are not traversed but are themselves copied. File or directory attributes—that is, metadata such as owner and group numbers, file permissions, and modification date—are also copied.

需要注意的信息有(无聊数了下有5个必须):

  1. 如果源路径(srcPath)是文件,则目标路径(dstPath)必须是文件(且后缀名一致);
  2. 如果源路径是文件夹,则目标路径必须是文件夹,将会复制源文件夹下所有文件(夹);
  3. 方法调用前,源路径必须存在,目标路径必须不存在(注意:目标文件不存在,但目标文件所在文件夹必须存在);
  4. 方法的一些错误提示等。