Linux文件IO之二 [补档-2023-07-21]

发布时间 2024-01-13 16:57:57作者: 小白同学_C

8-5 linux系统IO函数:

open函数:

函数原型int open(const char *pathname, int flags, mode_t mode);

功能:打开一个文件并返回文件描述符。与c库中的fopen差不多

参数

pathname:要打开的文件路径名。

flags:打开文件的标志

O_RDONLY(只读)

O_WRONLY(只写)

O_RDWR(读写)

O_CREAT(创建文件)

O_APPEND(追加写)

mode(可选):新文件的访问权限,只有在创建新文件时才会使用。一般使用八进制表示.

0400:只读权限,允许文件所有者读取。

0200:只写权限,允许文件所有者写入。

0100:执行权限,允许文件所有者执行(对于可执行文件)。

0040:允许组成员读取。

0020:允许组成员写入。

0010:允许组成员执行(对于可执行文件)。

0004:允许其他用户读取。

0002:允许其他用户写入。

0001:允许其他用户执行(对于可执行文件)。

这些权限可以通过使用按位或运算符(|)来进行组合。

返回值:成功时返回文件描述符,失败时返回-1。

close函数:

函数原型int close(int fd);

功能:关闭一个已打开的文件。

参数:fd为要关闭的文件描述符。

返回值:成功时返回0,失败时返回-1。

​ 如果一个进程打开了某个文件,如果这个进程终止了,那么系统会自己调用clos函数关闭这些个已经 打开的文件。

read函数:

函数原型ssize_t read(int fd, void *buf, size_t count);

功能:从文件中读取数据。

参数

​ fd:要读取的文件描述符。

​ buf:用于存储读取数据的缓冲区指针。

​ count:要读取的字节数。

返回值:返回实际读取的字节数,若返回0表示已达到文件末尾,失败时返回-1。

write函数:

函数原型ssize_t write(int fd, const void *buf, size_t count);

功能:向文件中写入数据。

参数

​ fd:要写入的文件描述符。

​ buf:要写入的数据缓冲区指针。

​ count:要写入的字节数。

返回值:返回实际写入的字节数,失败时返回-1。

lseek函数:

头文件

#include<sys/types.h>

#include<unistd.h>

函数原型:off_t lseek(int fd , off_t offset , int whence);

功能:在文件读写操作中设置文件指针的偏移量。

参数

​ fd: 文件描述符

​ offset: 文件偏移量

​ whence:位置

SEEK_SET: 如果offset为0则代表是文件的开始位置

SEEK_CUR: 如果offset为0则代表当前位置

SEEK_END: 如果offset为0则代表文件的结尾位置

返回值:调用成功则返回从当前位置到开始的长度,调用失败则返回-1,

一. lseak函数的一些用法:

​ 移动文件读写位置:如果我们使用write函数往文件中写入了内容,然后调用read函数进行读文件, 会发现没有读到刚才写入的内容。那是因为当我们输入完毕以后,读写位置此时是在刚才输入的内容之后的, 因此什么也读不到,所以我们可以使用lseek函数将读写位置往回移一下。请在合适的位置调用以下函数。

lseek(fd , 0 , SEEK_SET); //将读写位置移动到文件首部。

二. 计算文件大小:因为lseek函数的返回值是offset到whence的大小。请在合适的位置调用以下函数。

lseek(fd , 0 , SEEK_END); //返回值为从0到文件末尾之间有多少字节

三. 拓展文件大小:lseek的偏移量大小是以offset到whence之间决定的(函数会相对于文件首部来计算, 也是就是说offset可以看作首部),如果我们将whence设置为文件末尾,offset我们设置为大于0的数,那么 在计算偏移量的时候就会向文件尾再偏移offset个字节,然后我们再写入offset个字节的数据,这样我们就可 以用来扩展文件的大小了。可以尝试在合适的位置调用以下函数:

lseek(fd , 10 , SEEK_END); //先扩展

