第七章、文件I/O

本章主要介绍Objective-C输入/输出(简称I/O或O/I)的相关知识。
Objective-C提供了如下相关API:
本章包括:
    NSFileManager进行管理文件和目录,包括创建、删除、移动、修改和复制文件。
    NSFileHandle进行处理读取文件内容,
    NSUrl进行读取网络资源;
    NSBundle进行读取项目内部资源;

一、使用NSData与NDMutableData

Foundation提供了NSData和NSMutableData,他们代表Objective-C的数据缓冲区。NSData的作用有两个:

  • ①、对数据读取NSData;
  • ②、输出NSData的数据;

NSData的初始化方法:

  • (1)、data创建一个不包含任何数据的、空的NSData对象;
  • (2)、dataWithBytes:length:/initWithBytes:length:复制C数组所包含的数据来初始化NSData的数据;
  • (3)、dataWithBytesNoCopy:length:/initWithBytesNoCopy:length:直接利用C数组所包含的数据来初始化NSData对象。当该对象被执行malloc方法释放自己时,程序会释放该C数组;
  • (4)、dataWithBytesNoCopy:length:freeWhenDone:/initWithBytesNoCopy:length:freeWhenDone:直接利用C数组所包含的数据来初始化NSData对象,只有当最后一个参数为YES,且该对象执行malloc方法销毁自己时,程序才会是释放该C数组;
  • (5)、dataWithContentsOfFile:/initWithContentsOfFile:直接读取文件内容,并利用文件内容来初始化NSData;
  • (6)、dataWithContentsOfURL:/initWithContentsOfURL:直接读取URL关联的内容,并利用文件内容来初始化NSData;
  • (7)、dataWithData:/initWithData:直接使用另一个NSData所包含的数据来初始化新创建的数据。

得到NSData对象之后,可以调用如下方法来访问数据:

  • (1)、bytes返回该NSData所包含的数据;
  • (2)、getBytes:length:获取NSData所包含的指定长度的数据;
  • (3)、getBytes:range:获取NSData所包含的指定范围的数据;
  • (4)、subdataWithRange:获取NSData所包含的指定范围的数据组- 成的NSData对象;
  • (5)、writeToFile:atomically:将NSData的数据写入文件;
  • (6)、writeToUrl:atomically:将NSData的数据写入指定URL的资源;

例如:

(1)、使用指定URL对应的数据初始化NSData

//使用NSData读取指定URL对应的数据
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.crazyit.org/ethos.php"]];

(2)、求得NSData的长度

NSLog(@"%ld",[data length]);//
//定义一个长度为100的数组
char buffer[100];

(3)、将指定范围的数据写入数组

//将NSData指定范围的数据写入数组
[data getBytes:buffer range:NSMakeRange(103, 100)];
//输出数组的内容
NSLog(@"%s",buffer);
/*
 输出:
 transitional.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
 <meta http-equiv="Content-T…
 */

(4)、将NSData转化成NSString

//直接将NSData的数据用UTF-8的格式转化成字符串
NSString* content = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"网页内容为:%@",content);

二、使用NSFileManager管理文件和目录

NSFileManager代表文件管理器,通过NSFileManager的帮助,开发者可以完成许多通用的文件操作。当开发者使用NSFileManager执行移动、复制、链接、删除文件或目录时,程序可以为NSFileManager提供一个配套的事件委托(实现了NSFileManagerDelegate协议的对象)。
NSFileManager采用文件作为文件的唯一标识,每个文件都是一个普通的NSString对象,它即可使用相对路径,也可以是绝对路径。

  • (1)、相对路径:不以斜线开头的路径都是相对路径。比如:abc.m、codes/Test.m。
  • (2)、绝对路径:以斜线(代表根路径)开头的路径就是绝对路径。绝对路径是唯一的,他代表的文件或目录总是固定的,比如:/Users/abc。

除此之外,还有几个比较特殊的路径:

  • (1)、~:代表当前用户的Home目录。比如当前用户为abc,那么“~”就代表/Users/abc;还可以写成~xyz,它代表xyz用户的Home目录,即/Users/xyz。
  • (2)、.:代表当前路径。
  • (3)、..:代表当前目录的上一级目录。

1、访问文件属性和内容

