【Linux:资料】基础IO:资料操作的系统调用和库函数各个接口汇总及代码演示


头像


个人主页艾莉丝努力练剑

专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录
Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享

⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平

艾莉丝的简介:

在这里插入图片描述



在这里插入图片描述


1 ~> 文件操作的系统调用和库函数各个接口

1.1 C语言文件操作常用接口

函数名功能头文件参数说明
fopen打开文件stdio.hFILE* fopen(const char* filename, const char* mode)
fclose关闭文件stdio.hint fclose(FILE* stream)
fputc写入一个字符stdio.hint fputc(int char, FILE* stream)
fgetc读取一个字符stdio.hint fgetc(FILE* stream)
fputs写入一个字符串stdio.hint fputs(const char* str, FILE* stream)
fgets读取一个字符串stdio.hchar* fgets(char* str, int n, FILE* stream)
fprintf格式化写入数据stdio.hint fprintf(FILE* stream, const char* format, ...)
fscanf格式化读取数据stdio.hint fscanf(FILE* stream, const char* format, ...)
fwrite向二进制文件写入数据stdio.hsize_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream)
fread从二进制文件读取数据stdio.hsize_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream)
fseek设置文件指针的位置stdio.hint fseek(FILE* stream, long int offset, int whence)
ftell计算当前文件指针相对于起始位置的偏移量stdio.hlong int ftell(FILE* stream)
rewind设置文件指针到文件的起始位置stdio.hvoid rewind(FILE* stream)
ferror判断文件操作过程中是否发生错误stdio.hint ferror(FILE* stream)
feof判断文件指针是否读取到文件末尾stdio.hint 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); // OS本身自带的系统调用,相当于w
            if(fd < 0)  // 打开文件失败
            {
            perror("open");
            return 1;
            }
            //const char *message = "1234567890abcdefg\n";
            const char *message = "ccc";
            write(fd,message,strlen(message));
            close(fd);
            return 0;
            }
            //#define ONE (1<<0)   // 1
            //#define TWO (1<<1)   // 2
            //#define THREE (1<<2)   // 4
            //#define FOUR (1<<3)   // 8
            //#define FIVE (1<<4)   // 16
            //
            //void Print(int flags)
            //{
            //    if(flags & ONE)
            //        printf("ONE\n");
            //    if(flags & TWO)
            //        printf("TWO\n");
            //    if(flags & THREE)
            //        printf("THREE\n");
            //    if(flags & FOUR)
            //        printf("FOUR\n");
            //    if(flags & FIVE)
            //        printf("FIVE\n");
            //}
            //
            //int main()
            //{
            //    Print(ONE);
            //    printf("\n");
            //    Print(TWO);
            //    printf("\n");
            //    Print(ONE | TWO);
            //    printf("\n");
            //    Print(ONE | TWO | THREE);
            //    printf("\n");
            //    Print(ONE | TWO | THREE | FOUR);
            //    printf("\n");
            //    Print(TWO | THREE | FOUR | FIVE);
            //}
            //int main()
            //{
            //    //chdir("/home/Alice/118/linux-git"); // 可以修改文件新建的路径
            //    //char pwd[64];
            //    //getcwd(pwd, sizeof(pwd));
            //    //printf("cwd: %s\n", pwd);
            //
            //
            //    FILE *fp = fopen("log.txt", "w");
            //    if(NULL == fp)
            //    {
            //        perror("fopen");
            //        return 0;
            //    }
            //
            //    char inbuffer[1024];
            //    while(1)
            //    {
            //        long pos = ftell(fp);
            //        printf("pos: %ld\n", pos);
            //        int ch = fgetc(fp);
            //        if(ch == EOF)
            //        {
            //            break;
            //        }
            //        printf("%c\n", ch);
            //        //if(!fgets(inbuffer, sizeof(inbuffer), fp))
            //        //{
            //        //    break;
            //        //}
            //        printf("file : %s", inbuffer);
            //    }
            //
            //    //const char *message = "abcd\n";
            //    //fputs(message, fp);
            //    ////int cnt = 0;
            //    //while(cnt < 10)
            //    //{
            //    //    //fwrite(message, 1, strlen(message) + 1, fp);  // 文件的字符串这里不用+1,+1即算上了\0(C语言)
            //    //    fputs(message, fp);
            //    //    //fprintf(fp, "hello Alice: %d\n", cnt);
            //    //    cnt++;
            //    //}
            //
            //    fclose(fp);
            //    return 0;
            //}