write(fd , “a” , 1); //再写入

perror函数和errno:

头文件:#include<errno.h>

函数原型:void perror(const char* str);

功能:当系统调用出错时,系统会对errno自动赋值,perror可以将errno对应的错误信息打印出来。

参数

可以传入全局变量 “errno” 来打印相应的错误信息。

errno****变量:他在头文件<errno.h>中,当系统调用某个函数失败后会对该变量进行设置,相应的错误代码 会存储在该变量中。

8-6 文件IO的阻塞和非阻塞:

阻塞文件IO:当一个进程,线程或者其他什么东西对文件进行某些操作时,如果还有一个进程,线程或其 他什么东西也想对同一个文件进行操作。那么会将后面想要操作的进程,线程或者其他东西等阻塞,直到没有 东西对文件进行操作时,才可以去操作文件。

非阻塞文件IO:当一个进程,线程或者其他什么东西对文件进行某些操作时,如果还有一个进程,线程或 其他什么东西也想对同一个文件进行操作,那么后来的会直接返回,不会阻塞。

注意:如果多个进程,线程或者其他东西同时访问一个文件时,会触发竞争条件。linux多个线程,进程或 者其他东西访问同一个文件时,如果这个文件是普通文件则是非阻塞的,如果是终端设备或者管道和套接字那 就是阻塞的。

stat函数:

头文件:

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

函数原型:int stat(const char *path , struct stat *buf);

功能:通过文件路径来获取文件的相关信息,并且存储在结构体struct stat中.如果文件是个链接文件的话,那么会获取链接文件所指向的文件的信息

参数

​ path: 要获取文件信息的文件路径。

​ buf: 用于存储文件信息的结构体指针。

返回值

​ 成功时返回0,失败则返回-1。

lstat函数:

头文件

include <sys/types.h>

include <sys/stat.h>

include <unistd.h>

函数原型:int lstat(const char *path , struct stat *buf);

功能:通过文件路径来获取文件的相关信息,并且存储在结构体struct stat中.如果文件是个链接文件的话,那么会获取链接文件的信息,而不是获取链接文件指向的文件的信息。

参数

​ path: 要获取文件信息的文件路径。

​ buf: 用于存储文件信息的结构体指针。

返回值

​ 成功时返回0,失败则返回-1。

stat/lstat获取的stat结构体信息:

struct stat {

dev_t st_dev; // 文件的设备编号

ino_t st_ino; // 文件的 i-node 编号

mode_t st_mode; // 文件的类型和访问权限

nlink_t st_nlink; // 连接到该文件的硬链接数量

uid_t st_uid; // 文件所有者的用户 ID

gid_t st_gid; // 文件所有者的组 ID

dev_t st_rdev; // 如果文件是设备文件,则为其设备编号

off_t st_size; // 文件大小(以字节为单位)

blksize_t st_blksize; // 文件系统 I/O 缓冲区的优化大小

blkcnt_t st_blocks; // 分配给文件的块数

struct timespec st_atim; // 最后访问时间

struct timespec st_mtim; // 最后修改时间

struct timespec st_ctim; // 最后状态更改时间

};

stat结构体中成员变量mode_t st_mode;** 代表的是文件的类型和访问权限,它一共有16位:

0-2bit – 其他人权限:

S_IROTH 00004 读权限

S_IWOTH 00002 写权限

S_IXOTH 00001 执行权限

S_IRWXO 00007 掩码, 过滤 st_mode中除其他人权限以外的信息

3-5bit – 所属组权限:

S_IRGRP 00040 读权限

S_IWGRP 00020 写权限

S_IXGRP 00010 执行权限

S_IRWXG 00070 掩码, 过滤 st_mode中除所属组权限以外的信息

6-8bit – 文件所有者权限:

S_IRUSR 00400 读权限

S_IWUSR 00200 写权限

S_IXUSR 00100 执行权限

