Linux 文件操作:系统调用与标准库函数接口汇总及代码示例
1. 文件操作的系统调用和库函数各个接口
1.1 C 语言文件操作常用接口
| 函数名 | 功能 | 头文件 | 参数说明 |
|---|
fopen | 打开文件 | stdio.h | FILE* fopen(const char* filename, const char* mode) |
fclose | 关闭文件 | stdio.h | int fclose(FILE* stream) |
fputc | 写入一个字符 | stdio.h | int fputc(int char, FILE* stream) |
fgetc | 读取一个字符 | stdio.h | int fgetc(FILE* stream) |
fputs | 写入一个字符串 | stdio.h | int fputs(const char* str, FILE* stream) |
fgets | 读取一个字符串 | stdio.h | char* fgets(char* str, int n, FILE* stream) |
fprintf | 格式化写入数据 | stdio.h | int fprintf(FILE* stream, const char* format, ...) |
fscanf | 格式化读取数据 | stdio.h | int fscanf(FILE* stream, const char* format, ...) |
fwrite | 向二进制文件写入数据 | stdio.h | size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream) |
fread | 从二进制文件读取数据 | stdio.h | size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream) |
fseek | 设置文件指针的位置 | stdio.h | int fseek(FILE* stream, long int offset, int whence) |
ftell | 计算当前文件指针相对于起始位置的偏移量 | stdio.h | long int ftell(FILE* stream) |
rewind | 设置文件指针到文件的起始位置 | stdio.h | void rewind(FILE* stream) |
ferror | 判断文件操作过程中是否发生错误 | stdio.h | int ferror(FILE* stream) |
feof | 判断文件指针是否读取到文件末尾 | stdio.h | int feof(FILE* stream) |
1.2 系统调用和库函数汇总
1.2.1 系统调用
| 系统调用 | 函数功能 | 头文件 | 参数模板 | 返回值 |
|---|
| open() | 打开或创建文件 | <fcntl.h> | int open(const char *pathname, int flags, mode_t mode); | 文件描述符 (成功)/-1(失败) |
| creat() | 创建新文件 | <fcntl.h> | int creat(const char *pathname, mode_t mode); | 文件描述符 (成功)/-1(失败) |
| close() | 关闭文件描述符 | <unistd.h> | int close(int fd); | 0(成功)/-1(失败) |
| read() | 从文件描述符读取数据 | <unistd.h> | ssize_t read(int fd, void *buf, size_t count); | 读取字节数/-1(失败) |
| write() | 向文件描述符写入数据 | <unistd.h> | ssize_t write(int fd, const void *buf, size_t count); | 写入字节数/-1(失败) |
| lseek() | 移动文件读写指针 | <unistd.h> | off_t lseek(int fd, off_t offset, int whence); | 新偏移量/-1(失败) |
| pread() | 从指定偏移处读取 | <unistd.h> | ssize_t pread(int fd, void *buf, size_t count, off_t offset); | 读取字节数/-1(失败) |
| pwrite() | 向指定偏移处写入 | <unistd.h> | ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset); | 写入字节数/-1(失败) |
| fsync() | 将文件数据同步到磁盘 | <unistd.h> | int fsync(int fd); | 0(成功)/-1(失败) |
| fdatasync() | 同步文件数据(不包括元数据) | <unistd.h> | int fdatasync(int fd); | 0(成功)/-1(失败) |
| ftruncate() | 截断/扩展文件大小 | <unistd.h> | int ftruncate(int fd, off_t length); | 0(成功)/-1(失败) |
| dup() | 复制文件描述符 | <unistd.h> | int dup(int oldfd); | 新文件描述符/-1(失败) |
| dup2() | 复制文件描述符到指定值 | <unistd.h> | int dup2(int oldfd, int newfd); | 新文件描述符/-1(失败) |
| fcntl() | 文件描述符控制操作 | <fcntl.h> | int fcntl(int fd, int cmd, ... /* arg */); | 依赖 cmd/-1(失败) |
| ioctl() | 设备 I/O 控制 | <sys/ioctl.h> | int ioctl(int fd, unsigned long request, ...); | 依赖 request/-1(失败) |
| mmap() | 内存映射文件 | <sys/mman.h> | void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); | 映射地址/MAP_FAILED |
| munmap() | 解除内存映射 | <sys/mman.h> | int munmap(void *addr, size_t length); | 0(成功)/-1(失败) |
| mprotect() | 修改内存保护属性 | <sys/mman.h> | int mprotect(void *addr, size_t len, int prot); | 0(成功)/-1(失败) |
| msync() | 同步内存映射到文件 | <sys/mman.h> | int msync(void *addr, size_t length, int flags); | 0(成功)/-1(失败) |
| stat() | 获取文件状态信息 | <sys/stat.h> | int stat(const char *pathname, struct stat *statbuf); | 0(成功)/-1(失败) |
| fstat() | 通过 fd 获取文件状态 | <sys/stat.h> | int fstat(int fd, struct stat *statbuf); | 0(成功)/-1(失败) |
| lstat() | 获取符号链接状态 | <sys/stat.h> | int lstat(const char *pathname, struct stat *statbuf); | 0(成功)/-1(失败) |
| access() | 检查文件访问权限 | <unistd.h> | int access(const char *pathname, int mode); | 0(成功)/-1(失败) |
| chmod() | 修改文件权限 | <sys/stat.h> | int chmod(const char *pathname, mode_t mode); | 0(成功)/-1(失败) |
| fchmod() | 通过 fd 修改文件权限 | <sys/stat.h> | int fchmod(int fd, mode_t mode); | 0(成功)/-1(失败) |
| chown() | 修改文件所有者 | <unistd.h> | int chown(const char *pathname, uid_t owner, gid_t group); | 0(成功)/-1(失败) |
| fchown() | 通过 fd 修改文件所有者 | <unistd.h> | int fchown(int fd, uid_t owner, gid_t group); | 0(成功)/-1(失败) |
| readlink() | 读取符号链接目标 | <unistd.h> | ssize_t readlink(const char *pathname, char *buf, size_t bufsiz); | 读取字节数/-1(失败) |
| rename() | 重命名/移动文件 | <stdio.h> | int rename(const char *oldpath, const char *newpath); | 0(成功)/-1(失败) |
| mkdir() | 创建目录 | <sys/stat.h> | int mkdir(const char *pathname, mode_t mode); | 0(成功)/-1(失败) |
| rmdir() | 删除空目录 | <unistd.h> | int rmdir(const char *pathname); | 0(成功)/-1(失败) |
1.2.2 C 语言标准库文件 IO 函数
| 库函数 | 函数功能 | 头文件 | 参数模板 | 返回值 |
|---|
| fopen() | 打开文件流 | <stdio.h> | FILE *fopen(const char *path, const char *mode); | 文件指针/NULL |
| freopen() | 重新打开文件流 | <stdio.h> | FILE *freopen(const char *path, const char *mode, FILE *stream); | 文件指针/NULL |
| fclose() | 关闭文件流 | <stdio.h> | int fclose(FILE *stream); | 0(成功)/EOF |
| fread() | 从文件流读取数据 | <stdio.h> | size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); | 读取元素数 |
| fwrite() | 向文件流写入数据 | <stdio.h> | size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); | 写入元素数 |
| fgetc() | 从文件流读取字符 | <stdio.h> | int fgetc(FILE *stream); | 字符/EOF |
| getc() | 从文件流读取字符 | <stdio.h> | int getc(FILE *stream); | 字符/EOF |
| getchar() | 从标准输入读取字符 | <stdio.h> | int getchar(void); | 字符/EOF |
| fputc() | 向文件流写入字符 | <stdio.h> | int fputc(int c, FILE *stream); | 字符/EOF |
| putc() | 向文件流写入字符 | <stdio.h> | int putc(int c, FILE *stream); | 字符/EOF |
| putchar() | 向标准输出写入字符 | <stdio.h> | int putchar(int c); | 字符/EOF |
| fgets() | 从文件流读取字符串 | <stdio.h> | char *fgets(char *s, int size, FILE *stream); | 字符串指针/NULL |
| fputs() | 向文件流写入字符串 | <stdio.h> | int fputs(const char *s, FILE *stream); | 非负数/EOF |
| fseek() | 移动文件流指针 | <stdio.h> | int fseek(FILE *stream, long offset, int whence); | 0(成功)/-1 |
| ftell() | 获取文件流当前位置 | <stdio.h> | long ftell(FILE *stream); | 当前位置/-1 |
| rewind() | 重置文件流到开头 | <stdio.h> | void rewind(FILE *stream); | 无 |
| fgetpos() | 获取文件流位置 | <stdio.h> | int fgetpos(FILE *stream, fpos_t *pos); | 0(成功)/非 0 |
| fsetpos() | 设置文件流位置 | <stdio.h> | int fsetpos(FILE *stream, const fpos_t *pos); | 0(成功)/非 0 |
| feof() | 检测文件结束标志 | <stdio.h> | int feof(FILE *stream); | 非 0(结束)/0 |
| ferror() | 检测文件错误标志 | <stdio.h> | int ferror(FILE *stream); | 非 0(错误)/0 |
| clearerr() | 清除错误和 EOF 标志 | <stdio.h> | void clearerr(FILE *stream); | 无 |
| fflush() | 刷新文件流缓冲区 | <stdio.h> | int fflush(FILE *stream); | 0(成功)/EOF |
| setvbuf() | 设置文件流缓冲模式 | <stdio.h> | int setvbuf(FILE *stream, char *buf, int mode, size_t size); | 0(成功)/非 0 |
| setbuf() | 设置文件流缓冲区 | <stdio.h> | void setbuf(FILE *stream, char *buf); | 无 |
| fprintf() | 格式化输出到文件流 | <stdio.h> | int fprintf(FILE *stream, const char *format, ...); | 输出字符数/负数 |
| printf() | 格式化输出到标准输出 | <stdio.h> | int printf(const char *format, ...); | 输出字符数/负数 |
| sprintf() | 格式化输出到字符串 | <stdio.h> | int sprintf(char *str, const char *format, ...); | 输出字符数/负数 |
| fscanf() | 从文件流格式化输入 | <stdio.h> | int fscanf(FILE *stream, const char *format, ...); | 匹配项数/EOF |
| scanf() | 从标准输入格式化输入 | <stdio.h> | int scanf(const char *format, ...); | 匹配项数/EOF |
| sscanf() | 从字符串格式化输入 | <stdio.h> | int sscanf(const char *str, const char *format, ...); | 匹配项数/EOF |
| tmpfile() | 创建临时文件 | <stdio.h> | FILE *tmpfile(void); | 文件指针/NULL |
| tmpnam() | 生成临时文件名 | <stdio.h> | char *tmpnam(char *s); | 文件名指针/NULL |
| remove() | 删除文件 | <stdio.h> | int remove(const char *pathname); | 0(成功)/-1 |
| rename() | 重命名文件 | <stdio.h> | int rename(const char *oldpath, const char *newpath); | 0(成功)/-1 |
| fileno() | 获取文件描述符 | <stdio.h> | int fileno(FILE *stream); | 文件描述符/-1 |
| fdopen() | 从文件描述符创建文件流 | <stdio.h> | FILE *fdopen(int fd, const char *mode); | 文件指针/NULL |
2. 文件 IO 部分代码演示
2.1 文件操作 1:打开文件方式
Makefile
myfile:myfile.c
gcc -o $@ $^
.PHONY:clean
clean: rm -f myfile
myfile.c
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(){
umask(0);
int fd = open("log.txt", O_CREAT | O_WRONLY | O_TRUNC, 0666);
if(fd < 0){
perror("open");
return 1;
}
const char* message = "ccc";
write(fd, message, strlen(message));
close(fd);
return 0;
}
2.2 文件操作 2:重定向
Makefile
myfile:myfile.c
gcc -o $@ $^
.PHONY:clean
clean: rm -f myfile
myfile.c
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(){
FILE *fp = fopen("log.txt","w");
fprintf(stdout,"hello stdout\n");
close(1);
int fda = open("loga.txt",O_CREAT | O_WRONLY | O_TRUNC,0666);
int fdb = open("logb.txt",O_CREAT | O_WRONLY | O_TRUNC,0666);
int fdc = open("logc.txt",O_CREAT | O_WRONLY | O_TRUNC,0666);
fprintf(stdout,"fda : %d\n",fda);
fprintf(stdout,"fdb : %d\n",fdb);
fprintf(stdout,"fdc : %d\n",fdc);
close(fda);
close(fdb);
close(fdc);
return 0;
}
loga.txt
fda :1 fdb :4 fdc :5
2.3 文件操作 3:理解缓冲区
Print.c
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
int main(){
printf("hell world");
sleep(40);
return 0;
}
2.4 文件操作 4:实现 stdio
Makefile
testlibc:main.c my_stdio.c
gcc -o $@ $^
.PHONY:clean
clean: rm -f testlibc
main.c
#include"my_stdio.h"
#include<string.h>
#include<unistd.h>
int main(){
My_FILE *fp = Myfopen("log.txt","a");
if(!fp)
return 1;
int cnt = 10;
const char* msg = "hello world ";
while(cnt--){
Myfwrite(msg,1,strlen(msg),fp);
Myfflush(fp);
sleep(2);
}
Myfclose(fp);
return 0;
}
my_stdio.h
#pragma once
typedef struct{
int fd;
int flags;
int mode;
char outbuffer[1024];
int cap;
int size;
} My_FILE;
#define NONE_CACHE 1
#define LINE_CACHE 2
#define FULL_CACHE 4
My_FILE *Myfopen(const char* pathname,const char* mode);
int Myfwrite(const char* message,int size,int num,My_FILE *fp);
void Myfflush(My_FILE *fp);
void Myfclose(My_FILE *fp);
my_stdio.c
#include"my_stdio.h"
#include<string.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<fcntl.h>
#include<stdlib.h>
#include<unistd.h>
static mode_t global_mode = 0666;
My_FILE *Myfopen(const char* pathname,const char* mode){
if(pathname == NULL || mode == NULL)
return NULL;
umask(0);
int fd = 0;
int flags = 0;
if(strcmp(mode,"w")==0){
flags = O_CREAT | O_WRONLY | O_TRUNC;
fd = open(pathname,flags,global_mode);
}
if(strcmp(mode,"r")==0){
flags = O_RDONLY;
fd = open(pathname,flags);
}
if(strcmp(mode,"a")==0){
flags = O_CREAT | O_WRONLY | O_APPEND;
fd = open(pathname,flags,global_mode);
}
if(fd < 0)
return NULL;
My_FILE* fp = (My_FILE*)malloc(sizeof(My_FILE));
if(!fp)
return NULL;
fp->fd = fd;
fp->flags = flags;
fp->mode = LINE_CACHE;
fp->cap = 1024;
fp->size = 0;
memset(fp->outbuffer,0,sizeof(fp->outbuffer));
return fp;
}
int Myfwrite(const char* message,int size,int num,My_FILE *fp){
if(message == NULL || fp == NULL)
return -1;
int total = size * num;
if(total + fp->size > fp->cap -1)
return -1;
memcpy(fp->outbuffer + fp->size,message,total);
fp->size += total;
fp->outbuffer[fp->size]=0;
if(fp->outbuffer[fp->size -1]=='\n' && (fp->mode & LINE_CACHE))
Myfflush(fp);
return num;
}
void Myfflush(My_FILE *fp){
if(!fp)
return;
if(fp->size >0)
{
write(fp->fd,fp->outbuffer,fp->size);
fp->size = 0;
fsync(fp->fd);
}
}
void Myfclose(My_FILE *fp){
if(!fp)
return;
Myfflush(fp);
close(fp->fd);
}