log.txt

在这里插入图片描述

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()
            {
            //int fda = open("loga.txt",O_RDONLY);
            //dup2(fda,0);
            //int a = 0;
            //float f = 0.0f;
            //char c = 0;
            //scanf("%d %f %c",&a,&f,&c);
            //printf("%d %f %c\n",a,f,c);
            //// 联系重定向
            //// 格式化输出:上层的用户层,stdout -> 1
            //printf("hello printf\n");   // stdout -> 1
            //fprintf(stdout,"hello fprintf\n");  // stdout -> 1
            //// 三个标准流,默认打开的
            //printf("stdin: %d\n",stdin->_fileno);
            //printf("stdout: %d\n",stdout->_fileno);
            //printf("stdout: %d\n",stderr->_fileno);
            FILE *fp = fopen("log.txt","w");
            printf("log.txt: %d\n",fp->_fileno);    // 3(fd数组下标)
            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);
            //printf(stdout,"fda : %d\n",fda);
            //printf(stdout,"fdb : %d\n",fdb);
            //printf(stdout,"fdc : %d\n",fdc);
            close(fda);
            close(fdb);
            close(fdc);
            return 0;
            }
            //// cat file.txt
            //int main(int argc,char *argv[])
            //{
            //    if(argc != 2)   // 没有第二个参数
            //    {
            //        printf("Ussage: %s filename\n",argv[0]);    // ./myfile filename
            //        return 1;
            //    }
            //    int fd = open(argv[1],O_RDONLY);    // 只读
            //    if(fd < 0)  // 读错了
            //    {
            //        perror("open");
            //        return 2;
            //    }
            //
            //    char inbuffer[128];
            //    while(1)
            //    {
            //        ssize_t n = read(fd,inbuffer,sizeof(inbuffer)-1);   // 预备留给\n
            //        if(n > 0)
            //        {
            //            inbuffer[n] = 0;
            //            printf("%s",inbuffer);
            //        }
            //        else if(n == 0)
            //        {
            //            printf("end of file!\n");   // 到达文件结尾
            //            break;
            //        }
            //        else
            //        {
            //            perror("read");
            //            break;
            //        }
            //    }
            //
            //    close(fd);
            //    return 0;
            //}
            //// 追加
            //int main()
            //{
            //    umask(0);
            //    int fd = open("log.txt",O_CREAT | O_WRONLY | O_APPEND,0666);
            //    if(fd < 0)
            //    {
            //        perror("open");
            //        return 1;
            //    }
            //
            //    const char *msg = "hello Alice\n";
            //    int cnt = 10;
            //    while(cnt--)
            //    {
            //        write(fd,msg,strlen(msg));
            //    }
            //
            //    close(fd);
            //    return 0;
            //}
            //// 写入
            //int main()
            //{
            //    umask(0);   // 就近原则
            //    int fd = open("log.txt",O_CREAT | O_WRONLY | O_TRUNC,0666); // OS本身自带的系统调用,相当于w
            //    if(fd < 0)  // 打开文件失败
            //    {
            //        perror("open");
            //        return 1;
            //    }
            //    //const char *message = "1234567890abcdefg\n";
            //    const char *message = "ccc";
            //    write(fd,message,strlen(message));
            //
            //    close(fd);
            //    return 0;
            //}
            //#define ONE (1<<0)   // 1
            //#define TWO (1<<1)   // 2
            //#define THREE (1<<2)   // 4
            //#define FOUR (1<<3)   // 8
            //#define FIVE (1<<4)   // 16
            //
            //void Print(int flags)
            //{
            //    if(flags & ONE)
            //        printf("ONE\n");
            //    if(flags & TWO)
            //        printf("TWO\n");
            //    if(flags & THREE)
            //        printf("THREE\n");
            //    if(flags & FOUR)
            //        printf("FOUR\n");
            //    if(flags & FIVE)
            //        printf("FIVE\n");
            //}
            //
            //int main()
            //{
            //    Print(ONE);
            //    printf("\n");
            //    Print(TWO);
            //    printf("\n");
            //    Print(ONE | TWO);
            //    printf("\n");
            //    Print(ONE | TWO | THREE);
            //    printf("\n");
            //    Print(ONE | TWO | THREE | FOUR);
            //    printf("\n");
            //    Print(TWO | THREE | FOUR | FIVE);
            //}
            //int main()
            //{
            //    //chdir("/home/Alice/118/linux-git"); // 可以修改文件新建的路径
            //    //char pwd[64];
            //    //getcwd(pwd, sizeof(pwd));
            //    //printf("cwd: %s\n", pwd);
            //
            //
            //    FILE *fp = fopen("log.txt", "w");
            //    if(NULL == fp)
            //    {
            //        perror("fopen");
            //        return 0;
            //    }
            //
            //    char inbuffer[1024];
            //    while(1)
            //    {
            //        long pos = ftell(fp);
            //        printf("pos: %ld\n", pos);
            //        int ch = fgetc(fp);
            //        if(ch == EOF)
            //        {
            //            break;
            //        }
            //        printf("%c\n", ch);
            //        //if(!fgets(inbuffer, sizeof(inbuffer), fp))
            //        //{
            //        //    break;
            //        //}
            //        printf("file : %s", inbuffer);
            //    }
            //
            //    //const char *message = "abcd\n";
            //    //fputs(message, fp);
            //    ////int cnt = 0;
            //    //while(cnt < 10)
            //    //{
            //    //    //fwrite(message, 1, strlen(message) + 1, fp);  // 文件的字符串这里不用+1,+1即算上了\0(C语言)
            //    //    fputs(message, fp);
            //    //    //fprintf(fp, "hello Alice: %d\n", cnt);
            //    //    cnt++;
            //    //}
            //
            //    fclose(fp);
            //    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 <sys/fcntl.h>
            int main()
            {
            printf("hell world");   // 语言缓冲区 -> stdout->outbuffer
            sleep(40);  // 测试杀死这个进程
            //// C库函数
            //printf("hello printf\n");
            //fprintf(stdout,"hello fprintf\n");
            //const char *msg1 = "hello fputs\n";
            //fputs(msg1,stdout);
            // // 系统调用
            // const char *msg2 = "hello write\n";
            // write(1,msg2,strlen(msg2));
            //fork(); // 最后
            return 0;
            }
            //int main()
            //{
            //    fprintf(stdout,"hello stdout\n");
            //    fprintf(stderr,"hello error\n");
            //
            //    const char *msg1 = "hello 1\n";
            //    const char *msg2 = "hello 2\n";
            //    write(1,msg1,strlen(msg1));
            //    write(2,msg2,strlen(msg2));
            //
            //    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"); // 相当于把这个log.txt当显示器了
    if(!fp) // 打开文件失败或者底层malloc失败
    return 1;
    int cnt = 10;
    //const char *msg = "hello world \n";
    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;   // 缓冲区当前的数据量