S_IRWXU 00700 掩码, 过滤 st_mode中除文件所有者权限以外的信息

12-15bit – 文件类型:

S_IFSOCK 0140000 套接字

S_IFLNK 0120000 符号链接(软链接)

S_IFREG 0100000 普通文件

S_IFBLK 0060000 块设备

S_IFDIR 0040000 目录

S_IFCHR 0020000 字符设备

S_IFIFO 0010000 管道

S_IFMT 0170000 掩码,过滤 st_mode中除文件类型以外的信息

目录打开函数opendir:

头文件:#include<dirent.h>

函数原型:DIR *opendir(const char *dirname);

函数功能:打开一个目录,并且返回一个DIR结构体指针。

函数参数:dirname是要打开的目录的路径名。

函数返回值:调用成功后返回一个指向DIR结构体的指针,如果调用失败则返回NULL。

条目读取函数readdir:

​ 头文件:#include<dirent.h>

函数原型:struct dirent *readdir(DIR *dirp);

函数功能:读取目录中的文件或者子目录,一次调用只读取一个。

函数参数:dirp是函数opendir返回的目录流指针。

函数返回值:调用成功后返回一个指向struct dirent结构体的指针,如果调用失败或者读取到目录末尾则 返回NULL。

struct dirent****结构体的内容:

struct dirent{

ino_t d_ino; //文件的 inode 号。

off_t d_of;://文件在目录流中的偏移。

unsigned short d_reclen; //该条目的长度。

unsigned char d_type; //文件类型。

char d_name[]; //文件名。

}

其中成员变量 d_type 是一个用于表示文件的类型,以下为它的取值:

DT_UNKNOWN:未知类型。

DT_REG:普通文件。

DT_DIR:目录。

DT_FIFO:命名管道(FIFO)。

DT_SOCK:套接字。

DT_CHR:字符设备。

DT_BLK:块设备。

DT_LNK:符号链接

目录关闭函数closedir:

头文件:#include<dirent.h>

函数原型:int closedir(DIR *dirp);

函数功能:关闭先前opendir打开的目录。

函数参数:dirp是原先opendir打开的目录流指针。

函数返回值:调用成功后返回0,调用失败返回-1.

以上三个目录函数的例子:

dup函数:

头文件#include<unsitd.h>

函数原型:int dup(int oldfd);

函数功能:赋值一个已有的文件描述符,并且返回一个新的文件描述符,这个新的文件描述符与原来的文件描述符指向同一个资源或者文件。

函数参数:oldfd为要赋值的旧的文件描述符。

返回值:成功则返回新的文件描述符,这个新的描述符与旧的所指向的文件或者资源是一样的。失败则返回-1.

dup2函数:

头文件#include<unsitd.h>

函数原型:int dup2(int oldfd , int newfd);

函数功能:将一个已有的文件描述符赋值到指定的文件描述符中,如果指定的文件描述符已经打开了一个文件,则会先关闭它,然后再将旧的文件描述符复制到这个位置。

函数参数

​ oldfd为要赋值的旧的文件描述符。

​ newfd 为要指定的新文件描述符

返回值:成功则返回新的文件描述符,失败则返回-1。

注意:dup2函数可以用于重定向标准输入,输出和错误流(描述符表的0 1 2号元素)。

fcntl函数:

头文件:#include<fcnt1.h>

函数原型:int fcnt1(int fd , int cmd , …);

函数功能:对文件描述符进行各种控制操作。

函数参数

​ fd 是要操作的文件描述符

​ cmd 是要执行的命令:

​ F_DUPFD:复制文件描述符。

​ F_GETFD:获取文件描述符标志。

​ F_SETFD:设置文件描述符标志。

​ F_GETFL:获取文件状态标志。

​ F_SETFL:设置文件状态标志。

​ … 这个是与命令相关的附加参数,更具命令的不同来进行传递。

返回值:返回值取决于命令,如果调用失败则返回-1.