您的位置:首页 > 其它

NSFileHandle对文件管理的最详细介绍

2017-03-27 18:26 246 查看
一、在iOS开发中对于文件的管理非常重要。下面我们一起来探究一下 NSFileHandle 类是如何对文件管理的。

二、NSFileHandle类的方法介绍和使用,并加举例。

//

//  ViewController+KNSFileHandle.m

//  KNSFileHandle

/**

 

 本特辑是探究IOS
的文本管理的 NSFileHandle
类的使用和介绍。

 */

//  Created by MAC on 2017/3/17.

//  Copyright © 2017年 NetworkCode小贱. All rights reserved.

//

#import "ViewController.h"

#import <sys/socket.h>

#import <netinet/in.h>

#import <arpa/inet.h>

@implementation ViewController (KNSFileHandle)

-(void)viewDidLoad{

    /**

     首先创建一个文件

     */

    [self
createFile];

    

}

-(void)createFile{

    if (!filePath) {

        filePath =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES).firstObject;

        filePath =[NSString
stringWithFormat:@"%@/test.txt",filePath];

    }

    /**

     生成文件的属性设置

     */

    NSDictionary * attributes =
@{NSFileOwnerAccountName:@"NetWork小贱"};

    /**

     创建写入的数据

     */

    NSData * saveData = [@"成功QQ吧"
dataUsingEncoding:NSUTF8StringEncoding] ;

    NSFileManager * fileManager = [NSFileManager
defaultManager];

    BOOL isFile = [fileManager
createFileAtPath:filePath
contents:saveData
attributes:attributes];

    if (!isFile) {

        printf("创建失败");

        return;

    }

    /**

     读

     */

   // [self createReadingFileHandle];

    /**

     写

     */

   // [self createWritingFileHandle];

    /**

     更新数据

     */

   // [self createUpdatingFileHandle];

    /**

     文件的通知

     */

   // [self notifitionFileHandle];

    /**

     两个回调 read
和 write

     */

    // [self  fileHandleBlock];

    /**

     服务通知——socket     

     */

    [self
socketFileHandle];

}

#pragma mark --- create createReadingFileHandle

-(void)createReadingFileHandle{

    /**

     三种创建方法

     另外,下面的这个不常用:

     - (instancetype)initWithFileDescriptor:(int)fd closeOnDealloc:(BOOL)closeopt NS_DESIGNATED_INITIALIZER;

     */

   
// 打开文件准备读取

    NSFileHandle * fileHandle = [NSFileHandle
fileHandleForReadingAtPath:filePath];

    /**

     按长度读取数据

     */

    [self
analysis:[fileHandle
readDataOfLength:3]];

    /**

     读取文件内容

     */

    [self
analysis:[fileHandle
readDataToEndOfFile]];

    /**

     可获取的数据

     */

    [self
analysis:[fileHandle
availableData]];

    /**

     获取文件的操作位置

     例如:

     文件内有:成功QQ吧
,然后再使用 [self analysis:[fileHandle readDataOfLength:3]]
之后,再调用 [fileHandle offsetInFile]

     就可得到 3。因为,一个汉字占用3个字节,我们开始是读取3个字节,所以现在的文件操作位置是 
3.

     */

    NSInteger length = [fileHandle
offsetInFile];

    NSLog(@"%ld",length);

    /**

     设置当前文件的操作位置

     @param

     输出:

     2017-03-24 13:15:36.912 KNSFileHandle[3469:749724] 11

     2017-03-24 13:15:36.912 KNSFileHandle[3469:749724] 3

     */

    [fileHandle seekToFileOffset:3];

    NSInteger lengthSet = [fileHandle
offsetInFile];

    NSLog(@"%ld",lengthSet);

    /**

     seekToEndOfFile 是设置文件操作位置到文件的末尾

     输出:

     2017-03-24 13:17:45.497 KNSFileHandle[3505:759909] 3

     2017-03-24 13:17:45.497 KNSFileHandle[3505:759909] 11

     */

    [fileHandle seekToEndOfFile];

    NSInteger lengthSetLast = [fileHandle
offsetInFile];

    NSLog(@"%ld",lengthSetLast);

    /**

     同步文件

     */

    [fileHandle synchronizeFile];

    /**

     关闭文件

     */

    [fileHandle closeFile];

    

    /*

    // 测试读取创建的是否可以写入

    [fileHandle writeData:[self createData:@"特别推出"]];

    // 我们在读取

    [self analysis:[fileHandle readDataToEndOfFile]];

     */

    /****

     总结

     1、读取文件创建的NSFileHandle对象,不可用于写入NSFileHandle对象

     2、NSFileHandle
读取文件是从文件中取出数据,被取出的数据在文件中被删除

     3、读取创建的 NSFileHandle对象
,不可使用 truncateFileAtOffset
设置文件大小

     ********/

}

