在 iOS 中对接收到的网络数据(NSData)进行文件读写

在 c 语言中,文件操作都是由库函数来实现的,主要是分为两种操作:

文件指针

平常所说的文件不同于其他常见的数据类型,比如一个test.txt文档,它有自己的一些属性,比如文件的当前位置、与该文件对应的内存缓冲区地址、文件操作方式等等。对于这些信息都会专门开辟一定内存空间来存储。而且是保存在一个结构体类型变量中,比如:

struct
{
   int fd;           //文件号
   int cleft;        //缓冲区中剩下的字符
   int mode;         //文件操作模式
   char *nextc;      //下一个字符位置
   char *buff;       //文件缓冲区位置
}FILE;
/*FILE是一个存储文件信息的结构体类型的变量*/
在上述代码中可以看到,文件号、文件操作模式等信息都存储在一个结构体中。

这个结构体是系统自己定义的,定义在stdio.h头文件中,取名为FILE。也就是说FILE是系统名称,不可改变的,不是自定义。

所以只要程序用到一个文件,系统就为此文件开辟一个如上的结构体变量。需要几个文件,系统就开辟几个这样的结构体。

这些结构体变量不用变量名来标识,而是通过指向结构体类型的指针变量去访问,这就是文件指针

比如:FILE *fp1,*fp2,*fp3; 当引用文件时,就可以把这个文件的结构体首地址赋给某个文件指针(*fp1,通过*fp1就可以调用结构体以找到相关的信息。

一般来说,有多少个文件就有多少个结构体,有多少结构体就有多少个文件指针。

对磁盘文件的操作必须是先打开,然后读写操作,最后关闭


打开文件


函数原型

FILE * fopen(const char * path,const char * mode);
path:需要打开的文件路径
mode:文件打开方式
返回值文件顺利打开后,返回指向该流的文件指针。如果文件打开失败则返回NULL,并把错误代码存在errno中。(errno 是记录系统的最后一次错误代码。代码是一个int型的值,在errno.h中定义)
其中文件打开方式主要有一下几种:

文件使用方式

含义

r”(只读)

为输入打开一个文本文件

w(只写)

为输出打开一个文本文件

a(追加)

为文本文件尾增加数据

rb(只读)

为输入打开一个二进制文件

wb(只写)

为输出打开一个二进制文件

ab(追加)

向二进制文件尾增加数据

r+(读写)

为读写打开一个文本文件

w+(读写)

为读写打开一个新的文本文件

a+(读写)

为读写打开一个文本文件

rb+(读写)

为读写打开一个二进制文件

wb+(读写)

为读写建立一个新的二进制文件

ab+(读写)

为读写打开一个二进制文件

t(文本文件)可以省略不写

总结为:r为读 w为写 b为二进制文件 a为追加 +为读写。可以组合使用

关闭文件


函数原型:
int fclose( FILE *fp );
返回值:如果流成功关闭,fclose 返回 0,否则返回EOF(-1)。(如果流为NULL,而且程序可以继续执行,fclose设定error number给EINVAL,并返回EOF。)

读写文件


常用的文件读写函数主要有:

字符读写函数:fgetc() 和 fputc (getc 和 putc)

字符串读写函数:fgets() 和 fputs()

数据块读写函数:fread() 和 fwrite()

格式化读写函数:fscanf() 和 fprintf()


fread()


函数原型

size_t fread ( void *buffer, size_t size, size_t count, FILE *stream) ;
功能从一个文件流中读数据,最多读取count个元素,每个元素size字节,如果调用成功返回实际读取到的元素个数,如果不成功或读到文件末尾返回 0。
buffer用于接收数据的内存地址。
size要读的每个数据项的字节数,单位是字节(byte)。
count要读count个数据项,每个数据项size个字节。
stream:文件输入流
返回值实际读取的元素个数。如果返回值与count不相同,则可能文件结尾或发生错误。从ferror和feof获取错误信息或检测是否到达文件结尾。

fwrite()


函数原型

size_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream);
功能向文件写入一个数据块(注意:这个函数以二进制形式对文件进行操作,不局限于文本文件)。
buffer:是一个指针,对fwrite来说,是要获取数据的地址(即数据来源地址)。
size要写入内容的单字节数。
count要进行写入size字节的数据项的个数。
stream目标文件指针。
返回值返回实际写入的数据块数目。

