文件IO与标准库IO


一、文件(系统)IO与标准库IO

1、无缓存IO系统调用
函数:open close write read 等系统调用
操作数据流向路径:数据——内核缓存区——磁盘

2、标准IO库函数调用
函数:fopen fclose fwrite fread fgets fputs fgetc fputc 等标准库函数调用函数
操作数据流向路径:数据——流缓存区——内核缓存区——磁盘

文件IO是低级IO不带有缓存、而标准io带有缓存在open时会在用户层开启一个缓存区域提高效率,防止频繁调用系统io
标准io —> 系统io (标准io是在系统io之上)

二、标准IO 相关的API

头文件:#include<stdio.h>

1.fopen / fcolse

FILE * fopen(const char * path,const char * mode)

返回值:文件顺利打开后,指向该流的文件指针就会被返回。若果文件打开失败则返回NULL,并把错误代码存在errno 中。

参数:
path:字符串包含欲打开的文件路径及文件名
mode:有下列几种流形态字符串:
r 打开只读文件,该文件必须存在。
r+ 打开可读写的文件,该文件必须存在。
w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。
a+ 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。
上述的形态字符串都可以再加一个b字符,如rb、w+b或ab+等组合,加入b 字符用来告诉函数库打开的文件为二进制文件,而非纯文字文件。

int fclose(FILE * stream);

此动作会让缓冲区内的数据写入文件中,并释放系统所提供的文件资源。
返回值:若关文件动作成功则返回0,有错误发生时则返回EOF并把错误代码存到errno

2.fread/fwrite/fseek/ftell

size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream);

ptr: 存放buffer
size: 一个单元大小
nmemb:单元个数
stream:已打开的文件指针
理论接受的字节大小 size*nmemb     
返回值:
返回实际读取的单元个数。如果小于count,则可能文件结束或读取出错;
可以用ferror()检测是否读取出错,用feof()函数检测是否到达文件结尾。如果size或nmemb为0,则返回0
size_t fwrite(const void * ptr,size_t size,size_t nmemb,FILE * stream);
ptr: 传输送buffer
size: 一个单元大小
nmemb:单元个数
stream:已打开的文件指针
理论写的字节大小 size*nmemb  
返回值:
返回实际写入的nmemb 数目,如果小于nmemb ,则说明发生了错误,文件流错误标志位将被设置,随后可以通过ferror()函数判断。
int fseek(FILE * stream,long offset,int whence);
stream:已打开的文件指针
offset:根据参数whence来移动读写位置的位移数
whence:
SEEK_SET从距文件开头offset位移量为新的读写位置。
SEEK_CUR 以目前的读写位置往后增加offset(可负)个位移量。 
SEEK_END将读写位置指向文件尾后再增加offset(可负)个位移量。
返回值:
成功:0  错误: -1

long ftell(FILE * stream);

取得文件流目前的读写位置
返回值:当调用成功时则返回目前的读写位置,若有错误则返回-1

注意:读写指针是同一个 按情况使用fseek进行指针的偏移

3.fgetc/fgets fputc/fputs

int fgetc(FILE * stream);
函数说明:fgetc()从参数stream所指的文件中读取一个字符。若读到文件尾而无数据时便返回EOFchar * fgets(char * s,int size,FILE * stream);
从参数stream所指的文件内读入字符并存到参数s所指的内存空间,直到出现换行字符、
读到文件尾或是已读了size-1个字符为止,最后会加上NULL作为字符串结束 包括最后的空字符
size:通常是使用以 s传递的数组长度
返回为一个指针
int fputc(int c,FILE * stream);
会将参数c 转为unsigned char 后写入参数stream 指定的文件中
会返回写入成功的字符,即参数c

int fputs(const char * s,FILE * stream);
将参数s所指的字符串写入到参数stream所指的文件内
若成功则返回写出的字符个数,返回EOF则表示有错误发生。

三、文件IO相关API

头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include<unistd.h>
#include <fcntl.h>

1.open/close

open:

int open( const char * pathname, int flags);
int open( const char * pathname,int flags, mode_t mode);
成功:返回文件描述符     失败:  -1

参数flags:

flag功能
O_WRONLY以只写方式打开文件
O_RDWR以可读写方式打开文件
O_RDONLY以只读方式打开文件
O_CREAT若欲打开的文件不存在则自动建立该文件
O_EXCL如果O_CREAT 也被设置,此指令会去检查文件是否存在。文件若不存在则建立该文件,否则将导致打开文件错误。此外,若O_CREAT与O_EXCL同时设置,并且欲打开的文件为符号连接,则会打开文件失败
O_NOCTTY如果欲打开的文件为终端机设备时,则不会将该终端机当成进程控制终端机
O_TRUNC若文件存在并且以可写的方式打开时,此旗标会令文件长度清为0,而原来存于该文件的资料也会消失
O_APPEND当读写文件时会从文件尾开始移动,也就是所写入的数据会以附加的方式加入到文件后面
O_NONBLOCK以不可阻断的方式打开文件,也就是无论有无数据读取或等待,都会立即返回进程之中
O_NDELAY同O_NONBLOCK
O_SYNC以同步的方式打开文件
O_NOFOLLOW如果参数pathname 所指的文件为一符号连接,则会令打开文件失败
O_DIRECTORY如果参数pathname 所指的文件并非为一目录,则会令打开文件失败

参数mode:
只有在建立新文件时才会生效,此外真正建文件时的权限会受到umask值所影响,因此该文件权限应该为(mode-umaks)。

mode说明
S_IRWXU ,00700 权限代表该文件所有者具有可读、可写及可执行的权限。
S_IRUSR 或S_IREAD,00400权限,代表该文件所有者具有可读取的权限。
S_IWUSR 或S_IWRITE,00200 权限,代表该文件所有者具有可写入的权限。
S_IXUSR 或S_IEXEC,00100 权限,代表该文件所有者具有可执行的权限。
S_IRWXG 00070权限,代表该文件用户组具有可读、可写及可执行的权限。
S_IRGRP 00040 权限,代表该文件用户组具有可写入的权限。
S_IXGRP 00010 权限,代表该文件用户组具有可执行的权限。
S_IRWXO 00007权限,代表其他用户具有可读、可写及可执行的权限。
S_IROTH 00004 权限,代表其他用户具有可读的权限
S_IWOTH 00002权限,代表其他用户具有可写入的权限。
S_IXOTH 00001 权限,代表其他用户具有可执行的权限。

错误代码:

代码说明
EEXIST参数pathname 所指的文件已存在,却使用了O_CREAT和O_EXCL旗标。
EACCESS参数pathname所指的文件不符合所要求测试的权限。
EROFS欲测试写入权限的文件存在于只读文件系统内。
EFAULT参数pathname指针超出可存取内存空间。
EINVAL参数mode 不正确。
ENAMETOOLONG参数pathname太长。
ENOTDIR参数pathname不是目录。
ENOMEM核心内存不足。
ELOOP参数pathname有过多符号连接问题。
EIO I/O存取错误。

close:

int close(int fd);
0:成功   -1:失败
EBADF 参数fd 非有效的文件描述词或该文件已关闭

2.read/write

size_t : unsigned int
ssize : int
read:

ssize_t read(int fd,void * buf ,size_t count);

返回实际读到大小   返回0 :表示已到达文件尾或是无可读取的数据,此外文件读写位置会随读取到的字节移动
返回-1:  错误代码存于errno
EINTR 此调用被信号所中断。
EAGAIN 当使用不可阻断I/O 时(O_NONBLOCK),若无数据可读取则返回此值。
EBADF 参数fd 非有效的文件描述词,或该文件已关闭。

write:

ssize_t write (int fd,const void * buf,size_t count);

返回实际写入大小
错误返回-1:
EINTR 此调用被信号所中断。
EAGAIN 当使用不可阻断I/O 时(O_NONBLOCK),若无数据可读取则返回此值。
EADF 参数fd非有效的文件描述词,或该文件已关闭。