//char inbuffer[1024];
}My_FILE;
// 定义宏,是什么类型的缓冲
#define NONE_CACHE 1
#define LINE_CACHE 2
#define FULL_CACHE 4    // 1 2 4只有一个比特位为1(0001/0010/0100),检测起来比较容易
My_FILE *Myfopen(const char *pathname,const char *mode); // r w a方式 --> 打开文件
//int Myfputs(const char *message,My_FILE *fp);   // Myfputs可能太偏字符串,一会儿还要刷新,刷新还要写入,就用Myfwrite了
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> // malloc
          #include <unistd.h>
            static mode_t global_mode = 0666;
            // My_FILE *fp = Myfopen("log.txt","a");
            // 我写的和库的基本的细节肯定不一样,但是核心思想在大的轮廓上是一样的
            My_FILE *Myfopen(const char *pathname,const char *mode) // r w a方式(在内部选择不同的模式)
            {
            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);
            (void)fd;
            }
            if(strcmp(mode,"r") == 0)
            {
            flags = O_RDONLY;
            fd = open(pathname,flags);   // 传两参数的open
            (void)fd;
            }
            if(strcmp(mode,"a") == 0)
            {
            flags = O_CREAT | O_WRONLY | O_APPEND;
            fd = open(pathname,flags,global_mode);
            (void)fd;
            }
            else
            {}
            if(fd < 0)  // 文件打开失败
            return NULL;
            // 创建My_FILE对象
            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; // 容量,因为缓冲区大小定义的就是1024,这一块也可以定义成宏
            fp->size = 0;   // 当前缓冲区里没有数据,size是0
            //fp->outbuffer[0] = '\0';    // 我们把它当做字符串做的,我们这里默认这样就清空了,如果受不了这样写,可以像下面这样写
            memset(fp->outbuffer,0,sizeof(fp->outbuffer));
            return fp;  // 至此上层拿到了这个被打开的文件
            }
            int Myfwrite(const char *message,int size,int num,My_FILE *fp)  // 一定程度上减少系统调用次数,因为不一定所有的刷新条件都满足 --> 这个Myfwrite就是之前写的fwrite,是在进行把数据刷新到缓冲区里
            {
            if(message == NULL || fp == NULL)
            return -1;
            // 向C语言文件里面写,本质是向(不是操作系统,而是)缓冲区写
            // fwrite这样的接口在我们看来90%的情况不是IO函数,而是一种拷贝函数,就好比用系统调用,比如write,
            // 用write的时候把用户数据拷贝到内核当中(也只是拷贝),包括此时把内核中的数据(内存中)搬到了磁盘上,
            // 不也相当于一种拷贝嘛!只不过把存储到外设这个拷贝起名叫IO
            // 在计算机里面充满了大量的IO,包括未来学习网络部分的时候,把数据写到网络里面,从网络里读,
            // 其实本质上依然是从设备当中拷贝数据到内存,内存当中拷贝数据到外设,所以一切皆拷贝,
            // 当它都是拷贝时每个阶段不同的拷贝起个名字就叫IO
            // 所以向C语言文件里面写,本质是向缓冲区写,至于怎么办就不用我们管了
            int total = size * num;
            //if(total + fp->size > fp->cap)  // 没有考虑\0的问题
            if(total + fp->size > fp->cap - 1)  // 保证不会越界 --> 总容量给\0留个位置
            return -1;
            // 写入 --> 就相当于在进行数据拷贝 --> 核心
            memcpy(fp->outbuffer + fp->size,message,total); // 没有考虑\0的问题,保险起见就加个1,这里已经考虑到了
            fp->size +=  total;
            fp->outbuffer[fp->size] = 0;
            if(fp->outbuffer[fp->size - 1] == '\n' && (fp->mode & LINE_CACHE))
            Myfflush(fp);   // 如果字符串结尾是\n,并且模式是LINE(行缓冲),就直接强制刷新
            //// fwrite判断是否刷新,这不就是刷新吗(所谓的刷新就是把数据拷贝给内存)!!!
            //if(fp->size > 0 && fp->outbuffer[fp->size - 1] == '\n' && (fp->mode & LINE_CACHE))  // 刷新条件满足时才会调用系统调用
            //{
            //    // 系统调用
            //    write(fp->fd,fp->outbuffer,fp->size);
            //    fp->size = 0;   // 清空
            //    //fp->outbuffer = 0;  // 不清空也行
            //    // printf格式化也是输出到缓冲区
            //}
            return num; // num: 一共写了多少字节
            }
            void Myfflush(My_FILE *fp)
            {
            if(!fp)
            return;
            // fwrite判断是否刷新,这不就是刷新吗(所谓的刷新就是把数据拷贝给内存)!!!
            if(fp->size > 0) // 强制刷新,只要有数据就刷新
            {
            // 系统调用
            // 所谓的刷新就是把数据从用户缓冲区拷贝到内核
            // 像从用户缓冲区拷贝到内核这种模式叫做WB模式
            // WB: Write Back(写回)
            write(fp->fd,fp->outbuffer,fp->size);
            fp->size = 0;   // 清空
            //fp->outbuffer = 0;  // 不清空也行
            // printf格式化也是输出到缓冲区
            // WT模式,Write Though
            // 不仅仅要写入到内核缓冲区,还必须写到对应的硬件上
            fsync(fp->fd);  // 强度做大一点
            }
            }
            void Myfclose(My_FILE *fp) // 关闭文件
            {
            if(!fp)
            return;
            Myfflush(fp); // 只要有数据,无脑刷新
            close(fp->fd);  // 先刷新再关闭!先刷新,再关闭文件描述符!
            }

结尾

uu们,本文的内容到这里就全部结束了,艾莉丝在这里再次感谢您的阅读!

结语:希望对学习Linux相关内容的uu有所帮助,不要忘记给博主“一键四连”哦!

往期回顾

【Linux进程控制(三)】实现自主Shell命令行解释器

博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!
૮₍ ˶ ˊ ᴥ ˋ˶₎ა

在这里插入图片描述

posted @ 2026-03-06 22:04  gccbuaa  阅读(2)  评论(0)    收藏  举报