1.1 函数原型代码语言javascriptAI代码解释#include fcntl.h int creat(const char *pathname, mode_t mode);1.2 参数说明pathname指向要创建的文件路径名的字符串指针。可以是绝对路径也可以是相对路径。mode指定新文件的权限模式。它由一系列权限位组成这些权限位决定了文件所有者、所属组和其他用户对该文件的访问权限。常见的权限位有S_IRUSR所有者具有读权限0400S_IWUSR所有者具有写权限0200S_IXUSR所有者具有执行权限0100S_IRGRP所属组具有读权限0040S_IWGRP所属组具有写权限0020S_IXGRP所属组具有执行权限0010S_IROTH其他用户具有读权限0004S_IWOTH其他用户具有写权限0002S_IXOTH其他用户具有执行权限0001这些权限位可以通过按位或|运算组合使用例如S_IRUSR | S_IWUSR 表示所有者具有读写权限。1.3 返回值成功返回一个非负的文件描述符file descriptor该文件描述符用于后续对文件的操作。失败返回 - 1并设置 errno 来指示错误类型。常见的错误有EEXIST指定的文件已经存在且没有被截断当使用 O_CREAT | O_EXCL 标志时如果文件存在则会返回该错误但 creat 系统调用本身如果文件存在会截断文件所以此错误在 creat 中较少见ENOENT路径名中的目录不存在EACCES没有权限创建文件或访问路径中的目录ENOSPC文件系统没有足够的空间创建新文件1.4 使用示例代码语言javascriptAI代码解释#include stdio.h #include fcntl.h #include stdlib.h int main() { int fd; // 创建一个名为testfile.txt的文件所有者具有读写权限所属组和其他用户无权限 fd creat(testfile.txt, S_IRUSR | S_IWUSR); if (fd -1) { perror(creat failed); exit(EXIT_FAILURE); } printf(File created successfully with file descriptor: %d\n, fd); close(fd); // 创建文件后要记得关闭文件描述符 return 0; }使用 creat 函数创建了一个名为 “testfile.txt” 的文件设置所有者具有读写权限。如果创建成功会输出文件描述符如果失败会通过 perror 函数打印错误信息。二、文件打开open 系统调用open 系统调用是 Linux 中用于打开一个已存在的文件或创建一个新文件的主要系统调用。它比 creat 系统调用功能更强大可以通过不同的标志组合实现多种操作。2.1 函数原型代码语言javascriptAI代码解释#include fcntl.h int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);2.2 参数说明pathname与 creat 系统调用中的 pathname 参数相同指向要打开或创建的文件路径名。flags用于指定打开文件的方式和行为是一个整数可以由多个标志按位或组合而成。常见的标志有O_RDONLY以只读方式打开文件O_WRONLY以只写方式打开文件O_RDWR以读写方式打开文件O_CREAT如果指定的文件不存在则创建该文件。此时需要提供第三个参数 mode 来指定新文件的权限。O_EXCL与 O_CREAT 一起使用如果文件已经存在则 open 调用失败返回 - 1可以用于防止覆盖已存在的文件。O_TRUNC如果文件已经存在且以可写方式打开O_WRONLY 或 O_RDWR则将文件截断为零长度。O_APPEND以追加方式打开文件每次写操作都将数据添加到文件的末尾。mode当 flags 中包含 O_CREAT 标志时该参数用于指定新文件的权限模式与 creat 系统调用中的 mode 参数相同。如果 flags 中不包含 O_CREAT则该参数被忽略。2.3 返回值成功返回一个非负的文件描述符用于后续对文件的操作。失败返回 - 1并设置 errno 指示错误类型。常见的错误与 creat 系统调用类似此外还有EINVALflags 参数无效EMFILE进程已打开的文件描述符达到上限2.4 使用示例代码语言javascriptAI代码解释#include stdio.h #include fcntl.h #include stdlib.h #include unistd.h int main() { int fd1, fd2, fd3; // 以只读方式打开已存在的文件testfile.txt fd1 open(testfile.txt, O_RDONLY); if (fd1 -1) { perror(open for read failed); exit(EXIT_FAILURE); } // 以读写方式打开文件如果文件不存在则创建权限为所有者读写组和其他用户只读 fd2 open(newfile.txt, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd2 -1) { perror(open for read-write and create failed); close(fd1); exit(EXIT_FAILURE); } // 以只写、追加方式打开文件若文件不存在则创建 fd3 open(logfile.txt, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR); if (fd3 -1) { perror(open for write and append failed); close(fd1); close(fd2); exit(EXIT_FAILURE); } printf(fd1: %d, fd2: %d, fd3: %d\n, fd1, fd2, fd3); // 关闭文件描述符 close(fd1); close(fd2); close(fd3); return 0; }展示了 open 系统调用的几种常见用法只读打开已存在文件、读写打开并创建新文件、只写追加打开并创建新文件。三、文件读写read 和 write 系统调用打开文件后就可以进行读写操作了。Linux 提供了 read 和 write 系统调用来实现对文件的读写。3.1 read 系统调用read 系统调用用于从已打开的文件中读取数据。①函数原型代码语言javascriptAI代码解释#include unistd.h ssize_t read(int fd, void *buf, size_t count);②参数说明fd文件描述符即 open 或 creat 系统调用返回的非负整数标识要读取的文件。buf指向一个缓冲区的指针用于存储读取到的数据。count指定要读取的字节数。③ 返回值成功返回实际读取到的字节数。如果已经到达文件末尾则返回 0。失败返回 - 1并设置 errno 指示错误类型如 EBADF文件描述符无效、EIOI/O 错误等。3.2 write 系统调用write 系统调用用于向已打开的文件中写入数据。①函数原型代码语言javascriptAI代码解释#include unistd.h ssize_t write(int fd, const void *buf, size_t count);②参数说明fd文件描述符标识要写入的文件。buf指向一个缓冲区的指针该缓冲区中存储了要写入的数据。count指定要写入的字节数。③返回值成功返回实际写入的字节数。注意实际写入的字节数可能小于 count这并不一定表示错误可能是由于各种原因如磁盘空间不足、信号中断等导致的。失败返回 - 1并设置 errno 指示错误类型如 EBADF文件描述符无效或不具有写权限、EIOI/O 错误等。3.3 使用示例代码语言javascriptAI代码解释#include stdio.h #include fcntl.h #include stdlib.h #include unistd.h #include string.h int main() { int fd; char write_buf[] Hello, Linux File Operation!; char read_buf[1024]; ssize_t nwritten, nread; // 以读写方式打开文件不存在则创建 fd open(rwtest.txt, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd -1) { perror(open failed); exit(EXIT_FAILURE); } // 写入数据 nwritten write(fd, write_buf, strlen(write_buf)); if (nwritten -1) { perror(write failed); close(fd); exit(EXIT_FAILURE); } printf(Wrote %zd bytes: %s\n, nwritten, write_buf); // 将文件指针移到文件开头否则读取不到刚写入的数据 off_t offset lseek(fd, 0, SEEK_SET); if (offset -1) { perror(lseek failed); close(fd); exit(EXIT_FAILURE); } // 读取数据 nread read(fd, read_buf, sizeof(read_buf) - 1); // 留一个字节给\0 if (nread -1) { perror(read failed); close(fd); exit(EXIT_FAILURE); } else if (nread 0) { printf(Reached end of file\n); } else { read_buf[nread] \0; // 加上字符串结束符 printf(Read %zd bytes: %s\n, nread, read_buf); } close(fd); return 0; }先向文件写入一段字符串然后使用 lseek 系统调用将文件指针移到文件开头再读取文件内容并打印。需要注意的是write 调用返回的实际写入字节数可能小于请求的字节数因此在实际应用中可能需要循环写入直到所有数据都被写入。同样read 调用也可能需要循环读取直到读取到预期的数据量或到达文件末尾。四、文件定位lseek 系统调用在对文件进行读写操作时系统会维护一个文件偏移量file offset也称为文件指针它指示了下一次读写操作开始的位置。lseek 系统调用用于修改这个文件偏移量实现对文件的随机访问。4.1 函数原型代码语言javascriptAI代码解释#include unistd.h off_t lseek(int fd, off_t offset, int whence);4.2 参数说明fd文件描述符标识要操作的文件。offset偏移量是一个有符号整数表示要移动的字节数。whence用于指定偏移量的参考位置有以下三种取值SEEK_SET将文件偏移量设置为 offset 字节从文件开头开始计算。SEEK_CUR将文件偏移量设置为当前偏移量加上 offset 字节。SEEK_END将文件偏移量设置为文件末尾加上 offset 字节offset 为负时表示向文件开头方向移动。4.3 返回值成功返回新的文件偏移量从文件开头开始计算的字节数。失败返回 - 1并设置 errno 指示错误类型如 EBADF文件描述符无效、ESPIPE文件是管道、FIFO 或套接字这些文件不支持定位操作等。4.4 使用示例代码语言javascriptAI代码解释#include stdio.h #include fcntl.h #include stdlib.h #include unistd.h #include string.h int main() { int fd; char buf[100]; off_t offset; // 创建并打开一个文件 fd open(seektest.txt, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd -1) { perror(open failed); exit(EXIT_FAILURE); } // 写入一些数据 const char *data 0123456789abcdefghijklmnopqrstuvwxyz; write(fd, data, strlen(data)); // 将文件指针移到开头 offset lseek(fd, 0, SEEK_SET); if (offset -1) { perror(lseek to beginning failed); close(fd); exit(EXIT_FAILURE); } printf(Moved to beginning, offset: %ld\n, (long)offset); // 读取5个字节 ssize_t nread read(fd, buf, 5); if (nread -1) { perror(read failed); close(fd); exit(EXIT_FAILURE); } buf[nread] \0; printf(Read %zd bytes: %s\n, nread, buf); // 从当前位置向后移动10个字节 offset lseek(fd, 10, SEEK_CUR); if (offset -1) { perror(lseek from current failed); close(fd); exit(EXIT_FAILURE); } printf(Moved 10 bytes from current, new offset: %ld\n, (long)offset); // 读取5个字节 nread read(fd, buf, 5); if (nread -1) { perror(read failed); close(fd); exit(EXIT_FAILURE); } buf[nread] \0; printf(Read %zd bytes: %s\n, nread, buf); // 从文件末尾向前移动20个字节 offset lseek(fd, -20, SEEK_END); if (offset -1) { perror(lseek from end failed); close(fd); exit(EXIT_FAILURE); } printf(Moved 20 bytes before end, new offset: %ld\n, (long)offset); // 读取5个字节 nread read(fd, buf, 5); if (nread -1) { perror(read failed); close(fd); exit(EXIT_FAILURE); } buf[nread] \0; printf(Read %zd bytes: %s\n, nread, buf); close(fd); return 0; }展示了 lseek 系统调用的三种使用方式从文件开头设置偏移量、从当前位置调整偏移量、从文件末尾调整偏移量。通过 lseek我们可以灵活地定位到文件的任意位置进行读写操作实现随机访问。