#pragma mark --- createWritingFileHandle

-(void)createWritingFileHandle{

    /**

     打开并写入

     */

    NSFileHandle * fileHandle = [NSFileHandle
fileHandleForWritingAtPath:filePath];

    

    /**

     我们测试看能否读取

     [self analysis:[fileHandle availableData]];

     */

    /**

     设置写入文件的大小

    */

    [fileHandle truncateFileAtOffset:14];

    /**

     写入数据

     */

    [fileHandle writeData:[self
createData:@"特别提供"]];

    

    /**

     将文件的操作设置到最后

     */

    [fileHandle seekToEndOfFile];

    NSInteger lengthSet = [fileHandle
offsetInFile];

    NSLog(@"%ld",lengthSet);

    /***

     输出:2017-03-24 13:41:03.731 KNSFileHandle[3851:859436] 22

     问题:为什么输出的是 22
不是 23
???

     答:
因为写入文件前的文件操作位置是 11,我们又将操作位置设置为 10,然后,我们是从10的操作位置到12,则,最后的操作位置是
22,不是23


     **/

     /**

      写入完要同步一下

      */

    [fileHandle synchronizeFile];

    [fileHandle closeFile];

    /**

     我们查看最后的结果

     输出:

     2017-03-24 13:55:38.997 KNSFileHandle[4187:912750]

     Result:成功QQ吧

     */

    NSFileHandle * fileHandleRead = [NSFileHandle
fileHandleForReadingAtPath:filePath];

    [self
analysis:[fileHandleRead
readDataToEndOfFile]];

    [fileHandleRead closeFile];

    /****

     总结

     1、写入文件创建的NSFileHandle对象,不可用与读取数据

     2、由fileHandleForWritingAtPath
创建的 NSFileHandle对象 ,在写入数据是覆盖不是增加

     3、注意,如果在文件写入前设置 truncateFileAtOffset ;
如果设置的数字小于要写入的文件长度,则后期再获取文件的内容为空

     ********/

}

#pragma mark --- createUpdatingFileHandle

-(void)createUpdatingFileHandle{

    /**

     打开并更新

     */

    NSFileHandle * fileHandle = [NSFileHandle
fileHandleForUpdatingAtPath:filePath];

    /**

     测试更新状态是否可以读取数据

     

     输出:

     2017-03-24 14:10:01.971 KNSFileHandle[4326:965690]

     Result:成功QQ吧

     */

    [self
analysis:[fileHandle
availableData]];

    /**

     跳转操作节点

     */

    [fileHandle seekToEndOfFile];

    /**

     测试更新状态是否可以写入

     */

    [fileHandle writeData:[self
createData:@"特别提供"]];

    [fileHandle synchronizeFile];

    [fileHandle closeFile];

    /**

     我们读取数据

     */

    NSFileHandle * fileHandleWrite = [NSFileHandle
fileHandleForUpdatingAtPath:filePath];

    [self
analysis:[fileHandleWrite
availableData]];

    /***

     注意:

     使用fileHandleForUpdatingAtPath
创建的对象A
打开更新文件。不能写入后,再使用A,来获取写入的内容

     ****/

}

#pragma mark ---  notifitionFileHandle

-(void)notifitionFileHandle{

    /**

     文件数据读取到最后的时候发出通知

     */

    NSFileHandle * fileHandleReadToEnd = [NSFileHandle
fileHandleForReadingAtPath:filePath];

    [[NSNotificationCenter
defaultCenter] addObserver:self
selector:@selector(ReadToEndNotification:)
name:NSFileHandleReadToEndOfFileCompletionNotification
object:fileHandleReadToEnd];

    [fileHandleReadToEnd readToEndOfFileInBackgroundAndNotify];

    [self
analysis:[fileHandleReadToEnd
readDataToEndOfFile]];

    /**

     文件读取中,包括文件开始被读取,都发出通知

     */

    NSFileHandle * fileHandle = [NSFileHandle
fileHandleForReadingAtPath:filePath];

    [[NSNotificationCenter
defaultCenter] addObserver:self
selector:@selector(readCompletionNotification:)
name:NSFileHandleReadCompletionNotification
object:fileHandle];

    [fileHandle readInBackgroundAndNotify];

    [self
analysis:[fileHandle
availableData]];

    /**

    输出:

    2017-03-24 18:33:10.110 KNSFileHandle[7056:1676167] 文件被读取了

    2017-03-24 18:33:10.111 KNSFileHandle[7056:1676167] 文件被读取到最后了

    注意:

    一个是在文件开始和读取中发送通知,

    ;

    另一个是在文件读取完成发送通知

    **/

    

    /*

     socket建立。对于每个监听到的连接通知,我们可以从fileDescriptor
构造一个NSFileHandle
以接受请求。就会触发 NSFileHandleConnectionAcceptedNotification
通知。

     

     NSFileHandle* listeningHandle = [[NSFileHandle alloc]initWithFileDescriptor:fileDescriptor closeOnDealloc:YES];

     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(connectionAcceptedNotification:) name:NSFileHandleConnectionAcceptedNotification object:listeningHandle];

     [listeningHandle acceptConnectionInBackgroundAndNotify];

     [self analysis:[listeningHandle availableData]];

     */

    

    /**

     这个是当文件内部检测到可用数据的时候,会发起通知

     */

    NSFileHandle * fileHandleDataAvailable = [NSFileHandle
fileHandleForReadingAtPath:filePath];

    [[NSNotificationCenter
defaultCenter] addObserver:self
selector:@selector(dataAvailableNotification:)
name:NSFileHandleDataAvailableNotification
object:fileHandleDataAvailable];

    [fileHandleDataAvailable waitForDataInBackgroundAndNotify];

    [self
analysis:[fileHandleDataAvailable
availableData]];

}

