温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Linux操作文件的底层系统怎么调用

发布时间:2023-03-23 17:18:41 来源:亿速云 阅读:321 作者:iii 栏目:开发技术

Linux操作文件的底层系统调用

引言

在Linux操作系统中,文件操作是最基本且重要的功能之一。无论是读取文件内容、写入数据,还是创建、删除文件,这些操作都依赖于底层的系统调用。系统调用是操作系统提供给用户程序的接口,允许用户程序请求操作系统执行某些特权操作。本文将深入探讨Linux中操作文件的底层系统调用,包括文件描述符、文件打开与关闭、文件读写、文件定位、文件状态获取与设置等内容。

文件描述符

在Linux中,文件描述符(File Descriptor)是一个非负整数,用于标识一个打开的文件。每个进程都有一个文件描述符表,用于记录该进程打开的文件。文件描述符表中的每个条目都指向一个文件表项,文件表项中包含了文件的打开模式、文件偏移量等信息。

文件描述符的分配

当进程打开一个文件时,内核会为该文件分配一个文件描述符。通常情况下,文件描述符从0开始分配,依次递增。标准输入、标准输出和标准错误输出的文件描述符分别为0、1和2。

int fd = open("example.txt", O_RDONLY);
if (fd == -1) {
    perror("open");
    exit(EXIT_FLURE);
}

在上面的代码中,open系统调用返回的文件描述符存储在fd变量中。如果open调用失败,返回-1,并设置errno以指示错误原因。

文件打开与关闭

打开文件

open系统调用用于打开一个文件,并返回一个文件描述符。open函数的原型如下:

#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(只写)、O_RDWR(读写)、O_CREAT(创建文件)等。
  • mode:当flags包含O_CREAT时,指定文件的权限模式。
int fd = open("example.txt", O_RDWR | O_CREAT, 0644);
if (fd == -1) {
    perror("open");
    exit(EXIT_FLURE);
}

在上面的代码中,open系统调用以读写模式打开example.txt文件,如果文件不存在则创建它,并设置文件权限为0644

关闭文件

close系统调用用于关闭一个文件描述符,释放相关资源。close函数的原型如下:

#include <unistd.h>

int close(int fd);
  • fd:要关闭的文件描述符。
if (close(fd) == -1) {
    perror("close");
    exit(EXIT_FLURE);
}

在上面的代码中,close系统调用关闭了文件描述符fd。如果close调用失败,返回-1,并设置errno以指示错误原因。

文件读写

读取文件

read系统调用用于从文件中读取数据。read函数的原型如下:

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);
  • fd:要读取的文件描述符。
  • buf:存储读取数据的缓冲区。
  • count:要读取的字节数。
char buffer[1024];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
if (bytes_read == -1) {
    perror("read");
    exit(EXIT_FLURE);
}

在上面的代码中,read系统调用从文件描述符fd中读取最多1024字节的数据,并将其存储在buffer中。如果read调用失败,返回-1,并设置errno以指示错误原因。

写入文件

write系统调用用于向文件中写入数据。write函数的原型如下:

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);
  • fd:要写入的文件描述符。
  • buf:要写入的数据缓冲区。
  • count:要写入的字节数。
const char *data = "Hello, World!";
ssize_t bytes_written = write(fd, data, strlen(data));
if (bytes_written == -1) {
    perror("write");
    exit(EXIT_FLURE);
}

在上面的代码中,write系统调用将字符串"Hello, World!"写入文件描述符fd。如果write调用失败,返回-1,并设置errno以指示错误原因。

文件定位

lseek系统调用用于移动文件的读写位置。lseek函数的原型如下:

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);
  • fd:要操作的文件描述符。
  • offset:偏移量。
  • whence:偏移量的基准位置,可以是SEEK_SET(文件开头)、SEEK_CUR(当前位置)、SEEK_END(文件末尾)。
off_t new_offset = lseek(fd, 10, SEEK_SET);
if (new_offset == -1) {
    perror("lseek");
    exit(EXIT_FLURE);
}

在上面的代码中,lseek系统调用将文件描述符fd的读写位置移动到文件开头后的第10个字节。如果lseek调用失败,返回-1,并设置errno以指示错误原因。

文件状态获取与设置

获取文件状态

fstat系统调用用于获取文件的状态信息。fstat函数的原型如下:

#include <sys/stat.h>