NSFileManager为访问文件属性和内容提供了如下方法:

  • (1)、fileExistsAtPath::判断指定文件名对应的文件是否存在。
  • (2)、fileExistsAtPath:isDirectory::判断该指定文件名对应的文件或目录是否存在,该方法的后一个参数可用于返回该文件名是否为目录。
  • (3)、isReadableFileAtPath::判断指定目录下的文件是否可读。
  • (4)、isWritableFileAtPath::判断指定目录下的文件是否可写。
  • (5)、isExecutableFileAtPath::判断指定目录下的文件是否可执行。
  • (6)、isDeletableFileAtPath::判断指定目录下的文件是否可删除。
  • (7)、componentsToDisplayForPath::获取指定文件名对应文件的各个路径组件。
  • (8)、displayNameAtPath::获取指定文件问对应文件的简单文件名。
  • (9)、attributesOfItemAtPath:error::获取指定文件名对应文件的属性。
  • (10)、attributesOfFileSystemForPath:error::获取指定文件名对应文件所在文件系统的属性
  • (11)、setAttributes:ofItemAtPath::设置指定文件名对应文件的属性。
  • (12)、contentsAtPath::获取指定文件名对应文件的内容。
  • (13)、contentsEqualAtPath:andPath::判断两个文件名指定的文件内容是否相同。

例如:

(1)、获取单例

//单例
NSFileManager* fm = [NSFileManager defaultManager];

(2)、是否存在

//将输出代表真的1
NSLog(@"mydict.txt是否存在:%d",[fm fileExistsAtPath:@"mydict.txt"]);//mydict.txt是否存在:1

(3)、是否存在且是否为目录

BOOL isDir;
NSLog(@"mydict.txt是否存在:%d",[fm fileExistsAtPath:@"mydict.txt" isDirectory:&isDir]);
//将会输出代表假的0
NSLog(@"mydict.txt是否为目录:%d",isDir);//mydict.txt是否为目录:0

(4)、是否可读

//将会输出代表真的1
NSLog(@"mydict.txt是否为可读文件:%d",[fm isReadableFileAtPath:@"mydict.txt"]);

(5)、是否可写

//将会输出代表真的1
NSLog(@"mydict.txt是否为可写文件:%d",[fm isWritableFileAtPath:@"mydict.txt"]);

(6)、是否可执行

//将会输出代表假的0
NSLog(@"mydict.txt是否为可执行文件:%d",[fm isExecutableFileAtPath:@"mydict.txt"]);

(7)、是否可删除

//将会输出代表真的1
NSLog(@"mydict.txt是否为可删除文件:%d",[fm isDeletableFileAtPath:@"mydict.txt"]);

(8)、获取路径组件

//获取mydict.txt文件所在的路径组件
NSArray* arrat = [fm componentsToDisplayForPath:@"mydict.txt"];
NSLog(@"--mydict.txt所在路径的完整路径组件为--");
for (NSObject* ele in arrat) {
    NSLog(@"%@",ele);
    /* 输出: Macintosh HD 用户 chenxiao 资源库 Developer Xcode DerivedData 重新学习-fvftebswkwfhovfdqhoyfjkqitbx Build Products Debug mydict.txt */
}

(9)、获取相关属性

//获取文件的相关属性
NSDictionary* attr = [fm attributesOfItemAtPath:@"mydict.txt" error:nil];
//获取文件属性的详情
NSLog(@"mydict.txt的创建时间为:%@",[attr fileCreationDate]);//mydict.txt的创建时间为:2014-12-08 07:37:03 +0000
NSLog(@"mydict.txt的属主账户为:%@",[attr fileOwnerAccountName]);//mydict.txt的属主账户为:chenxiao
NSLog(@"mydict.txt的文件大小为:%lld",[attr fileSize]);//mydict.txt的文件大小为:356

(10)、获取文件内容

//直接获取文件内容
NSData* data = [fm contentsAtPath:@"mydict.txt"];
//直接将NSData的数据用UTF-8的格式转换字符串
NSString* content = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"------输出文件内容------");
NSLog(@"%@",content);
/*
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
 <key>four</key>
 <string>Perl</string>
 <key>one</key>
 <string>Objective-C</string>
 <key>three</key>
 <string>Python</string>
 <key>two</key>
 <string>Ruby</string>
 </dict>
 </plist>
 */

2、创建、删除、移动、复制

NSFileManager为创建、删除、移动、复制文件或目录提供了如下方法:

  • (1)、createDirectoryAtUrl:withIntermediateDirectories:attributes:error::根据指定的URL创建目录;
  • (2)、createDirectoryAtPath:withIntermediateDirectories:attributes:error::根据指定的路径创建目录;
  • (3)、createFileAtPath:contents:attributes::根据指定的文件路径、内容创建文件;
  • (4)、removeItemAtUrl:error::删除指定URL对应的文件;
  • (5)、removeItemAtPath:error::删除指定路径对应的文件;
  • (6)、copyItemAtURL:toURL:error::根据指定的URL复制文件或目录;
  • (7)、copyItemAtPath:toPath:error::根据指定路径复制文件或目录;
  • (8)、moveItemAtURL:toURL:error::根据指定URL移动文件或目录;
  • (9)、moveItemAtPath:toPath:error::根据指定路径移动文件或目录。

例如:注意路径全是绝对路径

(1)、单例

NSFileManager* fm = [NSFileManager defaultManager];

(2)、创建目录