#pragma mark  --- readCompletionNotification

-(void)readCompletionNotification:(NSNotification*)notification{

    NSLog(@"文件被读取了");

}

#pragma mark  --- ReadToEndNotification

-(void)ReadToEndNotification:(NSNotification*)notification{

    NSLog(@"文件被读取到最后了");

}

#pragma mark  --- ReadToEndNotification

-(void)connectionAcceptedNotification:(NSNotification*)notification{

    NSLog(@"connectionAcceptedNotification");

}

#pragma mark  --- ReadToEndNotification

-(void)dataAvailableNotification:(NSNotification*)notification{

    NSLog(@"dataAvailableNotification,文件内部检测到可用数据");

}

#pragma mark ---  fileHandleBlock

-(void)fileHandleBlock{

    /**

     写

     */

    NSFileHandle * fileHandleWriteability = [NSFileHandle
fileHandleForWritingAtPath:filePath];

    fileHandleWriteability.writeabilityHandler  = ^(NSFileHandle* handle){

        /**

         注意:

             此处的 handle
不可用于写入

         */

        [handle writeData:[self
createData:@"特别提供"]];

        [handle synchronizeFile];

        [handle closeFile];

        /**

         获取数据

         */

        [self
analysis:[NSData
dataWithContentsOfFile:filePath]];

    };

    [[NSPipe
pipe].fileHandleForWriting
writeabilityHandler];

    

    

    /**

     读

     */

    NSFileHandle * fileHandleReadability = [NSFileHandle
fileHandleForReadingAtPath:filePath];

    fileHandleReadability.readabilityHandler  = ^(NSFileHandle* handle){

        [self
analysis:[handle
readDataToEndOfFile]];

    };

    [[NSPipe
pipe].fileHandleForReading
readabilityHandler];

    /**

     注意:

     发起调用,可以是任意对象的 NSFileHandle
对象。

     创建的对象个是个的用途,不可用于其他用途,比如:读的对象就是读,不可用于写

     */

}

#pragma mark ---   socketFileHandle

-(void)socketFileHandle{

    /**

     创建一个socket

     知识扩展:

     TCP端口12345使用传输控制协议。TCP是TCP/IP网络中的主要协议之一。TCP是面向连接的协议,它要求握手建立端到端的通信。只有在连接建立时,用户的数据才能在连接上双向发送。

     注意!TCP保证在端口12345上传送数据包的顺序与它们发送的顺序相同。TCP端口12345的保证通信是TCP和UDP的主要区别。UDP端口12345不会保证TCP的通信。

     UDP端口12345提供不可靠的服务和数据报可能会重复、无序,或不通知。在端口12345上的UDP认为在应用程序中不需要进行错误检查和校正,从而避免了在网络接口级别上进行此类处理的开销。

     UDP(用户数据报协议)是一个面向消息的最小传输层协议(协议在IETF RFC 768中被记录)。

     应用实例,经常使用UDP:语音IP(VoIP),流媒体和实时多人游戏。许多Web应用程序使用UDP,如域名系统(DNS),路由信息协议(RIP),动态主机配置协议(DHCP),简单的网络管理协议(SNMP)。

     TCP与UDP TCP:可靠的,有序的,重量级的,UDP流;不可靠的,无序的,轻量级的,报。

     */

    NSSocketPort * socketPort = [[NSSocketPort
alloc]initWithTCPPort:12345];

    NSSocketNativeHandle socketId = [socketPort
socket];

    /**

     创建一个 NSFilehandle
对象

     */

    NSFileHandle * socketFileHandle = [[NSFileHandle
alloc]initWithFileDescriptor:socketId];

    /**

     添加链接服务器监控

     */

    [[NSNotificationCenter
defaultCenter] addObserver:self
selector:@selector(socketConnectionAcceptedNotification:)
name:NSFileHandleConnectionAcceptedNotification
object:socketFileHandle];

    [socketFileHandle acceptConnectionInBackgroundAndNotify];

    /**

     连接服务器,并发送消息

     */

    [self
connectionServer];

}

