Linux开发之文件IO(2023.04.18)

文件IO

C语言中有文件IO相关的库函数(fopen等),他的实际上是经过了某些步骤,然后调用linux系统调用。

这篇文章,要讲的是linux系统调用的文件IO,如open,close,read等。

预备知识

文件描述符

在linux中,程序打开的文件,会有一个整数指向它,这就叫文件描述符。通过对文件描述符进行操作,就能实际操作到打开的文件上。

文件描述符默认从3开始分配,因为0,1,2已经被占用,分别是标准输入,标准输出以及标准错误,这3个都指向当前终端。每打开一个新的文件,都会分配最小的未使用的文件描述符(系统做这个工作)。

man

linux的官方文档就是man手册,在学习系统调用时候查阅man手册很重要。系统函数在man的第2卷,比如想要查阅open系统函数可以输入man 2 open

open函数文档

perror()

打印errno所代表的错误信息。

// 所需头文件(之后将不再解释
#include <stdio.h>

void perror(const char *s);

s是展示给用户的字符串。

struct stat

stat()中涉及到的结构体,用来存储文件信息。

struct stat {
	dev_t st_dev; // 文件的设备编号
	ino_t st_ino; // 节点
	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; // 块大小
	blkcnt_t st_blocks; // 块数
	time_t st_atime; // 最后一次访问时间 可能类型为struct timespec
	time_t st_mtime; // 最后一次修改时间 同上
	time_t st_ctime; // 最后一次改变时间(指属性) 同上
};

其中st_mode含义如下,图源自牛客大学。
st_mode

IO system call

open()

open函数用来打开文件。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
  • pathname:的是文件路径。
  • flags:打开方式。必须包含这三个之一(O_RDONLY, O_WRONLY, or O_RDWR)。还有一些可选的,可以用按位或来选中。可选项如下:
    • O_APPEND:使用追加模式打开文件。
    • O_CREAT:如果文件不存在将创建文件。
  • mode:创建文件的权限,八进制形式(如0777)。不过文件最终权限=mode&~umask。(通过命令umask来查看)。

返回值是文件描述符(>0),如果文件打开失败,将返回-1,并设置errno。

read()

read函数用来从文件中读取数据。

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
  • fd:要读取的文件的文件描述符。
  • buf:要把读取到的数据存到哪里
  • count:读取的大小

返回值是实际读取到的大小,如果>0表示读取正常,如果=0表示读完文件了,如果=-1表示读取错误,并设置errno。

write()

write函数用来在文件中写入数据。

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);
  • fd:要写入的文件的文件描述符。
  • buf:要写入的数据的地址
  • count:写入的大小

返回值是实际读写入的大小,如果=-1表示写入错误,并设置errno。

lseek()

修改文件的指针偏移。

#include <sys/types.h>
#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);
  • fd:文件描述符
  • offset:偏移量
  • whence:偏移方式,有以下选项
    • SEEK_SET:设置文件偏移为 文件开头+offset
    • SEEK_CUR:设置文件偏移为 当前偏移+offset
    • SEEK_END:设置文件偏移为 文件末尾+offset

文件返回设置成功后的偏移位置。如果=-1表示读取错误,并设置errno。

lseek经常有以下作用

  • 移动文件指针到文件头lseek(df, 0, SEEK_SET)
  • 获取当前文件指针位置lseek(df, 0, SEEK_CUR)
  • 获取当前文件文件大小lseek(df, 0, SEEK_END)
  • 扩展文件长度(最后要写入数据)lseek(df, 100, SEEK_END);write(df, " ", 1);

stat()与lstat()

获取文件信息。

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int stat(const char *pathname, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
  • pathname:文件路径
  • statbuf:传出参数,获取到的信息将存入其中。

获取信息成功将返回0,如果返回-1表示获取错误,并设置errno。
statlstat区别就在于,前者获取软连接文件将获取到软连接指向的文件,而后者将获取到软连接文件本身。
实战案例:linux开发之ls -l命令实现

access()

检测用户是否有对应文件的权限,或检测文件是否存在。

#include <unistd.h>

int access(const char *pathname, int mode);
  • pathname:文件路径
  • mode:指名要检测的权限,有如下权限:
    • R_OK:检测是否有读权限。
    • W_OK:检测是否有写权限。
    • X_OK:检测是否有执行权限。
    • F_OK:检测文件是否存在。

如果用户具有对应的权限,或者文件存在则返回0,否则返回-1,并设置errno。

chmod()

更改文件权限。

#include <sys/stat.h>

int chmod(const char *pathname, mode_t mode);
  • pathname:文件路径
  • mode:可以是八进制数,也可以是具体的宏,具体请查看man。

设置成功将返回0,否则返回-1,并设置errno。

chown()

更改文件所有者,组。

#include <unistd.h>

int chown(const char *pathname, uid_t owner, gid_t group);
  • pathname:文件路径
  • owner:目标用户的用户号,如为-1则表示不变。
  • group:目标组的组号,如为-1则表示不变。

设置成功将返回0,否则返回-1,并设置errno。

truncate()

更改文件大小。

#include <unistd.h>
#include <sys/types.h>

int truncate(const char *path, off_t length);
  • path:文件路径
  • length:目标长度

设置成功将返回0,否则返回-1,并设置errno。

rename()

重命名或改变路径文件或文件夹。

#include <stdio.h>

int rename(const char *oldpath, const char *newpath);
  • oldpath:旧的文件路径
  • newpath:新的文件路径

若newpath已存在,则直接覆盖。
更改成功将返回0,否则返回-1,并设置errno。

chdir()

更改进程工作目录。

#include <unistd.h>

int chdir(const char *path);
  • path:目标目录

更改成功将返回0,否则返回-1,并设置errno。

getcwd()

获取当前工作目录。

#include <unistd.h>

char *getcwd(char *buf, size_t size);
  • buf:传出参数,存放工作目录
  • size:指名buf的长度

获取成功将返回buf,失败将返回NULL,并设置errno。

mkdir()

创建目录。

#include <sys/stat.h>
#include <sys/types.h>

int mkdir(const char *pathname, mode_t mode);
  • pathname:文件夹路径
  • mode:创建文件的权限,八进制形式(如0777)。不过文件最终权限=mode&~umask。(通过命令umask来查看)。
    创建成功将返回0,否则返回-1,并设置errno。

rmdir()

删除目录。

#include <unistd.h>

int rmdir(const char *pathname);
  • pathname:文件夹路径
    删除成功将返回0,否则返回-1,并设置errno。
posted @ 2023-04-16 23:33  1v7w  阅读(41)  评论(3编辑  收藏  举报