//创建目录
//第一个参数:文件路径
//第二个参数:如果父目录不存在,则创建父目录
//第三个参数:文件属性
[fm createDirectoryAtPath:@"/Users/chenxiao/Desktop/xyz/abc" withIntermediateDirectories:YES attributes:nil error:nil];
NSString* content = @"《疯狂iOS讲义》是我正在学习的图书";

(3)、创建文件

//创建一个文件
[fm createFileAtPath:@"/Users/chenxiao/Desktop/xyz/abc/myInfo.txt" contents:[content dataUsingEncoding:NSUTF8StringEncoding] attributes:nil];

(4)、获取文件属性

//获取文件属性
NSLog(@"myInfo.txt:%@",[fm attributesOfItemAtPath:@"/Users/chenxiao/Desktop/xyz/abc/myInfo.txt" error:nil]);
/*
 输出:
 myInfo.txt:
 {
 NSFileCreationDate = "2014-12-09 09:51:54 +0000";
 NSFileExtensionHidden = 0;
 NSFileGroupOwnerAccountID = 20;
 NSFileGroupOwnerAccountName = staff;
 NSFileHFSCreatorCode = 0;
 NSFileHFSTypeCode = 0;
 NSFileModificationDate = "2014-12-09 09:51:54 +0000";
 NSFileOwnerAccountID = 501;
 NSFileOwnerAccountName = chenxiao;
 NSFilePosixPermissions = 420;
 NSFileReferenceCount = 1;
 NSFileSize = 48;
 NSFileSystemFileNumber = 6150933;
 NSFileSystemNumber = 16777219;
 NSFileType = NSFileTypeRegular;
 }
 */

(5)、复制文件

//复制一份新文件
[fm copyItemAtPath:@"myInfo.txt" toPath:@"/Users/chenxiao/Desktop/xyz/abc/copyInfo.txt" error:nil];

(6)、删除文件

//删除文件
[fm removeItemAtPath:@"/Users/chenxiao/Desktop/xyz/abc/myInfo.txt" error:nil];

(7)、删除目录

//删除目录
[fm removeItemAtPath:@"/Users/chenxiao/Desktop/xyz" error:nil];

3、查看目录包含的内容

对于文件目录,NSFileManager提供了如下方法查看目录包含的内容

  • (1)、contentsOfDirectoryAtPath:error::获取指定目录下的所有文件和子目录。对于指定目录下的子目录该方法不会进行递归枚举;
  • (2)、enumeratorAtPath::获取指定目录下的所有文件和子目录对应的枚举器(NSDirectoryEnumerator对象)。如果指定目录下的文件是子目录,该方法默认会递归枚举子目录中所有的内容。当然,程序可调用NSDirectoryEnumerator方法的skipDescendants方法来组织递归枚举子目录。
  • (3)、subpathsOfDirectoryAtPath:error::递归获取指定路径包含的所有目录及子目录;
  • (4)、subpathsAtPath::与前一个方法的功能基本类似。

例如:

(1)、单例

NSFileManager* fm = [NSFileManager defaultManager];

(2)、获取指定目录下的文件夹 不递归子目录

//获取指定目录下的所有文件和文件夹
NSArray* array = [fm contentsOfDirectoryAtPath:@"/Users/chenxiao/Desktop/重新学习" error:nil];
for (NSString* item in array) {
    NSLog(@"%@",item);
    /* .DS_Store .git FDPersonTest.h FKPerson.h FKPerson.m FKPersonTest.m 重新学习 重新学习.xcodeproj */
}

(2)、获取指定目录下所有文件和文件夹的枚举器 递归子目录

//获取指定目录下所有文件和文件夹对应的枚举器
NSDirectoryEnumerator* dirEnum = [fm enumeratorAtPath:@"/Users/chenxiao/Desktop/重新学习"];
NSString* file;
while (file = [dirEnum nextObject]) {
    //如果该文件名以.m结尾
    if ([[file pathExtension] isEqualToString:@"m"]) {
        //直接获取文件内容
        NSData* data = [fm contentsAtPath:[NSString stringWithFormat:@"/Users/chenxiao/Desktop/重新学习/%@",file]];
        //直接将NSData的数据用UTF-8的格式转换字符串
        NSString* content = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"content = %@",content);
    }else{
        NSLog(@"%@",file);
    }

}

(3)、获取目录下的所有子目录,递归子目录

//获取当前目录下的所有子目录
NSArray* subArr = [fm subpathsOfDirectoryAtPath:@"/Users/chenxiao/Desktop/重新学习" error:nil];
NSArray* subarr = [fm subpathsAtPath:@"/Users/chenxiao/Desktop/重新学习"];
NSLog(@"%@==%@",subArr,subarr);

三、使用NSPathUtilities.h管理路径

