linux系统io文件操作函数

历史:
2023-2-23
初版。
1.系统文件api不够完善,待补充
2.write/read,一次调用返回值和预写入值不一致怎么处理。
3.函数的排版和历程怎么优化更好。
4.做笔记的目标是:模块化单个知识点,争取知识点简明。

1.open()函数

1.头文件:
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
2.函数原型:
int open(const char *path, int oflags, mode_tmode);
3.函数说明:
open建立了一条到文件或设备的访问路径。open函数一般用于打开或者创建文件,在打开或创建文件时可以制定文件的属性及用户的权限。
4.参数:
path:路径名或者文件名。路径名为绝对路径名(如/home/a.txt)。若是没有路径,则表示文件在当前工作目录下。
oflags:打开文件所采取的动作。
打开/创建文件时,必须使用下述三个常量中的一个(有且只能选其中一个,三者互斥):
O_RDONLY(只读),
O_WRONLY(只写),
O_RDWR(可读可写)
以下常量是可选用的,可选一个或者同时选多个:
O_APPEND 每次写操作都写入文件的末尾(追加)
O_CREAT 如果指定文件不存在,则创建这个文件
O_EXCL 如果要创建的文件已存在,则返回 -1,并且修改errno的值
O_TRUNC 如果文件存在,并且以只写/读写方式打开,则清空文件全部内容
O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件打开后 I/O设置为非阻塞模式(nonblocking mode)
mode:设置文件访问权限的初始值。(与用户掩码umask变量有关,实际的访问权限用mode &~umask确定)
mode使用宏定义:
S_IRUSR,S_IWUSR,S_IXUSR, S_IRGRP,S_IWGRP,S_IXGRP, S_IROTH,S_IWOTH,S_IXOTH.
其中R:读,W:写,X:执行,
USR:文件所属的用户,GRP:文件所属的组,OTH:其他用户。
mode用八进制定义:
0777表示 文件所有者 该文件用户组 其他用户 都有可读可写可执行权限
(-r wx:-421)(读写执行对应8进制的 4 2 1)
注:第三个参数是在第二个参数中有O_CREAT时才起作用。若没有,则第三个参数可以忽略。
5. 返回值:
如果操作成功,它将返回一个文件描述符(俗称句柄file descriptor 简称fd),如果失败,返回-1

2.close()函数

1.头文件:
#include<unistd.h>
2.函数原型:
int close(int fd);
3.函数说明:
关闭一个已打开的文件。
4.参数
参数fd: 由open返回的文件描述符
5.返回值:
成功返回0,出错返回-1并设置errno
6.备注:
当一个进程终止时,内核对该进程所有尚未关闭的文件描述符调用close关闭,所以即使用户程序不调用close,在程序终止时内核也会自动关闭它打开的所有文件。

3.write()函数

1.头文件:
#include<unistd.h>
2.函数原型:
size_t write (int fd,const void * buf,size_t count);
3.函数说明:
write()会把指针buf所指的内存写入count个字节到参数fd所指的文件内。当然,文件读写位置也会随之移动
4.参数:
Fd:文件描述符
Buf:存放要写入的数据的缓存区首地址
Count:想要写入的字节数
5.返回值:
write()返回实际写入的字节数(返回值可以和count不相等)。当有错误发生时则返回-1,错误代码存入errno中。错误码:
EINTR 此调用被信号所中断。
EAGAIN 当使用不可阻断I/O 时(O_NONBLOCK),若无数据可读取则返回此值。
EBADF 参数fd非有效的文件描述词,或该文件已关闭。
6.备注:
(1)write()函数返回值一般无0,只有当如下情况发生时才会返回0:len=write(fp, p1+len, (strlen(p1)-len))中第三参数为0,此时write()什么也不做,只返回0。
(2)write()函数从buf写数据到fd中时,若buf中数据无法一次性读完,那么第二次读buf中数据时,其读位置指针(也就是第二个参数buf)不会自动移动,需要程序员来控制,而不是简单的将buf首地址填入第二参数即可。如可按如下格式实现读位置移动:write(fp, p1+len, (strlen(p1)-len))。 这样write第二次循环时便会从p1+len处写数据到fp, 之后的也一样。由此类推,直至(strlen(p1)-len)变为0。
(3)在write一次可以写的最大数据范围内(貌似是BUFSIZ ,8192),第三参数count大小最好为buf中数据的大小,以免出现错误。(待确认)

4.read()函数

