Linux系统程序设计--2. 文件I/O

文件I/O

标准C的I/O

FILE结构体

  • 下面列出了5个成员
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

  • 可以观察到,有些函数没有FILE类型的结构体指针例如printf主要是一些标准输出,因为其内部用到了stdin,stdout,stderr
  • 查找文件所在的位置:find \ -name stat.h
  • 查找头文件所在的位置。可以使用gcc
    #include <sys/stat.h>
    
    int main() {
        return 0;
    }
    
    gcc -M test.c
    
    在这里插入图片描述
    在这里插入图片描述

代码文件

  • src
    • .c的目标文件
  • bin
    • 编译链接生成的可执行文件
  • obj
    • 存放生成的.o`的目标文件
  • include
    • 存储头文件

缓冲

缓冲类型

在这里插入图片描述

  1. 全缓冲(Fully Buffered)
    • 数据被写入缓冲区,当缓冲区满或显式调用fflush时才写入目标。
    • 通常用于文件I/O,尤其是磁盘文件。
  2. 行缓冲(Line Buffered)
    • 数据在遇到换行符时被写入目标。
    • 通常用于终端输入输出(如标准输入stdin和标准输出stdout)。
#include<stdio.h>
#include<unistd.h>


int main(void)
{

      printf("Hello Iotak\n");

      while(1)
      {
        sleep(1);
      }

      return 0;
}

sleep函数不是标准C库的一部分,而是POSIX标准的一部分
在大多数Unix-like系统(如Linux和macOS)上,sleep函数定义在unistd.h头文件中。
在Windows上,你可以使用Sleep函数(注意首字母大写),它定义在windows.h头文件中。

  1. 无缓冲(Unbuffered)
    • 每次I/O操作直接与目标交互,没有中间缓冲区。
    • 通常用于标准错误stderr
常见的I/O函数及其缓冲特性
  1. 标准输入/输出函数
    • printfputsputchar:默认行缓冲(对于终端),全缓冲(对于文件)。
    • scanfgetchargets:默认行缓冲(对于终端),全缓冲(对于文件)。
  2. 文件操作函数
    • fprintffputsfputc:默认全缓冲。
    • fscanffgetcfgets:默认全缓冲。
    • freadfwrite:默认全缓冲。
    • fclosefflush:显式刷新缓冲区。
    • setbufsetvbuf:允许手动设置缓冲方式和缓冲区大小。
特殊情况
  • 标准错误stderr
    • stderr默认是无缓冲的,这样可以确保错误信息立即显示,不会因为缓冲而延迟。
    • 使用setvbuf可以改变stderr的缓冲方式。
示例
默认缓冲行为
#include <stdio.h>

int main() {
    printf("This is a test.\n"); // 行缓冲,遇到换行符会刷新
    fprintf(stderr, "This is an error message.\n"); // 无缓冲,立即显示
    return 0;
}
手动设置缓冲方式
#include <stdio.h>

int main() {
    char buffer[1024];
    setvbuf(stdout, buffer, _IOFBF, sizeof(buffer)); // 设置stdout为全缓冲
    printf("This is a test."); // 不会立即显示,因为没有换行符
    fflush(stdout); // 显式刷新缓冲区
    return 0;
}
总结
  • 标准输入/输出:通常行缓冲(对于终端)或全缓冲(对于文件)。
  • 标准错误:默认无缓冲。
  • 文件操作:默认全缓冲。
  • 手动控制:可以使用setbufsetvbuf函数手动设置缓冲方式和缓冲区大小。

标准输入/输出函数

1. int printf(const char *format, ...);
  • 头文件<stdio.h>

  • 功能:将格式化的数据写入到标准输出(通常是屏幕)。

  • 参数

    • const char *format:格式控制字符串。
    • ...:可变参数列表,根据格式字符串中的占位符提供相应的值。
  • 返回值:成功时返回打印的字符数;失败时返回一个负值。

  • 例子

    #include <stdio.h>
    int main() {
        printf("Hello, World!\n");
        return 0;
    }
    
2. int scanf(const char *format, ...);
  • 头文件<stdio.h>

  • 功能:从标准输入读取格式化输入。

  • 参数

    • const char *format:格式控制字符串。
    • ...:可变参数列表,通常是指向变量的指针,用于存储读取的值。
  • 返回值:成功时返回成功读取并赋值的数据项数量;到达文件结束或遇到错误时返回EOF。

  • 例子

    #include <stdio.h>
    int main() {
        int num;
        printf("Enter an integer: ");
        scanf("%d", &num);
        printf("You entered: %d\n", num);
        return 0;
    }
    
3. int puts(const char *s);
  • 头文件<stdio.h>

  • 功能:将字符串写入标准输出,自动添加换行符。

  • 参数

    • const char *s:要写入的字符串。
  • 返回值:成功时返回非负值;如果发生错误,则返回EOF。

  • 例子

    #include <stdio.h>
    int main() {
        puts("Hello, World!");
        return 0;
    }
    
4. char *gets(char *s);
  • 头文件<stdio.h>

  • 功能:从标准输入读取一行字符串(不推荐使用,存在缓冲区溢出风险)。

  • 参数

    • char *s:指向存储读取字符串的缓冲区的指针。
  • 返回值:成功时返回指向字符串的指针;如果到达文件末尾或发生错误,则返回NULL。

  • 例子

    #include <stdio.h>
    int main() {
        char buffer[100];
        printf("Enter a line: ");
        gets(buffer); // 不推荐使用
        printf("You entered: %s\n", buffer);
        return 0;
    }
    
5. int getchar(void);
  • 头文件<stdio.h>

  • 功能:从标准输入读取下一个可用字符。

  • 参数:无。

  • 返回值:成功时返回读取的字符;如果到达文件结束或发生错误,则返回EOF。

  • 例子

    #include <stdio.h>
    int main() {
        int ch;
        printf("Press any key and then press enter: ");
        ch = getchar();
        printf("You pressed: %c\n", ch);
        return 0;
    }
    
6. int putchar(int c);
  • 头文件<stdio.h>

  • 功能:将指定的字符写入到标准输出。

  • 参数

    • int c:要写入的字符。
  • 返回值:成功时返回写入的字符;如果发生错误,则返回EOF。

  • 例子

    #include <stdio.h>
    int main() {
        putchar('A');
        return 0;
    }
    

文件操作函数

7. FILE *fopen(const char *path, const char *mode);
  • 头文件<stdio.h>

  • 功能:打开或创建一个文件,并返回一个指向该文件的FILE类型指针。

  • 参数

    • const char *path:文件路径。
    • const char *mode:打开模式(如"r"表示只读,"w"表示写入等)。
  • 返回值:成功时返回指向文件的指针;如果打开失败,则返回NULL。

  • 例子

    #include <stdio.h>
    int main() {
        FILE *file = fopen("example.txt", "r");
        if (file == NULL) {
            printf("Failed to open file.\n");
            return 1;
        }
        fclose(file);
        return 0;
    }
    
8. int fclose(FILE *stream);
  • 头文件<stdio.h>

  • 功能:关闭一个已打开的文件流。

  • 参数

    • FILE *stream:指向文件流的指针。
  • 返回值:成功时返回0;如果发生错误,则返回EOF。

  • 例子

    #include <stdio.h>
    int main() {
        FILE *file = fopen("example.txt", "r");
        if (file == NULL) {
            printf("Failed to open file.\n");
            return 1;
        }
        fclose(file);
        return 0;
    }
    
9. int fprintf(FILE *stream, const char *format, ...);
  • 头文件<stdio.h>

  • 功能:将格式化的数据写入指定的流。

  • 参数

    • FILE *stream:指向文件流的指针。
    • const char *format:格式控制字符串。
    • ...:可变参数列表,根据格式字符串中的占位符提供相应的值。
  • 返回值:成功时返回打印的字符数;失败时返回一个负值。

  • 例子

    #include <stdio.h>
    int main() {
        FILE *file = fopen("test.txt", "w");
        if (file == NULL) {
            printf("Error opening file.\n");
            return 1;
        }
        fprintf(file, "This is a test.\n");
        fclose(file);
        return 0;
    }
    
10. int fscanf(FILE *stream, const char *format, ...);
  • 头文件<stdio.h>

  • 功能:从指定的流读取格式化输入。

  • 参数

    • FILE *stream:指向文件流的指针。
    • const char *format:格式控制字符串。
    • ...:可变参数列表,通常是指向变量的指针,用于存储读取的值。
  • 返回值:成功时返回成功读取并赋值的数据项数量;到达文件结束或遇到错误时返回EOF。

  • 例子

    #include <stdio.h>
    int main() {
        FILE *file = fopen("test.txt", "r");
        if (file == NULL) {
            printf("Error opening file.\n");
            return 1;
        }
        char str[100];
        fscanf(file, "%s", str);
        printf("Read from file: %s\n", str);
        fclose(file);
        return 0;
    }
    
11. char *fgets(char *str, int n, FILE *stream);
  • 头文件<stdio.h>

  • 功能:从流中读取一行(直到换行符或达到指定长度减一)。

  • 参数

    • char *str:指向存储读取字符串的缓冲区的指针。
    • int n:要读取的最大字符数(包括终止的空字符)。
    • FILE *stream:指向文件流的指针。
  • 返回值:成功时返回指向字符串的指针;如果到达文件末尾或发生错误,则返回NULL。

  • 例子

    #include <stdio.h>
    int main() {
        char buffer[100];
        FILE *file = fopen("example.txt", "r");
        if (file == NULL) {
            printf("Failed to open file.\n");
            return 1;
        }
        fgets(buffer, sizeof(buffer), file);
        printf("Read from file: %s", buffer);
        fclose(file);
        return 0;
    }
    
12. int fputs(const char *str, FILE *stream);
  • 头文件<stdio.h>

  • 功能:向指定的流写入一个字符串(不包括终止的空字符)。

  • 参数

    • const char *str:要写入的字符串。
    • FILE *stream:指向文件流的指针。
  • 返回值:成功时返回非负值;如果发生错误则返回EOF。

  • 例子

    #include <stdio.h>
    int main() {
        FILE *file = fopen("test.txt", "w");
        if (file == NULL) {
            printf("Error opening file.\n");
            return 1;
        }
        const char *message = "This is a message.";
        fputs(message, file);
        fclose(file);
        return 0;
    }
    
13. int fgetc(FILE *stream);
  • 头文件<stdio.h>

  • 功能:从指定的流中读取下一个字符。

  • 参数

    • FILE *stream:指向文件流的指针。
  • 返回值:成功时返回读取的字符;如果到达文件结束或发生错误,则返回EOF。

  • 例子

    #include <stdio.h>
    int main() {
        FILE *file = fopen("example.txt", "r");
        if (file == NULL) {
            printf("Failed to open file.\n");
            return 1;
        }
        int ch;
        while ((ch = fgetc(file)) != EOF) {
            putchar(ch);
        }
        fclose(file);
        return 0;
    }
    
14. int fputc(int c, FILE *stream);
  • 头文件<stdio.h>

  • 功能:将指定的字符写入到指定的流。

  • 参数

    • int c:要写入的字符。
    • FILE *stream:指向文件流的指针。
  • 返回值:成功时返回写入的字符;如果发生错误,则返回EOF。

  • 例子

    #include <stdio.h>
    int main() {
        FILE *file = fopen("example.txt", "w");
        if (file == NULL) {
            printf("Failed to open file.\n");
            return 1;
        }
        fputc('A', file);
        fclose(file);
        return 0;
    }
    
15. int fseek(FILE *stream, long offset, int whence);
  • 头文件<stdio.h>

  • 功能:设置文件流的位置指针。

  • 参数

    • FILE *stream:指向文件流的指针。
    • long offset:相对于whence的偏移量。
    • int whence:位置基准点(如SEEK_SET表示文件开头,SEEK_CUR表示当前位置,SEEK_END表示文件结尾)。
  • 返回值:成功时返回0;如果发生错误,则返回非零值。

  • 例子

    #include <stdio.h>
    int main() {
        FILE *file = fopen("example.txt", "r+");
        if (file == NULL) {
            printf("Failed to open file.\n");
            return 1;
        }
        fseek(file, 5, SEEK_SET); // 移动到文件开头后的第5个字节
        fclose(file);
        return 0;
    }
    
16. long ftell(FILE *stream);
  • 头文件<stdio.h>

  • 功能:获取文件流的当前读写位置。

  • 参数

    • FILE *stream:指向文件流的指针。
  • 返回值:成功时返回当前的位置(以字节为单位);如果发生错误,则返回-1L。

  • 例子

    #include <stdio.h>
    int main() {
        FILE *file = fopen("example.txt", "r");
        if (file == NULL) {
            printf("Failed to open file.\n");
            return 1;
        }
        fseek(file, 5, SEEK_SET); // 移动到文件开头后的第5个字节
        long pos = ftell(file);
        printf("Current position: %ld\n", pos);
        fclose(file);
        return 0;
    }
    
17. void rewind(FILE *stream);
  • 头文件<stdio.h>

  • 功能:将文件流的位置指针重置到文件开头。

  • 参数

    • FILE *stream:指向文件流的指针。
  • 返回值:无。

  • 例子

    #include <stdio.h>
    int main() {
        FILE *file = fopen("example.txt", "r");
        if (file == NULL) {
            printf("Failed to open file.\n");
            return 1;
        }
        fseek(file, 5, SEEK_SET); // 移动到文件开头后的第5个字节
        rewind(file); // 重置到文件开头
        fclose(file);
        return 0;
    }
    
18. int feof(FILE *stream);
  • 头文件<stdio.h>

  • 功能:检测文件流是否到达文件结束。

  • 参数

    • FILE *stream:指向文件流的指针。
  • 返回值:如果文件流到达文件结束,则返回非零值;否则返回0。

  • 例子

    #include <stdio.h>
    int main() {
        FILE *file = fopen("example.txt", "r");
        if (file == NULL) {
            printf("Failed to open file.\n");
            return 1;
        }
        int ch;
        while ((ch = fgetc(file)) != EOF) {
            putchar(ch);
        }
        if (feof(file)) {
            printf("End of file reached.\n");
        }
        fclose(file);
        return 0;
    }
    
19. int ferror(FILE *stream);
  • 头文件<stdio.h>

  • 功能:检测文件流是否发生错误。

  • 参数

    • FILE *stream:指向文件流的指针。
  • 返回值:如果文件流发生错误,则返回非零值;否则返回0。

  • 例子

    #include <stdio.h>
    int main() {
        FILE *file = fopen("nonexistent.txt", "r");
        if (file == NULL) {
            printf("Failed to open file.\n");
            return 1;
        }
        int ch;
        while ((ch = fgetc(file)) != EOF) {
            if (ferror(file)) {
                printf("Error reading file.\n");
                break;
            }
            putchar(ch);
        }
        fclose(file);
        return 0;
    }
    
20. void clearerr(FILE *stream);
  • 头文件<stdio.h>

  • 功能:清除文件流的错误标志和文件结束标志。

  • 参数

    • FILE *stream:指向文件流的指针。
  • 返回值:无。

  • 例子

    #include <stdio.h>
    int main() {
        FILE *file = fopen("example.txt", "r");
        if (file == NULL) {
            printf("Failed to open file.\n");
            return 1;
        }
        int ch;
        while ((ch = fgetc(file)) != EOF) {
            if (ferror(file)) {
                clearerr(file); // 清除错误标志
                printf("Error cleared.\n");
                break;
            }
            putchar(ch);
        }
        fclose(file);
        return 0;
    }
    
21. int remove(const char *filename);
  • 头文件<stdio.h>

  • 功能:删除指定的文件。

  • 参数

    • const char *filename:要删除的文件名。
  • 返回值:成功时返回0;如果发生错误,则返回非零值。

  • 例子

    #include <stdio.h>
    int main() {
        if (remove("example.txt") == 0) {
            printf("File deleted successfully.\n");
        } else {
            printf("Error deleting file.\n");
        }
        return 0;
    }
    
22. int rename(const char *oldname, const char *newname);
  • 头文件<stdio.h>

  • 功能:重命名文件。

  • 参数

    • const char *oldname:旧文件名。
    • const char *newname:新文件名。
  • 返回值:成功时返回0;如果发生错误,则返回非零值。

  • 例子

    #include <stdio.h>
    int main() {
        if (rename("oldname.txt", "newname.txt") == 0) {
            printf("File renamed successfully.\n");
        } else {
            printf("Error renaming file.\n");
        }
        return 0;
    }
    
23. void setbuf(FILE *stream, char *buf);
  • 头文件<stdio.h>

  • 功能:设置或取消文件流的缓冲区。

  • 参数

    • FILE *stream:指向文件流的指针。
    • char *buf:缓冲区指针。如果为NULL,则取消缓冲。
  • 返回值:无。

  • 例子

    #include <stdio.h>
    int main() {
        FILE *file = fopen("example.txt", "w");
        if (file == NULL) {
            printf("Failed to open file.\n");
            return 1;
        }
        setbuf(file, NULL); // 取消缓冲
        fprintf(file, "This is a test.\n");
        fclose(file);
        return 0;
    }
    
24. int setvbuf(FILE *stream, char *buf, int mode, size_t size);
  • 头文件<stdio.h>

  • 功能:设置文件流的缓冲方式和大小。

  • 参数

    • FILE *stream:指向文件流的指针。
    • char *buf:缓冲区指针。如果为NULL,则使用系统分配的缓冲区。
    • int mode:缓冲方式(如_IOFBF表示完全缓冲,_IOLBF表示行缓冲,_IONBF表示不缓冲)。
    • size_t size:缓冲区大小。
  • 返回值:成功时返回0;如果发生错误,则返回非零值。

  • 例子

    #include <stdio.h>
    int main() {
        FILE *file = fopen("example.txt", "w");
        if (file == NULL) {
            printf("Failed to open file.\n");
            return 1;
        }
        char buffer[1024];
        setvbuf(file, buffer, _IOFBF, sizeof(buffer)); // 设置完全缓冲
        fprintf(file, "This is a test.\n");
        fclose(file);
        return 0;
    }
    
25. int fflush(FILE *stream);
  • 头文件<stdio.h>

  • 功能:刷新文件流的缓冲区。

  • 参数

    • FILE *stream:指向文件流的指针。如果为NULL,则刷新所有输出流。
  • 返回值:成功时返回0;如果发生错误,则返回EOF。

  • 例子

    #include <stdio.h>
    int main() {
        FILE *file = fopen("example.txt", "w");
        if (file == NULL) {
            printf("Failed to open file.\n");
            return 1;
        }
        fprintf(file, "This is a test.\n");
        fflush(file); // 刷新缓冲区
        fclose(file);
        return 0;
    }
    

这些函数是标准C语言中最常用的一些I/O函数,涵盖了标准输入/输出和文件操作的基本需求。希望这些信息对你有帮助!如果有任何其他问题或需要进一步的解释,请告诉我。

文件描述符

  • 标准IO函数通过FILE类型的结构体指针,系统IO函数则是通过文件描述符来完成
  • 在这里插入图片描述

文件描述符和文件结构体指针相互的转换

在这里插入图片描述

  • fdopen:将文件描述符转换为文件流,方便使用标准I/O函数进行操作。
  • fileno:将文件流转换为文件描述符,方便使用低级I/O系统调用进行操作。
fdopen 函数
  • 函数原型
FILE *fdopen(int fd, const char *mode);
  • 参数说明

    • int fd:文件描述符。

    • const char *mode:打开模式(如"r"表示只读,"w"表示写入,"a"表示追加等)。

  • 所在头文件

    • <stdio.h>
  • 返回值

    • 成功时返回指向文件流的指针。

    • 失败时返回NULL

  • 简单示例

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main() {
    int fd = open("example.txt", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    FILE *fp = fdopen(fd, "r+");
    if (fp == NULL) {
        perror("fdopen");
        close(fd);
        return 1;
    }

    // 使用文件流进行操作
    const char *message = "Hello, fdopen!";
    fwrite(message, 1, strlen(message), fp);

    // 重置文件位置指针
    rewind(fp);

    char buffer[100];
    size_t bytesRead = fread(buffer, 1, sizeof(buffer) - 1, fp);
    buffer[bytesRead] = '\0';
    printf("Read from file: %s\n", buffer);

    fclose(fp); // 关闭文件流,同时关闭文件描述符
    return 0;
}
fileno 函数
  • 函数原型
int fileno(FILE *stream);
  • 参数说明

  • FILE *stream:指向文件流的指针。

  • 所在头文件

  • <stdio.h>

  • 返回值

  • 成功时返回文件描述符。

  • 失败时返回-1。

  • 简单示例

#include <stdio.h>
#include <unistd.h>

int main() {
    FILE *fp = fopen("example.txt", "r+");
    if (fp == NULL) {
        perror("fopen");
        return 1;
    }

    int fd = fileno(fp);
    if (fd == -1) {
        perror("fileno");
        fclose(fp);
        return 1;
    }

    printf("File descriptor: %d\n", fd);

    // 使用文件描述符进行操作
    const char *message = "Hello, fileno!";
    write(fd, message, strlen(message));

    // 重置文件位置指针
    lseek(fd, 0, SEEK_SET);

    char buffer[100];
    ssize_t bytesRead = read(fd, buffer, sizeof(buffer) - 1);
    buffer[bytesRead] = '\0';
    printf("Read from file: %s\n", buffer);

    fclose(fp); // 关闭文件流,同时关闭文件描述符
    return 0;
}

文件I/O的系统调用

  • 文件操作函数的头文件一般都需要加上unistd.h
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

标准输入/输出函数

1. ssize_t read(int fd, void *buf, size_t count);

在这里插入图片描述

  • 头文件<unistd.h>

  • 功能:从文件描述符fd读取最多count个字节到缓冲区buf

  • 参数

    • int fd:文件描述符。
    • void *buf:指向存储读取数据的缓冲区的指针。
    • size_t count:要读取的最大字节数。
  • 返回值:成功时返回实际读取的字节数;到达文件结束时返回0;发生错误时返回-1。

  • 例子

    #include <unistd.h>
    #include <stdio.h>
    
    int main() {
        char buffer[100];
        ssize_t bytesRead = read(STDIN_FILENO, buffer, sizeof(buffer) - 1);
        if (bytesRead == -1) {
            perror("read");
            return 1;
        }
        buffer[bytesRead] = '\0'; // 确保字符串以空字符结尾
        printf("Read from stdin: %s\n", buffer);
        return 0;
    }
    
2. ssize_t write(int fd, const void *buf, size_t count);

在这里插入图片描述

  • 头文件<unistd.h>

  • 功能:将buf中的count个字节写入文件描述符fd

  • 参数

    • int fd:文件描述符。
    • const void *buf:指向要写入的数据的缓冲区的指针。
    • size_t count:要写入的字节数。
  • 返回值:成功时返回实际写入的字节数;发生错误时返回-1。

  • 例子

    #include <unistd.h>
    #include <stdio.h>
    
    int main() {
        const char *message = "Hello, World!\n";
        ssize_t bytesWritten = write(STDOUT_FILENO, message, strlen(message));
        if (bytesWritten == -1) {
            perror("write");
            return 1;
        }
        return 0;
    }
    

复制案例

在这里插入图片描述

  • io.h
    #ifndef __IO_H__
    #define __IO_H__
    extern void copy(int fdin,int fdout);
    #endif
    
  • io.c
    #include<io.h>
    #include<errno.h>
    #include<fcntl.h>
    #include<unistd.h>
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    
    #define BUFFER_LEN 1024
    
    void copy(int fdin,int fdout)
    {
      char buffer[BUFFER_LEN];
      ssize_t size;
    
      while((size=read(fdin,buffer,BUFFER_LEN))>0)
      {
        if(size<0)
        {
          fprintf(stderr,"read error:%s\n",strerror(errno));
          exit(1);
        }
        else
        {
          if(write(fdout,buffer,size)!=size)
          {
            fprintf(stderr,"read error:%s\n",strerror(errno));
            exit(1);
          }
        }
      }
    

gcc obj/io -Iinclude -c src/io.c

  • -Iinclude
    -在这里插入图片描述
  • -c
    - 产生目标文件

gcc bin/cp -Iinclude obj/io.o src/cp.c或者gcc bin/cp -Iinclude src/io.c src/cp.c

  • cp.c
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #include<fcntl.h>
    #include<unistd.h>
    #include<errno.h>
    #include"io.h"
    int main(int argc,char ** argv)
    {
      if(argc<3)
      {
        fprintf(stderr,"usage:%s srcfile destfile \n",argv[0]);
        exit(1);
      }
    
      int fdin = open(argv[1],O_RDONLY);
      if(fdin<0)
      {
        fprintf(stderr,"%s fdin open fails:%s \n",argv[1],strerror(errno));
        exit(1);
      }
      else
      {
        printf("%s %d\n",argv[1],fdin);
      }
      int fdout = open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0777);
      if(fdout<0)
      {
        fprintf(stderr,"%s fdout open fails:%s \n",argv[2],strerror(errno));
        exit(1);
      }else{
        printf("%s %d\n",argv[2],fdout);
      }
      copy(fdin,fdout);
      close(fdin);
      close(fdout);
      return 0;
    }
    

文件操作函数

  • C库函数的头文件都在\usr\include
  • -查找头文件所在的位置。可以使用gcc
    #include <sys/stat.h>
    
    int main() {
        return 0;
    }
    
    gcc -M test.c
    
3. int open(const char *pathname, int flags, mode_t mode);

在这里插入图片描述

  • 头文件<fcntl.h><sys/stat.h>

  • 功能:打开或创建一个文件,并返回一个文件描述符。

  • 参数

    • const char *pathname:文件路径。
    • int flags:打开模式(如O_RDONLY表示只读,O_WRONLY表示只写,O_RDWR表示读写等在头文件<fcntl.h>中定义)。
      • 在这里插入图片描述
        //例如,创建一个用户可读可写的文件:
        int fd = open("example.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
        
    • mode_t mode:文件权限(仅在创建文件时使用)。
      • mode参数是一个mode_t类型的值,通常由几个权限位按位或(|)组合而成。以下是一些常用的权限位及其说明:

      • 用户权限

        • S_IRUSR:用户读权限(0400)
        • S_IWUSR:用户写权限(0200)
        • S_IXUSR:用户执行权限(0100)
      • 组权限
        - S_IRGRP:组读权限(0040)
        - S_IWGRP:组写权限(0020)
        - S_IXGRP:组执行权限(0010)

      • 其他用户权限

        • S_IROTH:其他用户读权限(0004)
        • S_IWOTH:其他用户写权限(0002)
        • S_IXOTH:其他用户执行权限(0001)
      • 权限组合
        你可以通过按位或运算(|)组合多个权限位来设置文件的权限。例如:

        • 用户可读可写,组和其他用户不可访问:

          mode_t mode = S_IRUSR | S_IWUSR;
          
        • 用户可读可写可执行,组可读可执行,其他用户可读:

          mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH;
          
      • 以下是一些常见的权限组合示例:

        1. 用户可读可写

          int fd = open("example.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
          
        2. 用户可读可写可执行

          int fd = open("example.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IXUSR);
          
        3. 用户可读可写,组可读,其他用户不可访问

          int fd = open("example.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
          
        4. 用户可读可写可执行,组可读可写,其他用户可读

          int fd = open("example.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IROTH);
          
      • 八进制表示法
        - 权限也可以用八进制数字表示,每个数字对应一组权限:
        - 第一个数字:用户权限
        - 第二个数字:组权限
        - 第三个数字:其他用户权限

          例如:
          - `0600`:用户可读可写,组和其他用户不可访问
          - `0755`:用户可读可写可执行,组可读可执行,其他用户可读可执行
          - `0644`:用户可读可写,组和其他用户可读
          - 使用八进制表示法设置权限:
        
        int fd = open("example.txt", O_CREAT | O_RDWR, 0600);
        
  • 返回值:成功时返回文件描述符;如果打开失败,则返回-1。

  • 例子

    #include <fcntl.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <stdio.h>
    
    int main() {
        int fd = open("example.txt", O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
        if (fd == -1) {
            perror("open");
            return 1;
        }
        close(fd);
        return 0;
    }
    
creat

在这里插入图片描述
creat函数是Linux系统中用于创建文件的一个简化版本的open函数。creat函数的主要特点是它总是创建一个新的文件,并且只以写模式打开文件。如果文件已经存在,creat会截断文件并覆盖其内容。

函数原型

#include <fcntl.h>
int creat(const char *pathname, mode_t mode);
  • 参数说明

    • const char *pathname:要创建的文件的路径。

    • mode_t mode:文件的权限模式。

  • 返回值

    • 成功时返回文件描述符(非负整数)。

    • 失败时返回-1,并设置errno以指示错误类型。

  • 常用的权限模式

    权限模式可以用mode_t类型的值表示,通常由几个权限位按位或(|)组合而成。以下是一些常用的权限位:

    • S_IRUSR:用户读权限(0400)
    • S_IWUSR:用户写权限(0200)
    • S_IXUSR:用户执行权限(0100)
    • S_IRGRP:组读权限(0040)
    • S_IWGRP:组写权限(0020)
    • S_IXGRP:组执行权限(0010)
    • S_IROTH:其他用户读权限(0004)
    • S_IWOTH:其他用户写权限(0002)
    • S_IXOTH:其他用户执行权限(0001)
  • 示例

    • #include <fcntl.h>
      #include <unistd.h>
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <errno.h>
      
      int main() {
          int fd;
          const char *filename = "example.txt";
          const char *message = "Hello, creat!";
          char buffer[100];
      
          // 创建文件,权限为用户可读可写
          fd = creat(filename, S_IRUSR | S_IWUSR);
          if (fd == -1) {
              perror("creat");
              exit(EXIT_FAILURE);
          }
      
          // 写入数据
          ssize_t bytesWritten = write(fd, message, strlen(message));
          if (bytesWritten == -1) {
              perror("write");
              close(fd);
              exit(EXIT_FAILURE);
          }
      
          // 重置文件位置指针
          lseek(fd, 0, SEEK_SET);
      
          // 读取数据
          ssize_t bytesRead = read(fd, buffer, sizeof(buffer) - 1);
          if (bytesRead == -1) {
              perror("read");
              close(fd);
              exit(EXIT_FAILURE);
          }
          buffer[bytesRead] = '\0'; // 确保字符串以空字符结尾
          printf("Read from file: %s\n", buffer);
      
          // 关闭文件
          close(fd);
          return 0;
      }
      
4. int close(int fd);

在这里插入图片描述

  • 头文件<unistd.h>

  • 功能:关闭一个已打开的文件描述符。

  • 参数

    • int fd:文件描述符。
  • 返回值:成功时返回0;如果发生错误,则返回-1。

5. off_t lseek(int fd, off_t offset, int whence);

在这里插入图片描述
在这里插入图片描述

  • 可以计算文件的大小
 printf("%s file length:%ld\n",argv[1],lseek(fdin,0L,SEEK_END));
  • 头文件<unistd.h>

  • 功能:设置文件描述符fd的读写位置。

  • 参数

    • int fd:文件描述符。
    • off_t offset:相对于whence的偏移量。如 long 或 long long
    • int whence:位置基准点(如SEEK_SET表示文件开头,SEEK_CUR表示当前位置,SEEK_END表示文件结尾)。
  • 返回值:成功时返回新的文件位置;如果发生错误,则返回-1。

  • 例子

    #include <fcntl.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <stdio.h>
    
    int main() {
        int fd = open("example.txt", O_RDWR);
        if (fd == -1) {
            perror("open");
            return 1;
        }
        off_t new_pos = lseek(fd, 5, SEEK_SET); // 移动到文件开头后的第5个字节
        if (new_pos == -1) {
            perror("lseek");
            close(fd);
            return 1;
        }
        close(fd);
        return 0;
    }
    
生成空洞文件
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<fcntl.h>
#include<unistd.h>

char *buffer = "0123456789";

int main(int argc,char *argv[])
{
        if(argc<2)
        {

                fprintf(stderr,"parameter is less\n");
                exit(0);
        }
        int fd = open(argv[1],O_CREAT|O_RDWR,0777);
        if(fd==-1) // 文件打开s失败
        {
                fprintf(stderr,"%s file open fail\n",argv[1]);
                exit(1);
        }
        lseek(fd,20L,SEEK_SET);
        if(write(fd,buffer,strlen(buffer)*sizeof(char))==-1)
        {
                fprintf(stderr,"write error %s\n",argv[1]);
                exit(1);
        }
        return 0;
}
  • 查看文件的ASCALL码
    • od -c hole
  • 查看文件磁盘块大小
    • sudo tune2fs -l /dev/sda1
    • 在这里插入图片描述
    • 我们每次一次io读写文件,读写的基本单位是一个磁盘块,一个磁盘块的大小是4096个字节。所以缓存大小设置为磁盘块的大小
6. int dup(int oldfd);

在这里插入图片描述
在这里插入图片描述
- **是将oldfd的文件描述符表的指针复制给newfd,使oldfd和newfd都指向oldfd的文件描述符表的指针**

  • 头文件<unistd.h>

  • 功能:复制一个文件描述符。

  • 参数

    • int oldfd:要复制的文件描述符。
  • 返回值:成功时返回新的文件描述符;如果发生错误,则返回-1。

  • 例子

    #include <unistd.h>
    #include <stdio.h>
    
    int main() {
        int fd = open("example.txt", O_RDWR);
        if (fd == -1) {
            perror("open");
            return 1;
        }
        int new_fd = dup(fd);
        if (new_fd == -1) {
            perror("dup");
            close(fd);
            return 1;
        }
        close(fd);
        close(new_fd);
        return 0;
    }
    
实现cat命令
#include"io.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>


int main(int argc, char *argv[])
{
        int fd_in = STDIN_FILENO;
        int fd_out = STDOUT_FILENO;
        for(int i=1;i<argc;i++)   // 这里是为了实现输入    cat file.txt  的情况
        {
                fd_in = open(argv[i],O_RDONLY);
                if(fd_in<0)
                        {
                                perror("open error");
                                continue;
                        }
                copy(fd_in,fd_out);
                close(fd_in);
        }
        if(argc==1)   // 这里实现的是只是输入  cat命令时的情况
                copy(fd_in,fd_out);
        return 0;
}
实现±重定向

mcat + file.txt // 将file.txt输出到屏幕中,这要求将file.txt以只读方式打开之后,将其文件描述符表的指针复制给标准输入
mcat - file.txt //将屏幕输入的内容输出到file.txt中,这要求以可读方式打开file.txt之后,将其文件描述符表指针复制给标准输出

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#include"io.h"
/*
        bin/mcat + file +为输入从定向
        bin/mcat - file - 为输出重定向
*/

int main(int argc,char *argv[])
{
        int fd_in,fd_out;
        int flag = 0;

        for(int i =1;i<argc;i++)
        {
                if(!strcmp("+",argv[i]))
                {
                        fd_in = open(argv[++i],O_RDONLY);
                        if(fd_in<0)
                        {
                                perror("poen error");
                                exit(1);
                        }
                        // 将标准输入重定向到文件
                        if(dup2(fd_in,STDIN_FILENO)!=STDIN_FILENO)
                        {
                                perror("dup2 error");
                                exit(1);
                        }
                        close(fd_in);
                }
                else if(!strcmp("-",argv[i]))
                {
                        // 将文件的内容不是输出到屏幕而是输出到一个文件中
                        fd_out = open(argv[++i],O_WRONLY|O_CREAT|O_TRUNC,0777);
                        if(fd_out<0)
                        {
                                perror("open error");
                                exit(1);
                        }
                        if(dup2(fd_out,STDOUT_FILENO)!=STDOUT_FILENO)
                        {
                                perror("dup2 error");
                                exit(1);
                        }
                        close(fd_out);
                }
                else
                {
                        flag = 1;
                        fd_in = open(argv[i],O_RDONLY);
                        if(fd_in<0)
                        {
                                perror("open error");
                                exit(1);
                        }
                        if(dup2(fd_in,STDIN_FILENO))
                        {
                                perror("dup2 error");
                                exit(1);
                        }
                        copy(STDIN_FILENO,STDOUT_FILENO);
                        close(fd_in);

                }

        }

        if(!flag)
                copy(STDIN_FILENO,STDOUT_FILENO);

        return 0;
}

文件描述符的复制

7. int dup2(int oldfd, int newfd);
  • 头文件<unistd.h>

  • 功能:复制一个文件描述符,并将其绑定到另一个文件描述符。

  • 参数

    • int oldfd:要复制的文件描述符。
    • int newfd:新的文件描述符。
  • 返回值:成功时返回新的文件描述符;如果发生错误,则返回-1。

  • 例子

    #include <unistd.h>
    #include <stdio.h>
    
    int main() {
        int fd = open("example.txt", O_RDWR);
        if (fd == -1) {
            perror("open");
            return 1;
        }
        int new_fd = dup2(fd, 3); // 将fd复制到文件描述符3
        if (new_fd == -1) {
            perror("dup2");
            close(fd);
            return 1;
        }
        close(fd);
        close(new_fd);
        return 0;
    }
    

文件操作的内核数据结构

在这里插入图片描述
在这里插入图片描述

int fcntl(int fd, int cmd, … /* arg */ );

在这里插入图片描述在这里插入图片描述

fcntl 函数是 Unix 和类 Unix 操作系统中用于文件描述符控制的多功能函数。它可以执行多种与文件描述符相关的操作,如复制文件描述符、获取和设置文件状态标志、获取和设置文件锁等。

#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );
  • fd:文件描述符,表示要操作的文件或 I/O 对象。

  • cmd:命令,指定要执行的操作。常见的命令包括:

    • F_DUPFD:复制文件描述符。
    • F_GETFD:获取文件描述符的标志。
    • F_SETFD:设置文件描述符的标志。
    • F_GETFL:获取文件状态标志。
    • F_SETFL:设置文件状态标志。
    • F_GETLK:获取文件锁。
    • F_SETLK:设置文件锁。
    • F_SETLKW:设置文件锁,等待锁释放。
  • arg:根据 cmd 的不同,第三个参数可能是整数、指向 struct flock 的指针或其他类型的参数。

    1. 复制文件描述符
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main() {
    int old_fd = 0; // 标准输入文件描述符
    int new_fd;

    // 复制文件描述符
    new_fd = fcntl(old_fd, F_DUPFD, 100); // 从100开始寻找最小的未使用的文件描述符
    if (new_fd == -1) {
        perror("fcntl F_DUPFD");
        return 1;
    }

    printf("Old FD: %d, New FD: %d\n", old_fd, new_fd);

    // 关闭新旧文件描述符
    close(old_fd);
    close(new_fd);

    return 0;
}
    1. 获取和设置文件描述符标志
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main() {
    int fd =; // 标准输入文件描述符
    int flags;

    // 获取文件描述符标志
    flags = fcntl(fd, F_GETFD);
    if (flags == -1) {
        perror("fcntl F_GETFD");
        return 1;
    }

    printf("Current flags: %d\n", flags);

    // 设置文件描述符标志
    if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
        perror("fcntl F_SETFD");
        return 1;
    }

    // 再次获取文件描述符标志
    flags = fcntl(fd, F_GETFD);
    if (flags == -1) {
        perror("fcntl F_GETFD");
        return 1;
    }

    printf("New flags: %d\n", flags);

    return 0;
}
    1. 获取和设置文件状态标志
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

int main() {
    int fd =; // 标准输入文件描述符
    int flags;

    // 获取文件状态标志
    flags = fcntl(fd, F_GETFL);
    if (flags == -1) {
        perror("fcntl F_GETFL");
        return 1;
    }

    printf("Current file status flags: %d\n", flags);

    // 设置文件状态标志
    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
        perror("fcntl F_SETFL");
        return 1;
    }

    // 再次获取文件状态标志
    flags = fcntl(fd, F_GETFL);
    if (flags == -1) {
        perror("fcntl F_GETFL");
        return 1;
    }

    printf("New file status flags: %d\n", flags);

    return 0;
}
    1. 文件锁
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/file.h>

int main() {
    int fd;
    struct flock lock;

    // 打开文件
    fd = open("example.txt", O_RDWR | O_CREAT, 06½);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 初始化文件锁结构
    lock.l_type = F_WRLCK;  // 写锁
    lock.l_whence = SEEK_SET;
    lock.l_start = 0;
    lock.l_len = 0;  // 整个文件
    lock.l_pid = getpid();

    // 设置文件锁
    if (fcntl(fd, F_SETLK, &lock) == -1) {
        perror("fcntl F_SETLK");
        close(fd);
        return 1;
    }

    // 释放文件锁
    lock.l_type = F_UNLCK;
    if (fcntl(fd, F_SETLK, &lock) == -1) {
        perror("fcntl F_SETLK");
        close(fd);
        return 1;
    }

    // 关闭文件
    close(fd);

    return 0;
}

总结

fcntl 函数是一个非常强大的工具,可以用于多种文件描述符相关的操作。以下是一些常见的操作:

  • 复制文件描述符F_DUPFD
  • 获取和设置文件描述符标志F_GETFDF_SETFD
  • 获取和设置文件状态标志F_GETFLF_SETFL
  • 文件锁F_GETLKF_SETLKF_SETLKW
设置文件标准标志
void set_fl(int fd,int flag)
{
        int val = fcntl(fd,F_GETFL);// 获取原来的文件状态n标志
        val|=flag;  // 增加新的文件状态标志
        if(fcntl(fd,F_SETFL,val)<0)
                fprintf(stderr,"fcntl error %s\n",strerror(errno));
}

void clr_fl(int fd,int flag)
{
        int val = fcntl(fd,F_GETFL);
        // 清除指定的文件状态标志
        val&=~flag;
        if(fcntl(fd,F_SETFL,val)<0)
                fprintf(stderr,"fcntl error %s",strerror(errno));

}
文件描述符标志和文件状态标志的区别

fcntl 函数中,文件描述符标志(File Descriptor Flags)和文件状态标志(File Status Flags)是两种不同类型的状态标志,它们各自有不同的用途和意义。

文件描述符标志(File Descriptor Flags)

文件描述符标志是与特定文件描述符相关联的标志,而不是与文件本身相关联的标志。这些标志通常影响文件描述符的行为,特别是在进程执行 exec 系列函数时。

常见的文件描述符标志

  • FD_CLOEXEC:这是一个非常重要的标志。当设置此标志时,文件描述符将在执行 exec 系列函数时自动关闭。如果没有设置此标志,文件描述符将保持打开状态。

设置和获取文件描述符标志

  • 获取文件描述符标志

    int flags = fcntl(fd, F_GETFD);
    if (flags == -1) {
        perror("fcntl F_GETFD");
        return 1;
    }
    
  • 设置文件描述符标志

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

文件状态标志(File Status Flags)

文件状态标志是与文件本身相关联的标志,它们影响文件的打开方式和 I/O 操作的行为。这些标志通常在打开文件时通过 open 函数的 flags 参数设置,也可以在文件打开后通过 fcntl 函数修改。

常见的文件状态标志

  • O_RDONLY:只读模式。
  • O_WRONLY:只写模式。
  • O_RDWR:读写模式。
  • O_APPEND:每次写操作都追加到文件末尾。
  • O_NONBLOCK:非阻塞模式。
  • O_SYNC:同步写操作,确保数据立即写入磁盘。
  • O_CREAT:如果文件不存在,则创建文件。
  • O_TRUNC:如果文件已存在且为只写或读写模式,则截断文件长度为0。
  • O_EXCL:与 O_CREAT 一起使用,如果文件已存在,则打开失败。

设置和获取文件状态标志

  • 获取文件状态标志

    int flags = fcntl(fd, F_GETFL);
    if (flags == -1) {
        perror("fcntl F_GETFL");
        return 1;
    }
    
  • 设置文件状态标志

    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
        perror("fcntl F_SETFL");
        return 1;
    }
    

主要区别

  1. 作用对象

    • 文件描述符标志:作用于特定的文件描述符,影响文件描述符的行为。
    • 文件状态标志:作用于文件本身,影响文件的打开方式和 I/O 操作的行为。
  2. 使用场景

    • 文件描述符标志:主要用于控制文件描述符在 exec 系列函数执行时的行为。
    • 文件状态标志:主要用于控制文件的打开方式和 I/O 操作的行为。
  3. 标志位

    • 文件描述符标志:主要标志是 FD_CLOEXEC
    • 文件状态标志:包括 O_RDONLYO_WRONLYO_RDWRO_APPENDO_NONBLOCKO_SYNC 等。

示例

以下是一个示例,展示了如何分别获取和设置文件描述符标志和文件状态标志:

#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

int main() {
    int fd;
    int fd_flags, fl_flags;

    // 打开文件
    fd = open("example.txt", O_RDWR | O_CREAT, 0644);
    if (fd == -1) {
        perror("open");
        return 1;
    }

    // 获取文件描述符标志
    fd_flags = fcntl(fd, F_GETFD);
    if (fd_flags == -1) {
        perror("fcntl F_GETFD");
        close(fd);
        return 1;
    }
    printf("Current FD flags: %d\n", fd_flags);

    // 设置文件描述符标志
    if (fcntl(fd, F_SETFD, fd_flags | FD_CLOEXEC) == -1) {
        perror("fcntl F_SETFD");
        close(fd);
        return 1;
    }
    printf("New FD flags: %d\n", fcntl(fd, F_GETFD));

    // 获取文件状态标志
    fl_flags = fcntl(fd, F_GETFL);
    if (fl_flags == -1) {
        perror("fcntl F_GETFL");
        close(fd);
        return 1;
    }
    printf("Current file status flags: %d\n", fl_flags);

    // 设置文件状态标志
    if (fcntl(fd, F_SETFL, fl_flags | O_NONBLOCK) == -1) {
        perror("fcntl F_SETFL");
        close(fd);
        return 1;
    }
    printf("New file status flags: %d\n", fcntl(fd, F_GETFL));

    // 关闭文件
    close(fd);

    return 0;
}

总结

  • 文件描述符标志:与特定文件描述符相关联,影响文件描述符的行为,特别是 exec 时的行为。
  • 文件状态标志:与文件本身相关联,影响文件的打开方式和 I/O 操作的行为。

希望这些信息对你有帮助!如果你有任何其他问题或需要进一步的解释,请告诉我。

文件的原子操作

I/O处理模型

在这里插入图片描述

非阻塞IO

在这里插入图片描述

  • 设置阻塞方式,睡眠之后会等待输入

    #include<stdio.h>
    #include<fcntl.h>
    #include<unistd.h>
    #include<string.h>
    #include<stdlib.h>
    
    
    int main()
    {
            char buffer[4096] = {'\0'};
            ssize_t size = 0;
    
            sleep(5);
    
            size = read(STDIN_FILENO,buffer,sizeof(buffer));  // 默认是阻塞的
            if(size<0)
            {
    
                    perror("read error");
                    exit(1);
            }
            else if(size==0)
            {
                    printf("read finished!\n");
            }
            else
            {
                    if(write(STDOUT_FILENO,buffer,size)!=size)
                            perror("write error");
            }
            return 0;
    }
    
  • 当设置为阻塞方式时,没有输入内容会报错

    int main()
    {
            char buffer[4096] = {'\0'};
            ssize_t size = 0;
    
            set_fl(STDIN_FILENO,O_NONBLOCK);
            sleep(5);
    
            size = read(STDIN_FILENO,buffer,sizeof(buffer));
            // 设置非阻塞
            if(size<0)
            {
    
                    perror("read error");
                    exit(1);
            }
            else if(size==0)
            {
                    printf("read finished!\n");
            }
            else
            {
                    if(write(STDOUT_FILENO,buffer,size)!=size)
                            perror("write error");
            }
            return 0;
    }
    
    • 在这里插入图片描述

文件锁机制

存储映射

--------------------

文件操作函数

文件共享机制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/913377.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Modbus TCP 西门子PLC与 多个设备进行通讯 使用Modbus Slave模拟多个设备ID

目录 1前言 2相同地址不同ID 1创建连接数据 2创建连接程序 3模块参数设置 4Modbus Slave设置 5成果展示 3结语 1前言 本篇文章讲了PLC如何与同一地址的多个ID设备进行通讯&#xff0c;如果看不懂这篇文章就去看一下这篇博客学一下基础。 Modbus TCP 西门子PLC指令以太…

group_concat配置影响程序出bug

在 ThinkPHP 5 中&#xff0c;想要临时修改 MySQL 数据库的 group_concat_max_len 参数&#xff0c;可以使用 原生 SQL 执行 来修改该值。你可以通过 Db 类来执行 SQL 语句&#xff0c;从而修改会话&#xff08;Session&#xff09;级别的变量。 步骤 设置 group_concat_max_l…

UnixBench和Geekbench进行服务器跑分

1 概述 服务器的基准测试&#xff0c;常见的测试工具有UnixBench、Geekbench、sysbench等。本文主要介绍UnixBench和Geekbench。 1.1 UnixBench UnixBench是一款开源的测试UNIX系统基本性能的工具&#xff08;https://github.com/kdlucas/byte-unixbench&#xff09;&#x…

皮卡超级壁纸 1.4.1 | 解锁会员版的全景壁纸、动态壁纸和超级壁纸

皮卡超级壁纸是一款提供海量壁纸的应用&#xff0c;不仅包含静态的精美壁纸&#xff0c;还提供了独特的超级壁纸。这些超级壁纸不仅仅是动态效果&#xff0c;还能自动匹配用户的手机UI&#xff0c;提供更加个性化的体验。解锁会员版后&#xff0c;用户可以享受更多高级功能和壁…

怎么查看navicat的数据库密码

步骤1:打开navicat连接数据库工具&#xff0c;顶部的文件栏-导出结果-勾选导出密码-导出 步骤2&#xff1a;导出结果使用NotePad或文本打开&#xff0c;找到&#xff0c;数据库对应的的Password"995E66F64A15F6776“”的值复制下来 <Connection ConnectionName"…

09 Oracle数据拯救:Flashback Technologies精细级数据恢复指南

文章目录 09 Oracle数据拯救&#xff1a;Flashback Technologies精细级数据恢复指南一、Flashback Technologies概览二、Flashback Query&#xff1a;查询过去的数据三、Flashback Table&#xff1a;恢复整个表四、Flashback Database&#xff1a;恢复整个数据库五、总结与最佳…

在vscode中如何利用git 查看某一个文件的提交记录

在 Visual Studio Code (VSCode) 中&#xff0c;你可以使用内置的 Git 集成来查看某个文件的提交历史。以下是具体步骤&#xff1a; 使用 VSCode 内置 Git 功能 打开项目&#xff1a; 打开你的项目文件夹&#xff0c;确保该项目已经是一个 Git 仓库&#xff08;即项目根目录下…

【Qt聊天室客户端】登录窗口

1. 验证码 具体实现 登录界面中创建验证码图片空间&#xff0c;并添加到布局管理器中 主要功能概述&#xff08;创建一个verifycodewidget类专门实现验证码操作&#xff09; 详细代码 // 头文件#ifndef VERIFYCODEWIDGET_H #define VERIFYCODEWIDGET_H#include <QWidget>…

ctfshow(328)--XSS漏洞--存储型XSS

Web328 简单阅读一下页面。 是一个登录系统&#xff0c;存在一个用户管理数据库。 那么我们注册一个账号&#xff0c;在账号或者密码中植入HTML恶意代码&#xff0c;当管理员访问用户管理数据库页面时&#xff0c;就会触发我们的恶意代码。 思路 我们向数据库中写入盗取管理员…

智能电销机器人的操作流程

对于电销行业的人来说&#xff0c;有了智能电销机器人&#xff0c;简直是太省心了&#xff01; 智能外呼机器人&#xff0c;是一款基于人工智能语音外呼系统&#xff0c; 它可以代替人工自动拨打电话&#xff0c;自动筛选客户&#xff0c;自动推送意向客户到你的微信上 &#x…

【ESP】一小时速通入门笔记

【ESP】一小时速通入门笔记 前言: 之前上学时就用过一次esp32, 当时初次使用搭建编译环境费了老大功夫.在我第一篇esp32笔记中也有说明.以至于我好像忘记记录完整的入门笔记了.最近因为工作需要又开始接触esp32才发现,现在已经方便得多了.顺利的话一小时速通. 前排提醒: 本笔记…

Linux【基础篇】

-- 原生罪 linux的入门安装学习 什么是操作系统&#xff1f; 用户通过操作系统和计算机硬件联系使用。桥梁~ 什么是Linux&#xff1f; 他是一套开放源代码&#xff08;在互联网上找到Linux系统的源代码&#xff0c;C语言写出的软件&#xff09;&#xff0c;可以自由 传播&…

Golang | Leetcode Golang题解之第540题有序数组中的单一元素

题目&#xff1a; 题解&#xff1a; func singleNonDuplicate(nums []int) int {low, high : 0, len(nums)-1for low < high {mid : low (high-low)/2mid - mid & 1if nums[mid] nums[mid1] {low mid 2} else {high mid}}return nums[low] }

Python学习从0到1 day26 第三阶段 Spark ⑤ 搜索引擎日志分析

目录 一、搜索引擎日志分析 二、需求1&#xff1a;热门搜索时间段(小时精度)Top3 实现步骤 三、需求2&#xff1a;打印输出:热门搜索词Top3 实现步骤 四、需求3&#xff1a;打印输出:统计hadoop关键字在哪个时段被搜索最多 实现步骤 五、需求4&#xff1a;将数据转换为JSON格式…

Pr:视频过渡快速参考(合集 · 2025版)

Adobe Premiere Pro 自带七组约四十多个视频过渡 Video Transitions效果&#xff0c;包含不同风格和用途&#xff0c;可在两个剪辑之间创造平滑、自然的转场&#xff0c;用来丰富时间、地点或情绪的变化。恰当地应用过渡可让观众更好地理解故事或人物。 提示&#xff1a; 点击下…

Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多变量回归预测

Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多变量回归预测 目录 Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多变量回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Transformer-GRU、Transformer、CNN-GRU、GRU、CNN五模型多变量回归预…

多模态大模型技术方向和应用场景

多模态大模型&#xff08;Multimodal Large Language Models&#xff0c;MLLM&#xff09;是一种结合了大型语言模型&#xff08;LLM&#xff09;和大型视觉模型&#xff08;LVM&#xff09;的深度学习模型&#xff0c;它们能够处理和理解多种类型的数据&#xff0c;如文本、图…

用 Python 从零开始创建神经网络(四):激活函数(Activation Functions)

激活函数&#xff08;Activation Functions&#xff09; 引言1. 激活函数的种类a. 阶跃激活功能b. 线性激活函数c. Sigmoid激活函数d. ReLU 激活函数e. more 2. 为什么使用激活函数3. 隐藏层的线性激活4. 一对神经元的 ReLU 激活5. 在隐蔽层中激活 ReLU6. ReLU 激活函数代码7. …

从0到1基于LangChain制作一个AI猫娘

前言&#xff1a; 看到B站上的AIVtuber的项目落地了&#xff0c;就心血来潮想制作一个AI的猫娘供自己使用&#xff0c;顺便出一个简单的教程&#xff0c;跳过理论&#xff0c;直接实践&#xff0c;作者也还在学习摸索中&#xff0c;所以有错误可以直接在评论区指正。&#xff0…

【R78/G15 开发板测评】串口打印 DHT11 温湿度传感器、DS18B20 温度传感器数据,LabVIEW 上位机绘制演化曲线

【R78/G15 开发板测评】串口打印 DHT11 温湿度传感器、DS18B20 温度传感器数据&#xff0c;LabVIEW 上位机绘制演化曲线 主要介绍了 R78/G15 开发板基于 Arduino IDE 环境串口打印温湿度传感器 DHT11 和温度传感器 DS18B20 传感器的数据&#xff0c;并通过LabVIEW上位机绘制演…