NSPathUtilities.h包含了对NSString类的扩展,从而为NSString类新增了一些专门用于操作路径的方法:

  • (1)、+ (NSString )pathWithComponents:(NSArray )components;根据components中的元素构造有效的路径;
  • (2)、- (NSArray *)pathComponents;分拆路径,返回该路径中各部分所组成的数组;
  • (3)、- (BOOL)isAbsolutePath;返回该路径是否为绝对路径;
  • (4)、- (NSString *)lastPathComponent;提取该路径的最后一个组成部分;
  • (5)、- (NSString *)pathExtension;从路径的最后一个组成部分提取扩展名;
  • (6)、- (NSString *)stringByAbbreviatingWithTildeInPath;将路径中当前用户的home路径替换为~;将路径中指定当前用户的home路径替换为~user的形式;
  • (7)、- (NSString )stringByAppendingPathComponent:(NSString )str;将str添加到现有路径的结尾处;
  • (8)、- (NSString )stringByAppendingPathExtension:(NSString )str;将str扩展名添加到现有路径的结尾处;
  • (9)、- (NSString *)stringByDeletingLastPathComponent;删除路径的最后一个组成部分;
  • (10)、- (NSString *)stringByDeletingPathExtension;删除路径的最后一个组成部分的扩展名;
  • (11)、- (NSString *)stringByExpandingTildeInPath;将路径中的代字符(~或user)解析成当前用户的home目录或指定用户的home目录;
  • (12)、- (NSString *)stringByResolvingSymlinksInPath;解析路径中的符号链接,返回解析后的路径;
  • (13)、- (NSString *)stringByStandardizingPath;解析路径中的~、..、.和符号链接,返回解析后生成的标准路径;
    除此之外还有
  • (14)、NSString *NSUserName(void);返回当前用户名;
  • (15)、NSString *NSFullUserName(void);返回当前用户的完整用户名;
  • (16)、NSString *NSHomeDirectory(void);返回当前用户的home目录;
  • (17)、NSString *NSHomeDirectoryForUser(NSString *userName);返回指定用户的home目录;
  • (18)、NSString *NSTemporaryDirectory(void);返回系统的临时文件;
  • (19)、NSString *NSOpenStepRootDirectory(void);

例如:

(1)、获取当前用户

NSLog(@"当前用户名为:%@",NSUserName());//当前用户名为:chenxiao

(2)、获取当前用户完整用户名

NSLog(@"当前用户的完整用户名为:%@",NSFullUserName());//当前用户的完整用户名为:陈晓

(3)、获取当前用户的home目录

NSLog(@"当前用户的home目录为:%@",NSHomeDirectory());//当前用户的home目录为:/Users/chenxiao

(4)、获取root用户的home目录

NSLog(@"root用户的home目录为:%@",NSHomeDirectoryForUser(@"root"));//root用户的home目录为:/var/root

(5)、获取系统临时目录

NSLog(@"系统临时目录为:%@",NSTemporaryDirectory());//系统临时目录为:/var/folders/js/fsgm7wns4tq37pc2cfdqsp9w0000gn/T/

(6)、将~root解析成root用户的的home目录

NSString* path1 = @"~root";
//将~root解析成root用户的home目录
NSLog(@"解析~root的结果:%@",[path1 stringByExpandingTildeInPath]); //解析~root的结果:/var/root

(7)、替换成~的形式

NSString* path2 = @"/Users/chenxiao/publish";
//将会输出~/publish
NSLog(@"替换成~的形式:%@",[path2 stringByAbbreviatingWithTildeInPath]);//替换成~的形式:~/publish

(8)、遍历路径中包含的个路径组件

//遍历该路径中包含的各路径组件
NSArray* array = [path2 pathComponents];
for (NSString* item in array) {
    NSLog(@"%@",item);
    /* 输出: / Users chenxiao publish */
}

(9)、在路径后边追加一个路径

//在path2路径后追加一个路径
NSString* path3 = [path2 stringByAppendingPathComponent:@"abc.m"];
NSLog(@"path3为:%@",path3);//path3为:/Users/chenxiao/publish/abc.m

(10)、获取路径的最后部分

//获取路径的最后部分
NSString* last = [path3 lastPathComponent];
NSLog(@"path3的最后一个路径组件为:%@",last);//path3的最后一个路径组件为:abc.m

(11)、获取路径的最后部分的扩展名

//获取路径的最后部分的扩展名
NSLog(@"path3的最后一个路径的扩展名:%@",[path3 pathExtension]);//path3的最后一个路径的扩展名:m

四、使用ProcessInfo获取进度信息