1.头文件:
#include <unistd.h>
2.函数原型:
ssize_t read(int fd, void * buf, size_tcount);
3.函数说明:
read()会把参数fd所指的文件传送count 个字节到buf 指针所指的内存中。
4.参数:
fd: 将要读取数据的文件描述词。
buf: 所读取到的数据的内存缓冲。
count: 需要读取的数据量。
5.返回值:
成功执行时,返回所读取的数据量。失败返回-1,errno被设为以下的某个值
EAGAIN:打开文件时设定了O_NONBLOCK标志,并且当前没有数据可读取
EBADF:文件描述词无效,或者文件不可读
EFAULT:参数buf指向的空间不可访问
EINTR:数据读取前,操作被信号中断
EINVAL:一个或者多个参数无效
EIO:读写出错
EISDIR:参数fd索引的时目录

6.备注:
返回值:返回值为实际读取到的字节数, 如果返回0, 表示已到达文件尾或是无可读取的数据。若参数count 为0, 则read()不会有作用并返回0。另外,以下情况返回值小于count:
(1)读常规文件时,在读到count个字节之前已到达文件末尾。例如,距文件末尾还有50个字节而请求读100个字节,则read返回50,下次read将返回0。
(2)对于网络套接字接口,返回值可能小于count,但这不是错误。
注意:read时fd中的数据如果小于要读取的数据,就会引起阻塞。以下情况read不会引起阻塞:
(1)常规文件不会阻塞,不管读到多少数据都会返回;
(2)从终端读不一定阻塞:如果从终端输入的数据没有换行符,调用read读终端设备会阻塞,其他情况下不阻塞;
(3)从网络设备读不一定阻塞:如果网络上没有接收到数据包,调用read会阻塞,除此之外读取的数值小于count也可能不阻塞,原因见上面链接。

5.lseek()函数

1.头文件:
#include <sys/types.h>
#include <unistd.h>
2.函数原型:
off_t lseek(int fd, off_t offset, intwhence);光标的偏移量
3.函数说明:
打开的每个文件都有一个与其相关联的“当前文件位移量”。它是一个非负的整数,用以度量从文件开始处计算的字节数。
通常,读、写操作都从当前文件位移量处开始,并使位移量增加所读或写的字节数。按系统默认,当打开一个文件时,
除非指定O_APPEND选择项,否则该位移量被设置为0。
4.参数:
fd : 文件描述符
Offffset :偏移量
Whence :
SEEK_SET: 参数 offffset 即为新的读写位置
SEEK_CUR: 以目前的读写位置往后增加offffset 个偏移量
SEEK_END: 将读写位置指向文件尾后再增加 offffset 个位移量,当 whence 值为 SEEK_CUR 或 SEEK_END 时,参数 offffset 允许负值的出现
5.返回值:
文件读写距离文件开头的字节大小,出错返回 -1

6.备注:
open函数与C标准I/O库的fopen函数有些细微的区别:
  以可写的方式fopen一个文件时,如果文件不存在会自动创建,而open一个文件时必须明确指定O_CREAT才会创建文件,否则文件不存在就出错返回。
  以w或w+方式fopen一个文件时,如果文件已存在就截断为0字节,而open一个文件时必须明确指定O_TRUNC才会截断文件,否则直接在原来的数据上改写。
  第三个参数mode指定文件权限,可以用八进制数表示,比如0644表示-rw-r-r–,也可以用S_IRUSR、S_IWUSR等宏定义按位或起来表示,详见open(2)的Man Page。要注意的是,文件权限由open的mode参数和当前进程的umask掩码共同决定。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>    //前三个是open函数头文件

#include <unistd.h>    //close头文件
#include <stdio.h>    //perror头文件
#include <stdlib.h>    //exit头文件
#include <string.h>
#include <errno.h>
#include "share.h"

