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

news2024/11/23 6:09:23

文件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;
    }
    
    • 在这里插入图片描述

文件锁机制

存储映射

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

文件操作函数

文件共享机制

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux网络的基本设置

1、查看网络接口信息 ip a/ip addr #简略的查看网络接口信息 ifconfig #只显示当前活跃的设备 ifconfig -a #实现当前主机的所有网络设备&#xff0c;包括未运行的设备 rootubuntu1:~# ifconfig ens33:flags4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 设备名…

利用AI制作《职业生涯规划PPT》,10分钟完成

职业生涯规划是大学生活中非常重要的一环。通过制定职业规划&#xff0c;你能够明确未来的职业目标、认清自身的优劣势&#xff0c;进而制定切实可行的计划&#xff0c;以便顺利踏上职业发展的道路。而制作一份精美的职业生涯规划PPT&#xff0c;能有效帮助你在面试、职业规划报…

【数据结构与算法】希尔排序(直接插入排序)

大家好&#xff0c;我是小卡皮巴拉 文章目录 目录 引言 一.直接插入排序的基本思想 二. 直接插入排序算法解析 详细版本的算法思想解析 算法思想提炼 实现代码 画图刨析 三. 直接插入排序的特性 复杂度分析 稳定性分析 四. 希尔排序的基本思想 五. 希尔排序算法解…

RK3568 Android12跳过认证 预置谷歌服务GMS

在Rom开发中需要发布海外版本时基本都需要内置google服务,而规范方式集成的话都需要设备进行认证,获取google应用签名等非常复杂的一套流程,一般大厂才有这些资质和资源,这里介绍一种非常规方式集成GMS,跳过设置认证流程,在RK3568 android12环境亲测有效。 谷歌全家桶中…

深度学习之卷积问题

1 卷积在图像中有什么直观作用 ​ 在卷积神经网络中&#xff0c;卷积常用来提取图像的特征&#xff0c;但不同层次的卷积操作提取到的特征类型是不相同的&#xff0c;特征类型粗分如表1所示。 ​ 表1 卷积提取的特征类型 卷积层次特征类型浅层卷积边缘特征中层卷积局部特征深…

Go语言的内置容器

文章目录 一、数组数组的定义数组声明数组特点数组元素修改 二、切片切片声明基于数组创建切片使用make()函数构造切片使用append()为切片动态添加元素\使用copy()复制新的切片数组与切片相互转换 三、Map映射Map定义使用make()函数创建map用切片作为map的值使用delete()函数删…

二叉树的各种操作补充

二叉树的各种操作补充 求二叉树的结点数求二叉树的叶结点数求二叉树的高度求二叉树的第k层结点数查找指定结点层序遍历判断二叉树是否是完全二叉树 我们任然沿用二叉树的基本信息&#xff1a; typedef char BTDataType; typedef struct BinaryTreeNode {BTDataType _data;struc…

Go语言的常用内置函数

文章目录 一、Strings包字符串处理包定义Strings包的基本用法Strconv包中常用函数 二、Time包三、Math包math包概述使用math包 四、随机数包&#xff08;rand&#xff09; 一、Strings包 字符串处理包定义 Strings包简介&#xff1a; 一般编程语言包含的字符串处理库功能区别…

Perfetto中如何使用SQL语句

在使用 Perfetto 分析 Android 性能时&#xff0c;可以通过 Perfetto 提供的内置 SQL 查询来提取和分析不同的性能数据。Perfetto 允许你在 UI 界面或命令行中运行 SQL 查询&#xff0c;提取出 Trace 数据中包含的各种性能信息&#xff0c;比如 CPU 使用率、线程状态、内存分配…

QML项目实战:自定义TextField

目录 一.添加模块 import QtQuick.Controls 1.2 import QtQuick.Controls.Styles 1.4 import QtGraphicalEffects 1.15 二.自定义TextField 1.属性设置 2.输入框设置 3.按钮开关 三.效果 1.readonly为false 2.readonly为true 四.代码 一.添加模块 import QtQuick.…

【进阶】Stable Diffusion 插件 Controlnet 安装使用教程(图像精准控制)