fseek()

函数原型

int fseek(FILE *stream, long offset, int fromwhere);
功能 :重定位流(数据流/文件)上的文件内部位置指针(即: 可以移动文件的读写指针到指定的位置,即移动当前文件的位置指针 )。 如果执行失败(比如offset超过文件自身大小),则不改变stream指向的位置。
stream:文件指针。
offset:偏移量。
fromwhere :指针的起始位置,为下列其中一种
SEEK_SET:从距离文件开头 offset 位移量为新的读写位置;
SEEK_CUR :以目前的读写位置往后增加 offset 个位移量;
SEEK_END :将读写位置指向文件末尾后再增加 offset 个位移量。

ftell()

函数原型

long ftell(FILE *stream);
功能用于获取文件位置指针当前位置相对于文件首的偏移字节数。(使用fseek()后再调用函数ftell()就能非常容易地确定文件的当前位置。
strem:文件指针。(注意文件指针必须是有效的,且必须指向一个通过 fopen() 或 popen() 成功打开的文件。在附加模式(加参数 "a" 打开文件)中 ftell() 会返回未定义错误
返回值   handle指定的文件指针的位置,也就是文件流中的偏移量。如果出错,返回 FALSE
约束因为ftell返回long型,根据long型的取值范围-231~231-1(-2147483648~2147483647),故对大于2.1G的文件进行操作时出错。

改变文件大小

ftruncate()

函数原型
int ftruncate(int fd,off_t length);
功能:将参数fd指定的文件大小改为参数length指定的大小。
fd:为已打开的文件描述词,而且必须是以写入模式打开的文件。
length:要改成的大小,如果原来的文件大小比参数length大,则超过的部分会被删去。
返回值:执行成功则返回0,失败返回-1,错误原因存于errno
        EBADF 参数fd文件描述词为无效的或该文件已关闭。
         EINVAL 参数fd 为一socket 并非文件,或是该文件并非以写入模式打开。
说明:fd一般可以fileno(FILE *fp)获取,标示文件当前的大小,lenggth则可由用户定义。此函数一般用在文件初始化或者重新为文件分配空间时。

fileno()

函数原型
int _fileno( FILE *stream );
功能:用来取得参数stream指定的文件流所使用的文件描述符。
stream:文件输入流。
返回值:某个数据流的文件描述符。



下面简单讲一下在iOS 下,对NSData 的文件读写:

读文件

/*
 * ===  FUNCTION  ==================================================
 *         Name:  readDataToBuffer:fromPath:
 *  Description:  从指定 path 的文件读取内容到 buffer
 * =================================================================
 */
-(void)readDataToBuffer:(char *)buffer fromPath:(NSString *)path
{
    
    FILE *p_r= fopen([path cStringUsingEncoding:NSUTF8StringEncoding], "r");  //打开文件
    if (NULL == p_r)
    {
        NSLog(@"Open file error to read data !");
        return ;
    }

    fseek(p_r, 0, SEEK_END);                //定位到文件末尾
    NSInteger dataLength = ftell(p_r);      //获取文件长度
    fseek(p_r, 0, SEEK_SET);                //定位到文件起始位置
    fread(buffer, dataLength, 1, p_r);      //读取文件到指定的缓冲区
    fclose(p_r);                            //关闭文件

}


写文件

/*
 * ===  FUNCTION  ==================================================
 *         Name:  writeData:toPath:
 *  Description:  把数据写到指定的文件中
 * =================================================================
 */
-(void)writeData:(NSData *)data toPath:(NSString *)path
{
    FILE *p_w= fopen([path cStringUsingEncoding:NSUTF8StringEncoding], "ab");  //已追加二进制方式打开文件
    if (NULL == p_w)
    {
        NSLog(@"Open file error to write data!");
        return ;
    }
    fseek(p_w, 0, SEEK_END);                                 // 移到文件末尾
    fwrite((void *)[data bytes], data.length, 1, p_w);       // 写入数据
    data = nil;
    fclose(p_w);                                             //关闭文件
}


此博文源自 http://blog.csdn.net/shenyuanluo/article/details/48003531


如需转载,请说明博文出处。谢谢!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值