3.lseek

off_t:long类型,其默认为一个32位的整数 64位: long long int

off_t lseek(int fildes,off_t offset ,int whence);
成功时则返回目前的从开头开始的读写位置

whence:
SEEK_SET 参数offset即为新的读写位置。
SEEK_CUR 以目前的读写位置往后增加offset个位移量。
SEEK_END 将读写位置指向文件尾后再增加offset个位移量。
当whence 值为SEEK_CUR 或SEEK_END时,参数offet允许负值的出现

4.ioctl/fcntl

ioctl:

int ioctl(int fd, unsigned long request, ...);

fcntl:

int fcntl(int fd , int cmd);
int fcntl(int fd,int cmd,long arg);
int fcntl(int fd,int cmd,struct flock * lock);

cmd:

F_GETFL 取得文件描述词状态旗标,此旗标为open()的参数flags。
F_SETFL 设置文件描述词状态旗标,参数arg为新旗标,但只允许O_APPEND、O_NONBLOCK和O_ASYNC位的改变,其他位的改变将不受影响。
F_SETFD 设置close-on-exec 旗标。该旗标以参数arg 的FD_CLOEXEC位决定。
F_GETLK 取得文件锁定的状态。
F_SETLK 设置文件锁定的状态。

四、进阶文件I/O

1.独占方式创建文件

open()时标志位 指定 O_EXCL|O_CREAT 如果打开已存在返回错误,保证进程是打开文件的创建者


2.向文件尾部追加数据 与非阻塞IO

open()时标志位 指定 O_APPEND
open()时标志位 指定 O_NONBLOCK

3.复制文件描述符

int dup (int oldfd);   返回新文件描述符
int dup2(int odlfd,int newfd);

4.在文件特定偏移量处的I/O:pread/pwrite

lseek跟read和write结合 如果分开会出现在当lseek和read之间被其他线程切走,而在此修改偏移就会有误,存在竞争 结合后保证原子性

ssize_t pread(int fd, void *buf, size_t count, off_t offset);

ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);

返回写或读的字节数,-1为失败

5.分散输入和集中输出:readv/writev

函数用于在一次函数调用中读、写多个非连续缓冲区

ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
从fd读取一片连续的字节,然后将其散置于iov指定缓冲区,从iov[0]开始依次填满
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
将iov指定所以缓冲区的数据集中起来,然后以连续的字节序列写入fd指向的文件中

ssize_t preadv(int fd, const struct iovec *iov, int iovcnt,off_t offset);
ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt,off_t offset);
readv/writev与lseek结合

iov:指向iovec 结构体
struct iovec {
    void  *iov_base;    /* Starting address */
    size_t iov_len;     /* Number of bytes to transfer */
};



iovcnt:指定iov成员个数

6.截断文件 truncate/ftruncate 与创建临时文件mkstemp/tmpfile

截断文件:

int truncate(const char *path, off_t length);//可直接使用,不用open得文件描述符
int ftruncate(int fd, off_t length);   //在调用open之后使用

返回0成功  -1失败

创建临时文件:

int mkstemp(char *template);
    template:最后6个字符必须为XXXXXX  如:char template[] = "/tmp/somestringXXXXXX"
删除临时文件: int unlink(const char * pathname);

FILE* tmpfile(void);
内部调用unlink

7.大文件I/O

a、通常将文件偏移量的数据类型off_t为一个有符号的长整型(-1来表示错误情况),在32位系统下,这将文件大小置于2^31 -1字节(2GB)的限制下。在64位系统长整型为64位。
如要访问大文件超过2GB,应用程序有两种方式:
1、备选API
2、将宏**_FILE_OFFSET_BITS 的值定义为64位。 #define _FILE_OFFSET_BITS 64 要求文件偏移量的变量应正确地使用off_t**,不能使用原生的C语言整数。

b、要打印off_t值 :printf(“offset = %lld \n”,(long long )offset);
限定符%lld和进行强制转换为long long

long int = int = 4字节
long long = 8字节

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值