沙盒:每个iOS程序都有一个
独立的文件系统
(存储空间),而且只能在对应的文件系统中进行操作,此区域被称为沙盒
// 获取沙盒根目录路径
NSString *homeDir = NSHomeDirectory();
// 获取Documents目录路径
// 第二个参数:
// NSSearchPathDomainMask 表示“想要从哪个路径区域保护区查找”
// NSUserDomainMask 用户的主目录
// NSLocalDomainMask 当前机器的本地目录
// NSNetworkDomainMask 在网络中公开可用的位置
// NSSystemDomainMask 被苹果系统提供的,不可更改的位置 (/System)
// NSAllDomainsMask 上述所有及未来的位置
// 第三个参数:
// BOOL expandTilde 表示:是否用波浪线显示部分目录路径
/// YES结果
/// Users/XXX/Library/Developer/CoreSimulator/Devices/A34416C2-C536-4263-9928-40B19A4EA2FF/data/Containers/Data/Application/CB431402-2A6D-4F71-88B9-854AEB46F0F6/Documents
/// NO结果
/// ~/Documents
NSString *docDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// 获取Library目录路径
NSString *libDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
// 获取cache路径
NSString *cachesDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// 获取tmp路径
NSString *tmpDir = NSTemporaryDirectory();
// 获取应用程序程序包资源文件路径
NSString *bundle = [[NSBundle mainBundle] bundlePath];
NSFileManger:
文件管理(单例类)
比如文件的创建、移动、复制
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, copy, readwrite) NSString *filePath;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 文件路径
self.filePath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
self.filePath = [self.filePath stringByAppendingPathComponent:@"text.txt"];
NSFileManager *fileManager = [NSFileManager defaultManager];
// 判断文件是否存在,并且判断是文件夹还是文件
BOOL isDirectory;
BOOL isExist = [fileManager fileExistsAtPath:self.filePath isDirectory:&isDirectory];
if (isExist) {
NSLog(@"文件存在");
if (isDirectory) {
NSLog(@"是文件夹路基");
}else{
NSLog(@"是文件");
}
}
else{
NSLog(@"给定的路径不存在");
}
// 判断文件是否可读取
BOOL isReadAble = [fileManager isReadableFileAtPath:self.filePath];
if (isReadAble) {
NSLog(@"文件可读取");
}
else{
NSLog(@"文件不可读取");
}
// 判断文件是否可以写入
BOOL isWriteAble = [fileManager isWritableFileAtPath:self.filePath];
if (isWriteAble) {
NSLog(@"文件可写入");
}
else{
NSLog(@"文件不可以写入");
}
// 判断文件是否可以删除
BOOL isDeleteAble = [fileManager isDeletableFileAtPath:self.filePath];
if (isDeleteAble) {
NSLog(@"文件可以删除");
}
else{
NSLog(@"文件不可删除");
}
// 获取文件信息
NSError *error = nil;
NSDictionary *fileInfo = [fileManager attributesOfItemAtPath:self.filePath error:&error];
/**
NSFileCreationDate = "2020-04-24 08:24:56 +0000";
NSFileExtendedAttributes = {
"com.apple.lastuseddate#PS" = {length = 16, bytes = 0xa3a3a25e00000000be43631a00000000};
};
NSFileExtensionHidden = 0;
NSFileGroupOwnerAccountID = 20;
NSFileGroupOwnerAccountName = staff;
NSFileModificationDate = "2020-04-26 01:50:22 +0000";
NSFileOwnerAccountID = 501;
NSFilePosixPermissions = 420;
NSFileReferenceCount = 1;
NSFileSize = 89;
NSFileSystemFileNumber = 4363464572;
NSFileSystemNumber = 16777220;
NSFileType = NSFileTypeRegular;
*/
NSLog(@"文件大小:%@",fileInfo[NSFileSize]);
// 获取指定目录下所有目录(列出目录下的所有文件或文件夹名称,以及文件夹内部文件的路径)
NSString *fileDocument = [[self.filePath stringByDeletingLastPathComponent] stringByDeletingLastPathComponent];
NSArray *subs = [fileManager subpathsAtPath:fileDocument];
for (NSString *subPath in subs) {
NSLog(@"%@",subPath);
}
// 获取指定目录下(所有的文件或文件夹名称)
NSArray *children = [fileManager contentsOfDirectoryAtPath:fileDocument error:&error];
for (NSString *subPath in children) {
NSLog(@"=== %@",subPath);
}
// 在指定目录下创建文件
NSData *saveData = [@"2020年04月24日" dataUsingEncoding:NSUTF8StringEncoding];
NSFileManager *fileManger = [NSFileManager defaultManager];
// saveData 是创建文件时,写入的内容
// 如果文件已经存在了,则将文件覆盖
BOOL isFile = [fileManger createFileAtPath:self.filePath contents:saveData attributes:nil];
if (!isFile) {
NSLog(@"创建失败");
return;
}
// 这种写法,是将文件内容覆盖写入
NSData *newData = [@"星期日,天气晴" dataUsingEncoding:NSUTF8StringEncoding];
[newData writeToFile:self.filePath atomically:YES];
// 在指定的目录创建文件夹
// withIntermediateDirectories
// 参数说明:如果YES,代表路径下如果是没有的文件夹,则会自动创建,如果是NO,则不会,遇到不存在的则,停止创建
// 比如下面路径中cache这个目录是不存在的,则会运行失败
// 注意:
// 传入的路径,是指定的文件夹路径,而不是文件的路径,否则在创建的时候,也会将文件当文件夹创建处理
NSString *newFilePath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
newFilePath = [newFilePath stringByAppendingPathComponent:@"cache"];
BOOL isCreateSuccess = [fileManager createDirectoryAtPath:newFilePath withIntermediateDirectories:YES attributes:nil error:&error];
if (isCreateSuccess) {
NSLog(@"文件创建成功");
}
else{
NSLog(@"文件创建失败,原因:%@",error);
}
// 移动文件
// 注意:
// 1.移动到目标目录的时候,如果文件已经存在,则会直接失败
// 2.目标目录必须是文件,路径结尾为文件名结尾(所以更多的是文件的移动,不是文件夹的移动)
NSString *targetFilePath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
targetFilePath = [targetFilePath stringByAppendingPathComponent:@"text.txt"];
NSString *moveFilePath = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES).firstObject;
moveFilePath = [moveFilePath stringByAppendingPathComponent:@"text.txt"];
BOOL isMoveSuccess = [fileManager moveItemAtPath:targetFilePath toPath:moveFilePath error:&error];
if (isMoveSuccess) {
NSLog(@"文件移动成功");
}
else{
NSLog(@"文件移动失败,失败原因:%@",error);
}
// 复制文件
// 注意:
// 1.复制到目标目录的时候,如果文件已经存在,则会直接失败
// 2.目标目录必须是文件,路径结尾为文件名结尾(所以更多的是文件的复制,不是文件夹的复制)
BOOL isCopySuccess = [fileManager copyItemAtPath:moveFilePath toPath:targetFilePath error:&error];
if (isCopySuccess) {
NSLog(@"文件复制成功");
}
else{
NSLog(@"文件复制失败 失败原因:%@",error);
}
// 删除文件
// 目标路径可以是文件或者文件夹
BOOL isDeleteSuccess = [fileManager removeItemAtPath:moveFilePath error:&error];
if (isDeleteSuccess) {
NSLog(@"文件删除成功");
}
else{
NSLog(@"文件删除失败,失败原因:%@",error);
}
}
@end
NSFileHandle:文件
内容
管理
比如文件内容的读取、写入、清空
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, copy, readwrite) NSString *filePath;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 文件路径
self.filePath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
self.filePath = [self.filePath stringByAppendingPathComponent:@"text.txt"];
// 创建写入的数据
// NSData *saveData = [@"2020年04月24日" dataUsingEncoding:NSUTF8StringEncoding];
// NSFileManager *fileManger = [NSFileManager defaultManager];
// BOOL isFile = [fileManger createFileAtPath:self.filePath contents:saveData attributes:nil];
// if (!isFile) {
// NSLog(@"创建失败");
// return;
// }
// 读文件
// [self createReadingFileHandle];
// 写文件
// [self createWritingFileHandle];
// 更新文件
// [self createUpdatingFileHandle];
// 文件操作通知
// [self notifitionFileHandle];
}
/// 创建“读”操作
/// 备注:读的操作就不能进行写的操作
/// 结论:
/// 读取文件数据
- (void)createReadingFileHandle {
// 打开文件准备读取(默认:文件的操作位置从“0”开始)
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:self.filePath];
// 按长度读取数据(文件的操作位置相应的也会发生改变,变成在"3"的位置)
[self logWithData:[fileHandle readDataOfLength:3]];
// 读取文件内容 (读取当前的操作位置到文件的最后,操作位置相应的也移动到“最后”)
[self logWithData:[fileHandle readDataToEndOfFile]];
// 可获取的数据(与readDataToEndOfFile方法的效果相同)
// availableData方法也是会将当前的文件操作位置,至于文件末尾
// 可以在文件操作位置为0的时候,求出文件的长度 [[fileHandle availableData] length]
[self logWithData:[fileHandle availableData]];
// 当前的文件的操作位置
NSLog(@"%llu",[fileHandle offsetInFile]);
// 修改文件的操作位置
[fileHandle seekToEndOfFile];
[fileHandle seekToFileOffset:3];
// 同步文件
[fileHandle synchronizeFile];
// 关闭文件(关闭文件后就不能对文件进行任何的操作,否则会闪退)
[fileHandle closeFile];
}
/// 创建“写”操作
/// 相同道理,写操作就不能j进行读的相关操作
/// 结论:
/// 1.writing操作适合将文件清空或者截取文件内容
/// 2.如果原来的文件操作位置有内容,则会覆盖写入
/// 比如:原来内容是0123456789,文件操作位置是2,写入222,最终的结果是0122256789
/// 特别注意一个ut8的中文字符是占3个字节,所以修改操作偏移量的时候要注意,否则文件会报错
/// 比如原来的内容是好,文件操作位置设置为1,写入222后,文件会出现编码错误,这时操作偏移量必须设置为3才能写入成功
- (void)createWritingFileHandle {
NSFileHandle *readFileHandle = [NSFileHandle fileHandleForReadingAtPath:self.filePath];
// 打开并写入(默认的文件操作位置是从文件“末尾”开始的)
// 由fileHandleForWritingAtPath创建的NSFileHandled对象,在写入数据是“覆盖”不是“增加”
NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingAtPath:self.filePath];
// 设置写入文件的大小(
// 如果在文件写入前设置的truncateFileAtOffset,如果设置的数字小于要写入的文件长度,则后期再获取文件的内容为空
// 文件字节截取到offset的位置(与当前文件的操作位置offset的值无关,都是从0开始截取的)
// 如果offset为0,则是将文件清空,可供填写
[fileHandle truncateFileAtOffset:3];
// 写入数据
NSLog(@"%llu",[fileHandle offsetInFile]);
[fileHandle writeData:[self createDataWithString:@"很久很久以前,有一个小男孩"]];
NSLog(@"%llu",[fileHandle offsetInFile]);
[fileHandle writeData:[self createDataWithString:@",叫做小明"]];
NSLog(@"%llu",[fileHandle offsetInFile]);
[fileHandle writeData:[self createDataWithString:@"123456"]];
NSLog(@"%llu",[fileHandle offsetInFile]);
[fileHandle synchronizeFile];
[fileHandle closeFile];
[readFileHandle seekToFileOffset:0];
[self logWithData:[readFileHandle readDataToEndOfFile]];
}
/// 文件更新
/// 结论:
/// 1.update操作可以替代read操作
/// 2.可以通过seek操作更改操作位置,插入数据
- (void)createUpdatingFileHandle {
// 打开并更新
NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:self.filePath];
[self logWithData:[fileHandle availableData]];
[fileHandle seekToEndOfFile];
// 写入数据(在文件操作位置插入数据)
[fileHandle writeData:[self createDataWithString:@",他有一个美好的家庭"]];
[fileHandle seekToFileOffset:0];
[self logWithData:[fileHandle availableData]];
[fileHandle synchronizeFile];
[fileHandle closeFile];
}
/// 文件读到最后完成
- (void)notifitionFileHandle {
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:self.filePath];
// 文件读到最后
[fileHandle readToEndOfFileInBackgroundAndNotify];
// 文件读操作
[fileHandle readInBackgroundAndNotify];
// 文件检测到有可用数据时候发起通知
[fileHandle waitForDataInBackgroundAndNotify];
[self logWithData:[fileHandle readDataOfLength:12]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(readToEndNotification:) name:NSFileHandleReadToEndOfFileCompletionNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(readCompletionNotification:) name:NSFileHandleReadCompletionNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dataAvailableNotification:) name:NSFileHandleReadCompletionNotification object:nil];
}
- (void)readToEndNotification:(NSNotification *)notification {
NSLog(@"文件读到最后了");
}
- (void)readCompletionNotification:(NSNotification *)notification {
NSLog(@"文件读操作完成");
}
- (void)dataAvailableNotification:(NSNotification *)notification {
NSLog(@"有可用数据");
}
- (NSData *)createDataWithString:(NSString *)string {
return [string dataUsingEncoding:NSUTF8StringEncoding];
}
- (void)logWithData:(NSData *)data {
NSLog(@"%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
}
@end