当一个程序运行起来之后就变成了一个进程,NSProcessInfo对象则可用于获取该进程的相关信息,包括获取运行该程序的参数、进程标识符等。还可以获取该进程的主机名,操作系统名,操作系统版本等信息。
程序调用NSProcessInfo的processInfo类方法即可获取该进程对应的NSProcessInfo对象,接下来即可调用NSProcessInfo的如下方法来获取该进程,以及该进程所在系统的信息:

  • (1)、argument:该方法返回该程序所传入的参数组成的NSArray对象;
  • (2)、environment:该方法返回系统内所有环境变量名和值组成的NSDictionary对象;
  • (3)、processIdentifier:该方法返回该进程的标识符;
  • (4)、globallyUniqueString:该方法用于返回一个全局的、唯一的字符串;
  • (5)、processName:该方法返回该进程的进程名;
  • (6)、setProcessName:该方法用于设置进程的进程名;
  • (7)、hostName:该方法返回该进程所在系统的主机名;
  • (8)、operationSystem:该方法返回该进程所在系统的操作系统;
  • (9)、operatingSystemName:该方法返回该进程所在系统的操作系统名;
  • (10)、operationSystemVersionString:该方法返回该进程所在系统的操作系统版本号;
  • (11)、physicalMemory:该方法返回系统的物理内存;
  • (12)、activeProcessorCount:该方法返回系统中激活状态的处理器的数量;
  • (13)、systemUptime:该方法返回系统已运行的时间。

例如:

(1)、获取当前进程的ProcessInfo对象

//获取当前进程对应的ProcessInfo对象 NSProcessInfo* proInfo = [NSProcessInfo processInfo];

(2)、获取运行该程序所指向的参数

//获取运行该程序所指向的参数
NSArray* arr = [proInfo arguments];
NSLog(@"运行程序的参数为:%@",arr);

(3)、获取进程标识符

NSLog(@"进程标识符为:%d",[proInfo processIdentifier]);//进程标识符为:1590

(4)、获取进程的进程名

NSLog(@"进程的进程名为:%@",[proInfo processName]);//进程的进程名为:重新学习

(5)、获取所在系统的主机名

NSLog(@"进程所在系统的主机名为:%@",[proInfo hostName]);//进程所在系统的主机名为:chenxiaodemacbook-pro.local

(6)、获取进程所在系统的操作系统

NSLog(@"进程所在系统的操作系统为:%ld",[proInfo operatingSystem]);//进程所在系统的操作系统为:5

(7)、获取进程所在系统的操作系统名

NSLog(@"进程所在系统的操作系统名为:%@",[proInfo operatingSystemName]);//进程所在系统的操作系统名为:NSMACHOperatingSystem

(8)、获取进程所在系统的操作系统版本字符串

NSLog(@"进程所在系统的操作系统版本字符串为:%@",[proInfo operatingSystemVersionString]);//进程所在系统的操作系统版本字符串为:Version 10.9.5 (Build 13F34)

(9)、获取进程所在系统的物理内存

NSLog(@"进程所在系统的物理内存为:%lld",[proInfo physicalMemory]);//进程所在系统的物理内存为:8589934592

(10)、获取进程所在系统的处理器数量

NSLog(@"进程所在系统的处理器数量为:%ld",[proInfo processorCount]);//进程所在系统的处理器数量为:4

(11)、获取进程所在系统的激活的处理器数量

NSLog(@"进程所在系统的激活的处理器数量为:%ld",[proInfo activeProcessorCount]);//进程所在系统的激活的处理器数量为:4

(12)、获取进程所在系统的运行时间为

NSLog(@"进程所在系统的运行时间为:%f",[proInfo systemUptime]);//进程所在系统的运行时间为:17633.546019

五、使用NSFileHandle处理文件IO

NSFileHandle提供了处理文件IO相关方法,步骤如下:

  1. 创建一个NSFileHandle,该NSFileHandle将会打开指定的文件;
  2. 对打开的文件执行IO操作;
  3. 关闭文件;