void sys_io_hander_open(void)
{
    int fd;

    //打开文件
    //fd = open("a_sys_io_test.txt", O_RDWR);          
    //若该文件没有,则报错. Open file error: No such file or directory


    //fd = open("a_sys_io_test.txt", O_RDWR | O_CREAT);    
    //若是文件不存在,则创建文件。由于没有第三个参数,所以这个文件没有用户的读写之类的权限。
    // 0 ----r-x--T  1 ol ol     0 2月  20 10:49 a_sys_io_test.txt
    //当第二次再运行同样的程序的时候,就会报错:
    //Open file error: Permission denied


    //fd = open("a_sys_io_test.txt", O_RDWR | O_CREAT, S_IRUSR | S_IRGRP | S_IROTH );
    //若是文件不存在,则创建文件,并且赋予第三个参数相应的权限(也和umask有关)
    // 0 -r--r--r--  1 ol ol     0 2月  20 11:14 a_sys_io_test.txt
    //当第二次再运行同样的程序的时候,就会报错:(文件操作的方式要和文件用户的权限保持一致)
    //Open file error: Permission denied

    //fd = open("a_sys_io_test.txt", O_RDWR | O_CREAT, S_IRUSR |S_IWUSR | S_IRGRP | S_IROTH );
    //若是文件存在,则成功打开文件.
    //若是文件不存在,则创建文件,并且赋予第三个参数相应的权限(也和umask有关)
    // 0 -rw-r--r--  1 ol ol     0 2月  20 11:20 a_sys_io_test.txt
    //当第二次再运行同样的程序的时候,依然成功打开。(成功打开表示重新创建的吗,还是没有重新创建)
    //Create 3 success!

    //fd = open("a_sys_io_test.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP| S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);    
    //若是文件存在就打开。
    //若是文件不存在,就创建文件,并且赋予第三个参数相应的权限(也和umask有关)
    // 0 -rwxrwxr-x  1 ol ol     0 2月  20 11:05 a_sys_io_test.txt
    //若是文件被之前调用创建,文件的权限如下:
    // 0 -rw-r--r--  1 ol ol     0 2月  20 11:20 a_sys_io_test.txt
    //再次调用这个函数,也不会去改变文件的权限。依然还是权限:
    // 0 -rw-r--r--  1 ol ol     0 2月  20 11:20 a_sys_io_test.txt


    //fd = open("a_sys_io_test.txt", O_RDWR | O_EXCL, 0777 );
    //参数O_EXCL用来判断文件是否存在,其必须与O_CREAT一起使用才能判断文件是否存在
    //1.若是文件存在,则打开文件成功。(O_EXCL不起作用)
    //2.若是文件不存在,则打开文件失败。(O_EXCL不起作用)
    //Open file error: No such file or directory

    //fd = open("a_sys_io_test.txt", O_RDWR | O_CREAT | O_EXCL, 0777 );
    //参数O_EXCL用来判断文件是否存在,其必须与O_CREAT一起使用才能判断文件是否存在
    //1.若是文件存在,则b报错
    //Open file error: File exists
    //2.若是文件不存在,则创建文件
    //Create 3 success!
    //O_EXCL:意义是和O_CREAT一起使用,当没有时候,创建文件,当文件存在的时候,就判断出文件已经存在,不再创建,并报错出来,提醒已经创建文件了。

    //打开文件失败
    if (fd== -1)
    {
        perror("Open file error");//通过errno函数的返回值,perror把提示信息和错误信息一起输出
        exit(1);
    }
    
    printf("Create %d success!\n",fd);
    close(fd);    //关闭文件,fd为open函数返回的文件描述符

    return;
} 

//linux shell 指令: umask 0123 #把本地的掩码修改成0123
//其中后面三个数字分别代表文件的所有者、所属组、其他用户的权限
//通过设置数字表示取消该用户对文件的权限;上述1表示取消了用户的执行权限,2表示取消了用户组的写权限
void sys_io_hander_umask(void)
{
    umask(0777);//其中后面三个数字分别代表文件的所有者、所属组、其他用户的权限

    int fd = open("a_sys_io_test.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IXUSR );
    if (fd== -1)
    {
        perror("Open file error");//通过errno函数的返回值,perror把提示信息和错误信息一起输出
        exit(1);
    }
    
    printf("Create %d success!\n",fd);
    close(fd);    //关闭文件,fd为open函数返回的文件描述符
}

void sys_io_hander_O_TRUNC(void)
{
    int fd;
    char write_buf[64] = "dayup";
    char read_buf[64]  = {0};

    //fd = open("a_sys_io_test.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR );//创建文件
    //fd = open("a_sys_io_test.txt", O_RDWR | O_TRUNC );//O_TRUNC将文件截断为零,即清空文件内容 
    fd = open("a_sys_io_test.txt", O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR );//O_CREAT和O_TRUNC可以并列使用,没有文件就创建,有文件就截断为0
    if(-1 == fd)
    {
        perror("Open file error");
        return;
    }

    int ret_write = write(fd, write_buf, 5);
    printf("ret_write:%d\r\n", ret_write); 

    close(fd);
    return ;
}

void sys_io_hander_write_read(void)
{
    char write_buf[64] = "dayup";
    char read_buf[64]  = {0};

    int fd = open("a_sys_io_test.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR ); 
    if(-1 == fd)
    {
        perror("Open file error");
        return;
    }
 
    int ret_write = write(fd, write_buf, 3);

    if (-1 == lseek(fd, 0, SEEK_SET))
    {
        perror("lseek error");
        return;
    }

    int ret_read = read(fd, read_buf, 2);

    printf("ret_write:%d\r\n", ret_write);
    //ret_write:3
    printf("ret_read :%d\r\n", ret_read);
    //ret_read :2
    printf("read_buf :%s\r\n", read_buf);
    //read_buf :da

    close(fd);
    return ;
}

int main()
{
    //测试open函数
    //sys_io_hander_open();
    
    //测试umask
    sys_io_hander_umask();

    //测试O_TRUNC
    //sys_io_hander_O_TRUNC();

    //测试write/read/lseek
    //sys_io_hander_write_read();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值