int fstat(int fd, struct stat *buf);
  • fd:要获取状态的文件描述符。
  • buf:存储文件状态信息的结构体指针。
struct stat st;
if (fstat(fd, &st) == -1) {
    perror("fstat");
    exit(EXIT_FLURE);
}

在上面的代码中,fstat系统调用获取文件描述符fd的状态信息,并将其存储在st结构体中。如果fstat调用失败,返回-1,并设置errno以指示错误原因。

设置文件权限

fchmod系统调用用于设置文件的权限。fchmod函数的原型如下:

#include <sys/stat.h>

int fchmod(int fd, mode_t mode);
  • fd:要设置权限的文件描述符。
  • mode:新的权限模式。
if (fchmod(fd, 0644) == -1) {
    perror("fchmod");
    exit(EXIT_FLURE);
}

在上面的代码中,fchmod系统调用将文件描述符fd的权限设置为0644。如果fchmod调用失败,返回-1,并设置errno以指示错误原因。

文件链接与删除

创建硬链接

link系统调用用于创建一个硬链接。link函数的原型如下:

#include <unistd.h>

int link(const char *oldpath, const char *newpath);
  • oldpath:现有文件的路径。
  • newpath:新链接的路径。
if (link("example.txt", "example_link.txt") == -1) {
    perror("link");
    exit(EXIT_FLURE);
}

在上面的代码中,link系统调用为example.txt文件创建了一个名为example_link.txt的硬链接。如果link调用失败,返回-1,并设置errno以指示错误原因。

删除文件

unlink系统调用用于删除一个文件。unlink函数的原型如下:

#include <unistd.h>

int unlink(const char *pathname);
  • pathname:要删除的文件路径。
if (unlink("example.txt") == -1) {
    perror("unlink");
    exit(EXIT_FLURE);
}

在上面的代码中,unlink系统调用删除了example.txt文件。如果unlink调用失败,返回-1,并设置errno以指示错误原因。

文件重命名

rename系统调用用于重命名或移动文件。rename函数的原型如下:

#include <stdio.h>

int rename(const char *oldpath, const char *newpath);
  • oldpath:原文件路径。
  • newpath:新文件路径。
if (rename("example.txt", "new_example.txt") == -1) {
    perror("rename");
    exit(EXIT_FLURE);
}

在上面的代码中,rename系统调用将example.txt文件重命名为new_example.txt。如果rename调用失败,返回-1,并设置errno以指示错误原因。

文件同步

fsync系统调用用于将文件数据同步到磁盘。fsync函数的原型如下:

#include <unistd.h>

int fsync(int fd);
  • fd:要同步的文件描述符。
if (fsync(fd) == -1) {
    perror("fsync");
    exit(EXIT_FLURE);
}

在上面的代码中,fsync系统调用将文件描述符fd的数据同步到磁盘。如果fsync调用失败,返回-1,并设置errno以指示错误原因。

文件锁定

fcntl系统调用用于对文件进行锁定操作。fcntl函数的原型如下:

#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );
  • fd:要操作的文件描述符。
  • cmd:操作命令,如F_SETLK(设置文件锁)、F_GETLK(获取文件锁)等。
  • arg:命令参数。
struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_pid = getpid();

if (fcntl(fd, F_SETLK, &fl) == -1) {
    perror("fcntl");
    exit(EXIT_FLURE);
}

在上面的代码中,fcntl系统调用对文件描述符fd设置了一个写锁。如果fcntl调用失败,返回-1,并设置errno以指示错误原因。

文件映射

mmap系统调用用于将文件映射到内存中。mmap函数的原型如下:

#include <sys/mman.h>

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
  • addr:映射的起始地址,通常为NULL,由系统自动选择。
  • length:映射的长度。
  • prot:映射区域的保护方式,如PROT_READ(可读)、PROT_WRITE(可写)等。
  • flags:映射标志,如MAP_SHARED(共享映射)、MAP_PRIVATE(私有映射)等。
  • fd:要映射的文件描述符。
  • offset:文件中的偏移量。
void *addr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (addr == MAP_FLED) {
    perror("mmap");
    exit(EXIT_FLURE);
}

在上面的代码中,mmap系统调用将文件描述符fd的前4096字节映射到内存中。如果mmap调用失败,返回MAP_FLED,并设置errno以指示错误原因。

文件截断

ftruncate系统调用用于截断文件到指定长度。ftruncate函数的原型如下:

#include <unistd.h>

int ftruncate(int fd, off_t length);
  • fd:要截断的文件描述符。
  • length:截断后的文件长度。
if (ftruncate(fd, 1024) == -1) {
    perror("ftruncate");
    exit(EXIT_FLURE);
}

在上面的代码中,ftruncate系统调用将文件描述符fd的文件截断为1024字节。如果ftruncate调用失败,返回-1,并设置errno以指示错误原因。

文件描述符复制

dupdup2系统调用用于复制文件描述符。dupdup2函数的原型如下:

#include <unistd.h>

int dup(int oldfd);
int dup2(int oldfd, int newfd);
  • oldfd:要复制的文件描述符。
  • newfd:新的文件描述符。
int new_fd = dup(fd);
if (new_fd == -1) {
    perror("dup");
    exit(EXIT_FLURE);
}

在上面的代码中,dup系统调用复制了文件描述符fd,并返回一个新的文件描述符new_fd。如果dup调用失败,返回-1,并设置errno以指示错误原因。

if (dup2(fd, new_fd) == -1) {
    perror("dup2");
    exit(EXIT_FLURE);
}

在上面的代码中,dup2系统调用将文件描述符fd复制到new_fd。如果dup2调用失败,返回-1,并设置errno以指示错误原因。

文件描述符控制

fcntl系统调用还可以用于控制文件描述符的属性。fcntl函数的原型如下:

#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );
  • fd:要操作的文件描述符。
  • cmd:操作命令,如F_SETFD(设置文件描述符标志)、F_GETFD(获取文件描述符标志)等。
  • arg:命令参数。
int flags = fcntl(fd, F_GETFD);
if (flags == -1) {
    perror("fcntl");
    exit(EXIT_FLURE);
}

flags |= FD_CLOEXEC;
if (fcntl(fd, F_SETFD, flags) == -1) {
    perror("fcntl");
    exit(EXIT_FLURE);
}

在上面的代码中,fcntl系统调用获取文件描述符fd的标志,并设置FD_CLOEXEC标志。如果fcntl调用失败,返回-1,并设置errno以指示错误原因。

文件描述符的异步I/O

aio_readaio_write系统调用用于进行异步I/O操作。aio_readaio_write函数的原型如下:

#include <aio.h>

int aio_read(struct aiocb *aiocbp);
int aio_write(struct aiocb *aiocbp);
  • aiocbp:异步I/O控制块指针。
struct aiocb aio;
aio.aio_fildes = fd;
aio.aio_buf = buffer;
aio.aio_nbytes = sizeof(buffer);
aio.aio_offset = 0;

if (aio_read(&aio) == -1) {
    perror("aio_read");
    exit(EXIT_FLURE);
}

在上面的代码中,aio_read系统调用从文件描述符fd中异步读取数据到buffer中。如果aio_read调用失败,返回-1,并设置errno以指示错误原因。

if (aio_write(&aio) == -1) {
    perror("aio_write");
    exit(EXIT_FLURE);
}

在上面的代码中,aio_write系统调用将buffer中的数据异步写入文件描述符fd。如果aio_write调用失败,返回-1,并设置errno以指示错误原因。

文件描述符的轮询

poll系统调用用于轮询多个文件描述符的状态。poll函数的原型如下:

#include <poll.h>

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
  • fds:轮询的文件描述符数组。
  • nfds:文件描述符数组的长度。
  • timeout:轮询的超时时间,单位为毫秒。
struct pollfd fds[1];
fds[0].fd = fd;
fds[0].events = POLLIN;

int ret = poll(fds, 1, 1000);
if (ret == -1) {
    perror("poll");
    exit(EXIT_FLURE);
}

在上面的代码中,poll系统调用轮询文件描述符fd的状态,等待1秒钟。如果poll调用失败,返回-1,并设置errno以指示错误原因。

文件描述符的选择

select系统调用用于监视多个文件描述符的状态。select函数的原型如下:

#include <sys/select.h>

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
  • nfds:要监视的文件描述符的最大值加1。
  • readfds:要监视的可读文件描述符集合。
  • writefds:要监视的可写文件描述符集合。
  • exceptfds:要监视的异常文件描述符集合。
  • timeout:超时时间。

”`c fd_set read_fds; FD_ZERO(&read_fds); FD_SET(fd, &read_fds

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI