内容简介:级别: ★★☆☆☆标签:「iOS 文件操作」「SandBox」「QiFileManager」作者:dac_1033
级别: ★★☆☆☆
标签:「iOS 文件操作」「SandBox」「QiFileManager」
作者:dac_1033
审校:QiShare团队
在iOS开发过程中,网络出错没有返回正确数据时有发生,这时可以读取本地数据展示给用户来优化用户体验,并且在网络请求正常时及时更新这些本地数据,这些本地数据一般都存在沙盒目录的文件中,下面我们就来简单介绍一下iOS开发中的文件操作。 附:苹果官方文件系统编程指南。
一、 关于iOS文件系统
1.1 沙盒(SandBox)
iOS中每个app都有个独立、封闭、安全的目录,叫做沙盒,它一般存放着程序包文件(可执行文件)、图片、音频、视频、 plist
文件、 SQLite
数据库以及其他文件。每个app的沙盒都是独立的,应用程序之间是不可以直接互相访问的。苹果官网将沙盒结构划分为三类( Bundle Container
、 Data Container
、 iClound Container
),如下图:
上图中的沙盒结构其实是与小编的理解有出入的,具体的沙盒结构我们暂且不做研究。在开发iOS应用程序过程中,我们只能看到沙盒中的根目录及默认生成的三个文件夹 Documents
、 Library
和 Tmp
,这些才是我们关注的重点, 关于常用目录的描述如下:
目录 | 描述 |
---|---|
AppName.app | 应用程序的程序包目录,包含应用程序的本身。由于应用程序必须经过签名,所以不能在运行时对这个目录中的内容进行修改,否则会导致应用程序无法启动。 |
Documents/ | 保存应用程序的重要数据文件和用户数据文件等。用户数据基本上都放在这个位置(例如从网上下载的图片或音乐文件),该文件夹在应用程序更新时会自动备份,在连接iTunes时也可以自动同步备份其中的数据; 该目录的内容被iTunes和iCloud备份。 |
Library/ | 这个目录下有两个子目录,可创建子文件夹。可以用来放置您希望被备份但不希望被用户看到的数据。该路径下的文件夹,除Caches以外,都会被iTunes备份; 该目录的内容被iTunes和iCloud备份 |
Library/Caches | 保存应用程序使用时产生的支持文件和缓存文件(保存应用程序再次启动过程中需要的信息),还有日志文件最好也放在这个目录; iTunes 不会备份该目录,并且该目录下数据可能被其他 工具 清理掉。 |
Library/Preferences | 保存应用程序的偏好设置文件。NSUserDefaults类创建的数据和plist文件都放在这里; 该目录的内容被iTunes和iCloud备份。 |
Tmp/ | 使用此目录可以编写在应用程序启动之间不需要保留的临时文件,您的应用程序应在不再需要时删除此目录中的文件,但是,当您的应用未运行时,系统可能会清除此目录; iTunes或iCloud不会备份此目录下的内容。 |
1.2 获取沙盒目录
- (void)testSandBoxDirectory { // 获取app沙盒的根目录(home) NSString *homePath = NSHomeDirectory(); NSLog(@"NSHomeDirectory: %@", homePath); // 获取temp路径 NSString *tmp = NSTemporaryDirectory( ); NSLog(@"NSTemporaryDirectory: %@", tmp); // 获取Document目录 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *docPath = [paths lastObject]; NSLog(@"NSDocumentDirectory: %@", docPath); // 获取Library目录 paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); NSString *libPath = [paths lastObject]; NSLog(@"NSLibraryDirectory: %@", libPath); // 获取Library中的Cache paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *cachesPath = [paths lastObject]; NSLog(@"NSCachesDirectory: %@", cachesPath); } 复制代码
1.3 常用的路径处理方法
系统在类 NSPathUtilities
中实现了对NSString的扩展NSString ( NSStringPathExtensions
),其中定义了很多方法专门用于处理路径:
- (NSArray *)pathComponents; - (NSString *)lastPathComponent; - (NSString *)stringByDeletingLastPathCpmponent; - (NSString *)stringByAppendingPathConmponent:(NSString *)str; - (NSString *)pathExtension; - (NSString *)stringByDeletingPathExtension; - (NSString *)stringByAppendingPathExtension:(NSString *)str; 复制代码
1.4 iOS工程中的NSBundle
如图,我们自己在工程中创建了一个 Test.bundle
, bundle
是一个目录,其中包含程序会使用到的资源(如图像、声音、代码文件、 nib
文件等)。在系统中app本身和其他文件没有什么区别,app包中实际上包含了 nib
文件、编译连接过的代码和其他资源的目录,我们把app包这个目录叫做该app的 main bundle
。在iOS开发中可以使用NSBundle类来操作bundle及其中的资源。 NSBundle的官方文档描述
使用NSBundle的示例代码如下:
// 获取main bundle NSBundle *mainBundle = [NSBundle mainBundle]; // 放在app mainBundle中的自定义Test.bundle NSString *testBundlePath = [mainBundle pathForResource:@"Test" ofType:@"bundle"]; NSBundle *testBundle = [NSBundle bundleWithPath:testBundlePath]; // 获取Test.bundle中资源 NSString *resPath = [testBundle pathForResource:@"sound02" ofType:@"wav"]; NSLog(@"自定义bundle中资源的路径: %@", resPath); // 直接根据目录获取资源 UIImage *img = [UIImage imageNamed:[NSString stringWithFormat:@"Test.bundle/%@", @"logo_img_02"]]; NSLog(@"自定义bundle中图片: %@", img); 复制代码
二、文件操作
2.1 文件路径及文件
// 获取沙盒根路径 + (NSString *)getHomePath { return NSHomeDirectory(); } // 获取tmp路径 + (NSString *)getTmpPath { return NSTemporaryDirectory(); } // 获取Documents路径 + (NSString *)getDocumentsPath { NSArray *pathArr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *path = [pathArr firstObject]; return path; } // 获取Library路径 + (NSString *)getLibraryPath { NSArray *pathArr = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); NSString *path = [pathArr firstObject]; return path; } // 获取LibraryCache路径 + (NSString *)getLibraryCachePath { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *path = [paths firstObject]; return path; } // 检查文件、文件夹是否存在 + (BOOL)fileExistsAtPath:(NSString *)path isDirectory:(BOOL *)isDir { NSFileManager *fileManager = [NSFileManager defaultManager]; BOOL exist = [fileManager fileExistsAtPath:path isDirectory:isDir]; return exist; } // 创建路径 + (void)createDirectory:(NSString *)path { NSFileManager *fileManager = [NSFileManager defaultManager]; BOOL isDir; BOOL exist = [fileManager fileExistsAtPath:path isDirectory:&isDir]; if (!isDir) { [fileManager removeItemAtPath:path error:nil]; exist = NO; } if (!exist) { // 注:直接创建不会覆盖原文件夹 [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil]; } } // 创建文件 + (NSString *)createFile:(NSString *)filePath fileName:(NSString *)fileName { // 先创建路径 [self createDirectory:filePath]; // 再创建路径上的文件 NSFileManager *fileManager = [NSFileManager defaultManager]; NSString *path = [filePath stringByAppendingPathComponent:fileName]; BOOL isDir; BOOL exist = [fileManager fileExistsAtPath:path isDirectory:&isDir]; if (isDir) { [fileManager removeItemAtPath:path error:nil]; exist = NO; } if (!exist) { // 注:直接创建会被覆盖原文件 [fileManager createFileAtPath:path contents:nil attributes:nil]; } return path; } // 复制 文件or文件夹 + (void)copyItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath { NSFileManager *fileManager = [NSFileManager defaultManager]; NSError *error; BOOL result = [fileManager copyItemAtPath:srcPath toPath:dstPath error:&error]; if (!result && error) { NSLog(@"copyItem Err : %@", error.description); } } // 移动 文件or文件夹 + (void)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath { NSFileManager *fileManager = [NSFileManager defaultManager]; NSError *error; BOOL result = [fileManager moveItemAtPath:srcPath toPath:dstPath error:&error]; if (!result && error) { NSLog(@"moveItem Err : %@", error.description); } } // 删除 文件or文件夹 + (void)removeItemAtPath:(NSString *)path { NSFileManager *fileManager = [NSFileManager defaultManager]; NSError *error; BOOL result = [fileManager removeItemAtPath:path error:&error]; if (!result && error) { NSLog(@"removeItem Err : %@", error.description); } } // 获取目录下所有内容 + (NSArray *)getContentsOfDirectoryAtPath:(NSString *)docPath { NSFileManager *fileManager = [NSFileManager defaultManager]; NSError *error; NSArray *contentArr = [fileManager contentsOfDirectoryAtPath:docPath error:&error]; if (!contentArr.count && error) { NSLog(@"ContentsOfDirectory Err : %@", error.description); } return contentArr; } 复制代码
2.2 能直接进行文件读写的数据类型
iOS中有四种简单类型能够直接进行文件读写:字符串 NSString
/ NSMutableString
、数组 NSArray
/ NSMutableArray
、字典 NSDictionary
/ NSMutableDictionary
、二进制数据 NSData
/ NSMutableData
。
代码示例如下:
NSString *string = @"QiShare test string ..."; [string writeToFile:path11 atomically:YES encoding:NSUTF8StringEncoding error:nil]; NSString *readStr = [NSString stringWithContentsOfFile:path11 encoding:NSUTF8StringEncoding error:nil]; NSLog(@"读取文件-字符串: %@", readStr); NSArray *array = @[@"Q", @"i", @"S", @"h", @"a", @"r", @"e"]; [array writeToFile:path33 atomically:YES]; NSArray *readArr = [NSArray arrayWithContentsOfFile:path33]; NSLog(@"读取文件-数组: %@", readArr); NSDictionary *dict = @{@"en":@"QiShare", @"ch":[[FileUtil alloc] init]}; [dict writeToFile:path34 atomically:YES]; NSDictionary *readDict = [NSDictionary dictionaryWithContentsOfFile:path34]; NSLog(@"读取文件-字典: %@", readDict); NSData *data = [@"QiShare test data ..." dataUsingEncoding:NSUTF8StringEncoding]; [data writeToFile:path11 atomically:YES]; NSData *readData = [NSData dataWithContentsOfFile:path11]; NSLog(@"读取文件-二进制: %@", readData); 复制代码
- 其中数组和字典中的元素对象的类型也必须是上述四种,否则不能直接写入文件;
- 每次调用writeToFile:方法写入文件时,都会覆盖文件原有内容。
三、文件内容操作
iOS开发在涉及到文件操作的过程中,进行一些细粒度的文件内容操作时会用到NSFileHandle。一般用NSFileHandle修改文件内容有三个步骤:打开文件,获取一个NSFileHandle对象;对打开文件执行相关操作;关闭文件。NSFileHandle具体功能概括如下:
- 打开一个文件,执行读、写或更新操作;
- 在文件中查找指定位置;
- 从文件中读取特定数目的字节,或将特定数目的字节写入文件中;
- NSFileHandle类提供的方法也可以用于各种设备或套接字。
用 NSFileHandle
操作文件内容示例代码如下:
// NSFileHandle操作文件内容 - (void)testFileHandle { NSString *docPath = [FileUtil getDocumentsPath]; NSString *readPath = [docPath stringByAppendingPathComponent:@"read.txt"]; NSString *writePath = [docPath stringByAppendingPathComponent:@"write.txt"]; NSData *data = [@"abcdefghijklmnopqrstuvwxyz" dataUsingEncoding:NSUTF8StringEncoding]; NSFileManager *manager=[NSFileManager defaultManager]; [manager createFileAtPath:readPath contents:data attributes:nil]; [manager createFileAtPath:writePath contents:nil attributes:nil]; [data writeToFile:readPath atomically:YES]; // 打开文件 读 NSFileHandle *readHandle = [NSFileHandle fileHandleForReadingAtPath:readPath]; NSData *readData = [readHandle readDataToEndOfFile]; // 读取文件中指定位置/指定长度的内容 [readHandle seekToFileOffset:10]; readData = [readHandle readDataToEndOfFile]; NSLog(@"seekToFileOffset:10 = %@", [[NSString alloc] initWithData:readData encoding:NSUTF8StringEncoding]); [readHandle seekToFileOffset:10]; readData = [readHandle readDataOfLength:5]; NSLog(@"seekToFileOffset:10 = %@",[[NSString alloc]initWithData:readData encoding:NSUTF8StringEncoding]); [readHandle closeFile]; // 打开文件 写 NSFileHandle *writeHandle = [NSFileHandle fileHandleForWritingAtPath:writePath]; // 注:直接覆盖文件原有内容 [writeHandle writeData:data]; // 注:覆盖了指定位置/指定长度的内容 [writeHandle seekToFileOffset:2]; [writeHandle writeData:[@"CDEFG" dataUsingEncoding:NSUTF8StringEncoding]]; [writeHandle seekToEndOfFile]; [writeHandle writeData:[@"一二三四五六" dataUsingEncoding:NSUTF8StringEncoding]]; [writeHandle closeFile]; } 复制代码
工程源码地址: GitHub地址
关注我们的途径有:
QiShare(微信公众号)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 安卓文件存储/文件读写操作
- QT选择目录等常用文件/文件夹操作
- Go语言的文件操作:文件的读写,文件的新建打开和删除
- Go 文件操作详解
- 013.Python的文件操作
- Gradle学习(十六)——文件操作
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。