NSFileHandle提供的方法如下:

  • (1)、+ (instancetype)fileHandleForReadingAtPath:(NSString *)path;根据指定路径打开一份准备读取文件内容的文件,并返回该文件对应的NSFileHandle;
  • (2)、+ (instancetype)fileHandleForReadingFromURL:(NSURL )url error:(NSError *)error;根据指定URL打开一份准备读取文件内容的文件,并返回该文件对应的NSFileHandle;
  • (3)、+ (instancetype)fileHandleForWritingAtPath:(NSString *)path;根据指定路径打开一份准备写入文件内容的文件,并返回该文件对应的NSFileHandle;
  • (4)、+ (instancetype)fileHandleForWritingToURL:(NSURL )url error:(NSError *)error;根据指定URL打开一份准备写入文件内容的文件,并返回该文件对应的NSFileHandle;
  • (5)、+ (instancetype)fileHandleForUpdatingAtPath:(NSString *)path;根据指定路径路径打开一份即可读取,又可写入文件内容的文件,并返回该文件对应的NSFileHandle;
  • (6)、+ (instancetype)fileHandleForUpdatingURL:(NSURL )url error:(NSError *)error;根据指定URL打开一根即可读取,又可写入文件内容的文件,并返回该文件对应的NSFileHandle;
  • (7)、+ (NSFileHandle *)fileHandleWithStandardError;打开标准错误输出设备对应的NSFileHandle;
  • (8)、+ (NSFileHandle *)fileHandleWithStandardInput;打开标准输入设备(通常是键盘)对应的NSFileHandle;
  • (9)、+ (NSFileHandle *)fileHandleWithStandardOutput;打开标准输出设备(通常是屏幕)对应的NSFileHandle;
  • (10)、+ (NSFileHandle *)fileHandleWithNullDevice;打开空设备对应的NSFileHandle;
  • (11)、- fileDescriptor:获取对应文件的描述器;
  • (12)、- availableData:返回该文件所有可用的数据;
  • (13)、- (NSData *)readDataToEndOfFile;读取该文件中包含的所有数据;
  • (14)、- (NSData *)readDataOfLength:(NSUInteger)length;读取该文件中length字节的数据;
  • (15)、- seekToEndOfFile:将该NSFileHandle中文件指针移动到文件的结尾处;
  • (16)、- (void)seekToFileOffset:(unsigned long long)offset;将该NSFileHandle中文件指针移动到指定的位置;
  • (17)、- (void)closeFile;关闭底层文件;
  • (18)、- (void)truncateFileAtOffset:(unsigned long long)offset;将文件长度“截断”为offset字节。如果该offset参数小于文件本身的大小,多余的备份被截断;如果该offset参数大于文件本身的大小,文件末尾将会被填充空数据;

例如:

(1)、打开一份可读文件

//打开一份文件准备读取
NSFileHandle* fh = [NSFileHandle fileHandleForReadingAtPath:@"/Users/chenxiao/Desktop/重新学习的ios/重新学习的ios/NSFileHandleTest.m"];
NSData* data;

(2)、按指定的长度读取文件,文件指针会移动