Stable Diffusion WebUI 的绘画插件 Controlnet 最近更新了 V1.1 版本&#xff0c;发布了 14 个优化模型&#xff0c;并新增了多个预处理器&#xff0c;让它的功能比之前更加好用了&#xff0c;最近几天又连续更新了 3 个新 Reference 预处理器&#xff0c;可以直接根据图像生产…

DAF-FM DA与NO反应后,生成的产物能够发出强烈的绿色荧光,254109-22-3

一、基本信息 产品名称&#xff1a;DAF-FM DA&#xff08;一氧化氮NO荧光探针DAF-FM&#xff09; 英文名称&#xff1a;DAF-FM DA&#xff0c;DAF-FM diacetate CAS号&#xff1a;254109-22-3 分子式&#xff1a;C25H18F2N2O7 供应商&#xff1a;陕西新研博美生物科技 分…

在 Mac 和 Windows 系统中快速部署 OceanBase

OceanBase 是一款分布式数据库&#xff0c;具备出色的性能和高扩展性&#xff0c;可以为企业用户构建稳定可靠、灵活扩展性能的数据库服务。本文以开发者们普遍熟悉的Windows 或 Mac 环境为例&#xff0c;介绍如何快速上手并体验OceanBase。 一、环境准备 1. 硬件准备 OceanB…

使用Ant Design的Layout布局不能撑满整个屏幕问题解决方法

代码示例&#xff1a; import React, { useState } from react import {LaptopOutlined,NotificationOutlined,UserOutlined, } from ant-design/icons import type { MenuProps } from antd import { Layout, Menu, theme } from antd import routes from ./routes/index imp…

【ubuntu18.04】使用U盘制作ubuntu18.04启动盘操作说明

打开show application 打开Startup Disk 选择镜像 双击选择ubuntu的iso镜像 镜像下载地址 Ubuntu 18.04.6 LTS (Bionic Beaver) 制作镜像 注意&#xff1a; 制作镜像会格式化U盘&#xff0c;记得备份资料 点击Make Startup Disk,弹出如下对话框 点击Yes 输入管理员密码&a…

22.04Ubuntu---ROS2创建python节点

创建工作空间 mkdir -p 02_ros_ws/src 然后cd到该目录 创建功能包 在这条命令里&#xff0c;tom就是你的功能包 ros2 pkg create tom --build-type ament_python --dependencies rclpy 可以看到tom功能包已经被创建成功了。 使用tree命令&#xff0c;得到如下文件结构 此时…

《手写Spring渐进式源码实践》实践笔记(第十七章 数据类型转换)

文章目录 第十七章 数据类型转换工厂设计实现背景技术背景Spring数据转换实现方式类型转换器&#xff08;Converter&#xff09;接口设计实现 业务背景 目标设计实现代码结构类图实现步骤 测试事先准备属性配置文件转换器工厂Bean测试用例测试结果&#xff1a; 总结 第十七章 数…

使用docker形式部署jumpserver

文章目录 前言一、背景二、使用步骤1.基础环境准备2.拉取镜像3.进行部署4.备份记录启动命令 前言 记录一下使用docker形式部署jumpserver服务的 一、背景 搭建一个jumpserver的堡垒机&#xff0c;但是发现之前是二进制文件部署的&#xff0c;会在物理机上部署污染环境&#x…

(62)使用RLS自适应滤波器进行系统辨识的MATLAB仿真

文章目录 前言一、基本概念二、RLS算法原理三、RLS算法的典型应用场景四、MATLAB仿真代码五、仿真结果1.滤波器的输入信号、参考信号、输出信号、误差信号2.对未知系统进行辨识得到的系数 总结与后续 前言 RLS&#xff08;递归最小二乘&#xff09;自适应滤波器是一种用于系统…

算法每日双题精讲——滑动窗口(长度最小的子数组,无重复字符的最长子串)

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 别再犹豫了&#xff01;快来订阅我们的算法每日双题精讲专栏&#xff0c;一起踏上算法学习的精彩之旅吧&#xff01;&#x1f4aa;…