#pragma mark  ---  connectionAcceptedNotification

-(void)socketConnectionAcceptedNotification:(NSNotification*)notification{

    /**

     获取有请求服务器创建的 NSFileHandle
对象

     */

    NSFileHandle * connectedSocketFileHandle = [[notification
userInfo] objectForKey:NSFileHandleNotificationFileHandleItem];

    /**

     在监控数据的读取

     */

    [[NSNotificationCenter
defaultCenter] addObserver:self
selector:@selector(readFileHandle:)
name:NSFileHandleReadCompletionNotification
object:connectedSocketFileHandle];

    /**

     发送消息给客户端,确认连接已被接受

     */

    [connectedSocketFileHandle writeData:[self
createData:@"已经连接成功"]];

    /**

     开启监控

     */

    [connectedSocketFileHandle readInBackgroundAndNotify];

    

}

#pragma mark --- readFileHandle

-(void)readFileHandle:(NSNotification*)notification{

    NSData * data = [[notification
userInfo] objectForKey:NSFileHandleNotificationDataItem];

    /**

     对数据的解析

     */

    [self
analysis:data];

    /**

     告诉文件句柄继续等待数据

     */

    [[notification object]
readInBackgroundAndNotify];

}

-(void)connectionServer{

    /**

     创建socket对象

     @param kCFAllocatorDefault  内存分配的类型

     @param PF_INET  协议族,一般为Ipv4:PF_INET,(Ipv6,PF_INET6)

     @param SOCK_STREAM  套接字类型,TCP用流式—>SOCK_STREAM,UDP用报文式->SOCK_DGRAM

     @param IPPROTO_TCP  指定通信协议.如果前一个参数为SOCK_STREAM,则默认使用TCP协议;如果前一个参数SOCK_DGRAM,则默认使用UDP协议

     @param kCFSocketNoCallBack   回调的函数类型,有好多类型

     @param callout   回调的第2中类型

     @param context   用户定义的数据指针,用于对CFSocket对象的额外定义或者申明,可以为NULL

     */

    CFSocketRef  socketRef =
CFSocketCreate(kCFAllocatorDefault,PF_INET,SOCK_STREAM,IPPROTO_TCP,kCFSocketNoCallBack,nil,NULL);

    if (socketRef!=nil) {

        /**

         创建 socket
对象的地址,网络类型

         */

        struct
sockaddr_in addR4;

        memset(&addR4,
0, sizeof(addR4));

        addR4.sin_len =
sizeof(addR4);

        addR4.sin_family =
AF_INET;

        /**

         设置连接服务器的地址

         */

        addR4.sin_addr.s_addr =
inet_addr("127.0.0.1");

        /**

         设置远程监听的端口

         */

        addR4.sin_port =
htons(12345);

        /**

         进行地址转换

         */

        CFDataRef dataRef =
CFDataCreate(kCFAllocatorDefault, (UInt8*)&addR4,
sizeof(addR4));

        /**

         连接服务器,并返回结果

         */

        CFSocketError socketError =
CFSocketConnectToAddress(socketRef, dataRef,
10);

        if (socketError ==
kCFSocketSuccess) {

            NSLog(@"连接服务器成功");

            const
char * stringToSend = [@"NetWork小贱" 
UTF8String];

            send(CFSocketGetNative(socketRef),stringToSend,
strlen(stringToSend)+1,
1);

            /**

             输出:

             2017-03-27 17:39:05.921 KNSFileHandle[4453:1317371]
连接服务器成功

             2017-03-27 17:39:08.647 KNSFileHandle[4453:1317371]

             Result:NetWork小贱

             */

        }

    }

}

#pragma mark  --- createData  生成

-(NSData*)createData:(NSString*)string{

    NSData * saveData = [string
dataUsingEncoding:NSUTF8StringEncoding] ;

    return saveData;

}

#pragma mark  --- analysis 解析

-(void)analysis:(NSData*)data{

    NSString * string = [[NSString
alloc]initWithData:data
encoding:NSUTF8StringEncoding];

    NSLog(@"\nResult:%@",string);

}

/***

 输出的结果:

 

 1、2017-03-24 11:34:59.606 KNSFileHandle[2436:574179]
成功QQ吧

 2、2017-03-24 11:53:27.531 KNSFileHandle[2792:653731]

 Result:成

 2017-03-24 11:53:27.532 KNSFileHandle[2792:653731]

 Result:功QQ吧

 */

@end

三、完整文件的下载
https://pan.baidu.com/s/1nvqJlVV
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息