//读取NSFileHandle中的128字节
while ([(data = [fh readDataOfLength:128]) length] > 0) { NSLog(@"%ld",[data length]); //直接将NSData的数据用UTF-8的格式转换字符串 NSString* content = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%@",content); }

(3)、关闭文件

[fh closeFile];

(4)、打开一份可写文件

//打开一份可以准备写入的文件
NSFileHandle* fh2 = [NSFileHandle fileHandleForWritingAtPath:@"/Users/chenxiao/Desktop/abc.txt”];

(5)、如果文件不存在,创建文件

if (!fh2) {
    //创建一个NSFileManager对象
    NSFileManager* fm = [NSFileManager defaultManager];
    [fm createFileAtPath:@"/Users/chenxiao/Desktop/abc.txt" contents:nil attributes:nil];
    fh2 = [NSFileHandle fileHandleForWritingAtPath:@"/Users/chenxiao/Desktop/abc.txt"];
}

(6)、将指定数据写入文件

NSString* myBook = @"疯狂iOS讲义";
[fh2 writeData:[myBook dataUsingEncoding:NSUTF8StringEncoding]];

(7)、关闭文件

[fh2 closeFile];

六、使用NSURL读取网络资源

URL(Uniform Resource Locator)对象代表同意资源定位器,它是指向互联网“资源”的指针。资源可以是简单的文件或目录,也可以是对更复杂的对象引用,例如:对数据库或搜索引擎的查询。通常情况下,URL可以由协议名、主机、端口和资源路径组成,格式如下:

scheme://host:port/path

例如,如下的URL地址:

http://www.crazyit.org/index.php

例如:

(1)、创建NSURL对象

NSURL* url = [NSURL URLWithString:@"http://www.crazyit.org/index.php”];

(2)、获取NSURL对象的协议名

NSLog(@"url的协议名为:%@",[url scheme]);//url的协议名为:http

(3)、获取NSURL对象的主机

NSLog(@"url的主机为:%@",[url host]);//url的主机为:www.crazyit.org

(4)、获取NSURL对象的端口

NSLog(@"url的端口为:%@",[url port]);//url的端口为:(null)

(5)、获取NSURL对象的资源路径

NSLog(@"url的资源路径为:%@",[url path]);//url的资源路径为:/index.php

(6)、使用URL对应的资源来初始化NSString对象

//使用URL对应的资源来初始化NSString对象
NSString* homePage = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
//输出NSString内容,即可看到页面源代码
NSLog(@"%@",homePage);

七、使用NSBundle处理项目相关资源

得到NSBundle对象,接下来就可通过该对象的如下常用方法来获取指定的资源文件:

  • (1)、- (NSURL )URLForResource:(NSString )name withExtension:(NSString )ext subdirectory:(NSString )subpath;根据资源名、扩展名从指定子目录中获取资源对应的URL;
  • (2)、- (NSURL )URLForResource:(NSString )name withExtension:(NSString *)ext;根据资源名、扩展名获取资源对应的URL;
  • (3)、- (NSArray )URLsForResourcesWithExtension:(NSString )ext subdirectory:(NSString *)subpath;根据指定子目录下匹配特定的扩展名的所有资源对应的URL组成的数组;
  • (4)、- (NSString )pathForResource:(NSString )name ofType:(NSString *)ext;根据资源名、类型名获取资源对应的路径;
  • (5)、 - (NSString )pathForResource:(NSString )name ofType:(NSString )ext inDirectory:(NSString )subpath;从指定的目录下,根据资源名、类型名获取该资源对应的路径;
  • (6)、- (NSArray )pathsForResourcesOfType:(NSString )ext inDirectory:(NSString *)subpath;获取指定子目录下,匹配特定类型名所有资源对应的路径组成的数组;
  • (7)、- resourcePath:直接根据完整的资源路径来获取对应的资源;

例如:

NSString* filePath = [[NSBundle mainBundle] pathForResource:@"bookinf" ofType:@"txt"];
//使用指定文件的内容来初始化NSString
NSString* content = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
NSLog(@"content = %@",content);

八、对象归档

归档就是用某种格式把一个或多个对象保存到指定文件中,方便以后从文件中恢复他们。通常来说,归档包含两方面的操作:

  • (1)、需要把对象写入指定的文件中;
  • (2)、需要从文件中恢复这些对象。

1、使用NSKeyedArchiver归档,NSKeyedUnarchiver解档

用法如下:

  • (1)、对于NSArray、NSDictionary对象,直接调用NSKeyedArchiver的archivedDataWithRootObject:data、archiveRootObject:toFile:file类方法经指定对象作为root进行归档;恢复时,则调用NSKeyedUnarchiver的unarchiverObjectWithData:data或unarchiveObjectWithFile:file类方法。
  • (2)、以NSMutableData对象作为参数,创建NSKeyedArchiver对象,接下来重复调用NSKeyedArchiver对象的encodeXxx:value forKey:key方法一次归档不同的对象,最后调用finishEncoding方法结束归档即可,接下来重复调用decodeXxxForKey:key方法一次恢复不同的对对象。

例如:

(1)、创建NSDictionary对象

//使用过个value、key的形式创建NSDictionary对象
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:89],@"Objective-C",[NSNumber numberWithInt:69],@"Ruby",[NSNumber numberWithInt:75],@"Python",[NSNumber numberWithInt:109],@"Perl", nil];

(2)、获取一个路径

//获取路径
NSString *homePath = NSHomeDirectory();
NSString *path = [homePath stringByAppendingPathComponent:@"test.arc”];

(3)、归档

//对dict进行归档
[NSKeyedArchiver archiveRootObject:dict toFile:path];

(4)、解档
//解档

NSDictionary* dict1 = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
//下面代码只是获取NSDictionary中的key-value数据
NSLog(@"Objective-C对应的value:%@",[dict1 valueForKey:@"Objective-C"]);//Objective-C对应的value:89
NSLog(@"Ruby对应的value:%@",[dict1 valueForKey:@"Ruby"]);//Ruby对应的value:69
NSLog(@"Python对应的value:%@",[dict1 valueForKey:@"Python"]);//Python对应的value:75
NSLog(@"Perl对应的value:%@",[dict1 valueForKey:@"Perl"]);//Perl对应的value:109

2、实现NSCoding协议

如果尝试使用NSKeyedArchiver将一个自定义的类对象归档到指定文件中,运行程序将会提示如下错误:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[FKApple encodeWithCoder:]: unrecognized selector sent to instance 0x7faf62e46520'

*** First throw call stack:

从信息中可以看出,当程序使用NSKeyedArchiver归档一个自定义的FKApple对象时,系统会自动调用FKApple对象的encodeWithCoder:进行归档;当程序恢复一个自定义的实例时,系统会自动调用该对象的decodeWithCoder:方法进行恢复。所以,如果程序需要归档,恢复任意自定义的实例,那么该类应该实现NSCoding协议,实现该协议就必须实现该协议中定义的如下两个方法:
- initWithCoder::该方法负责恢复该对象。
- encodeWithCoder::该方法负责归档该对象。

例如:FKApple.h的实例部分

#import <Foundation/Foundation.h>
@interface FKApple : NSObject<NSCoding >

@property (nonatomic ,copy)NSString* color;
@property (nonatomic ,assign)double weight;
@property (nonatomic ,assign)int size;
- (id)initWithColor:(NSString *)color weight:(double)weight size:(int)size;
@end

FKApple.m的实现部分

#import "FKApple.h"
@implementation FKApple
- (id)initWithColor:(NSString *)color weight:(double)weight size:(int)size{
    if (self = [super init]) {
        self.color = color;
        self.weight = weight;
        self.size = size;
    }
    return self;
}
//归档
- (void)encodeWithCoder:(NSCoder *)aCoder{
    [aCoder encodeObject:self.color forKey:@"color"];
    [aCoder encodeDouble:self.weight forKey:@"weight"];
    [aCoder encodeInt:self.size forKey:@"size"];
}
//解档
- (id)initWithCoder:(NSCoder *)aDecoder{
    if (self = [super init]) {
        //使用NSCoder依次恢复color、weight、size这3个key
        //所对应的value,并将恢复的value赋给当前对象的3个实例变量
        self.color = [aDecoder decodeObjectForKey:@"color"];
        self.weight = [aDecoder decodeDoubleForKey:@"weight"];
        self.size = [aDecoder decodeIntForKey:@"size"];
    }
    return self;
}
@end

在mian函数中的实现部分

//获取documents路径
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documents = [paths objectAtIndex:0];
NSString* path = [documents stringByAppendingPathComponent:@"apple.archiv"];
FKApple* apple = [[FKApple alloc]initWithColor:@"红色" weight:3.4 size:20];
//归档
[NSKeyedArchiver archiveRootObject:apple toFile:path];
//解档
FKApple* apple2 = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
//获取对象的属性
NSLog(@"苹果的颜色为:%@",apple2.color);//苹果的颜色为:红色
NSLog(@"苹果的重量为:%g",apple2.weight);//苹果的重量为:3.4
NSLog(@"苹果的规格为:%d",apple2.size);//苹果的规格为:20

3、使用NSData完成自定义归档

如果程序需要一次性将多个对象归档到单个档案文件中,可按如下步骤进行:

  1. 以NSMutableData作为参数,创建NSKeyedArchive对象;
  2. 重复调用NSKeyedArchiver对象的encodeXxx:forKey:方法归档所有需要归档到一个文件中的对象;
  3. 调用NSKeyedArchiver对象的finishEncoding方法结束归档;
  4. 根据需要,程序可以选择将保存归档数据的NSData通过网络传输或输出到磁盘文件上;

例如:

//直接使用value、key的形式创建NSDictionary对象
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:89],@"Objective-C",[NSNumber numberWithInt:69],@"Ruby",[NSNumber numberWithInt:75],@"Python",[NSNumber numberWithInt:109],@"Perl", nil];
//创建一个NSSet对象
NSSet* set = [NSSet setWithObjects:@"疯狂iOS讲义",@"疯狂Android讲义",@"疯狂Ajax讲义", nil];
//创建一个FKApple对象
FKApple* apple = [[FKApple alloc]initWithColor:@"红色" weight:3.4 size:20];
//创建一个NSMutableData对象,用于保存归档数据
NSMutableData* data = [NSMutableData data];
//以NSMutableData为参数,创建NSKeyedArchiver对象
NSKeyedArchiver* arch = [[NSKeyedArchiver alloc]initForWritingWithMutableData:data];
[arch encodeObject:dict forKey:@"myDict"];
[arch encodeObject:set forKey:@"set"];
[arch encodeObject:apple forKey:@"myApple"];
//结束归档
[arch finishEncoding];
//将程序NSData缓存区保存的数据写入文件
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* documents = [paths objectAtIndex:0];
NSString* path = [documents stringByAppendingPathComponent:@"apple.archiv"];
NSLog(@"path = %@",path);
if ([data writeToFile:path atomically:YES] == NO) {
    NSLog(@"归档失败");
}
  • (1)、以NSData作为参数,创建NSKeyedUnarchiver对象。
  • (2)、复制调用NSKeyedUnarchiver对象的decodeXxx:forKey:方法从一个文件中回复所有归档过的对象。
  • (3)、调用NSKeyedUnarchiver对象的finishDecoding方法结束恢复。
NSData* data2 = [NSData dataWithContentsOfFile:path];
//以data2对象作为参数,创建NSKeyedUnichiver对象
NSKeyedUnarchiver* unarch = [[NSKeyedUnarchiver alloc]initForReadingWithData:data2];
//重复调用decodeObjectForKey:方法恢复所有需要恢复的对象
NSDictionary* dict2 = [unarch decodeObjectForKey:@"myDict"];
NSSet* set2 = [unarch decodeObjectForKey:@"set"];
FKApple* apple2 = [unarch decodeObjectForKey:@"myApple”];
//结束恢复
[unarch finishDecoding];
NSLog(@"dict2 = %@",dict2);
NSLog(@"set2 = %@",set2);
NSLog(@"apple2 = %@",apple2);

4、使用归档实现深复制

归档会将整个对象转换为字节数据——包括该对象的所有势力变量,如果该实例变量指向另一个Objecyive-C对象,归档时也会归档该实例变量所指向的Objective-C对象。这表明:当程序归档一个对象时,系统会把对象关联的所有数据都转为字节数据;如果程序从这些字节数据中恢复该对象,恢复出来的对象与原对象将完全相同,但没有任何共用的部分,这就是实现了深复制。

九、小结

你可能感兴趣的:(Objective-C,文件I-O)