IO基础笔记

IO即是input和output, 是程序与外部设备进行信息交换的过程。

1. IO分为标准IO和文件IO

标准IO:调用封装好的相关库函数,来实现数据的输入输出

文件IO:调用系统(内核)提供的相关函数,来实现数据的输入输出

标准IO和文件IO的区别:

1、标准IO属于库函数,文件IO属于系统调用

2、标准IO操作的是文件指针,文件IO操作的是文件描述符

3、标准IO有缓冲器,文件IO没有缓冲区

左图:

描述了一个传统计算机系统的架构,具体来说:

  1. 在最上层,有多个应用程序(app),它们位于用户空间。
  2. 应用程序通过库函数(如printf)与系统进行交互。
  3. 库函数调用系统调用(write),将数据从用户空间传递给内核空间。
  4. 内核空间包含驱动层,负责处理硬件相关的任务。
  5. 最底层是硬件平台,例如磁盘、终端和网络接口等。

右图:

是GNU/Linux操作系统的架构,具体来说:

  1. 用户空间包含了应用程序(app)和GNU C库(glibc)。glibc提供了系统调用的封装,使得应用程序能够方便地访问系统资源。
  2. 系统调用(sys_write)是用户空间与内核空间之间的重要桥梁,它允许应用程序请求内核执行某些特权操作。
  3. 内核空间包括Kernel层和架构依赖内核代码。Kernel层提供了一些基本的服务,而架构依赖内核代码则针对特定硬件平台进行了优化。

IO分为阻塞IO和非阻塞IO;

常用的IO接口函数:

标准IO:fprint、fscanf、fputc、fgetc、fputs、fgets、fread、 fwrite、fopen、fclose、fseek、ftell、rewind...

文件IO:open、close、read、write、seek...

<stdio.h>提供的IO函数

FILE结构体:

struct_IO_FILE
{
    char* _IO_buf_base;  /* 缓冲区开始地址 */
    char* _IO_buf_end;   /* 缓冲区结束地址 */

    int _fileno;         //用于系统调用的文件描述符
};

当一个程序启动后,系统会自动打开三个文件指针:

stdin:标准输入文件指针 scanf、getchar、gets

stdout:标准输出文件指针 printf、putchar、puts

stderr:标准出错文件指针 perror

以上三个文件指针,都是针对于终端文件操作而言的

fopen()

用法:FILE *fopen(const char *pathname, const char *mode);

DESCRIPTION
       The  fopen()  function opens the file whose name is the string pointed to by pathname and
       associates a stream with it.

              ┌─────────────┬───────────────────────────────┐
              │fopen() mode │ open() flags                  │
              ├─────────────┼───────────────────────────────┤
              │     r       │ O_RDONLY                      │
              ├─────────────┼───────────────────────────────┤
              │     w       │ O_WRONLY | O_CREAT | O_TRUNC  │
              ├─────────────┼───────────────────────────────┤
              │     a       │ O_WRONLY | O_CREAT | O_APPEND │
              ├─────────────┼───────────────────────────────┤
              │     r+      │ O_RDWR                        │
              ├─────────────┼───────────────────────────────┤
              │     w+      │ O_RDWR | O_CREAT | O_TRUNC    │
              ├─────────────┼───────────────────────────────┤
              │     a+      │ O_RDWR | O_CREAT | O_APPEND   │
              └─────────────┴───────────────────────────────┘

        r 以只读的形式打开文件,文件光标定位在开头.如果文件不存在,则报错

        r+ 以读写的形式打开文件,文件光标定位在开头.如果文件不存在,则报错

        w 以只写的形式打开文件,如果文件存在,则清空文件内容,如果文件不存在,则创建该文件,文件光标定位在开头.

        w+ 以读写的形式打开文件,如果文件存在,则清空文件内容,如果文件不存在,则创建该文件,文件光标定位在开头.

        a 以追加的形式打开文件,如果文件不存在则创建文件,文件光标定位在结尾

        a+ 以读或者追加的形式打开文件,如果文件不存在,则创建文件,如果第一次是读数据,则光标定位在开头,否则定位在结尾 返回值:成功调用返回打开的文件地址,失败返回NULL,并置位错误码

fclose()

用法 :fclose(FILE *stream);

功能:关闭给定的文件指针

参数1:要关闭的文件指针

返回值:成功返回0,失败返回EOF,并置位错误码

fgetc\fputc()

单字符的输入输出

int fputc(int c, FILE *stream);

功能:将给定的字符,写入到文件指针stream指向的文件中去

参数1:要写入的字符

参数2:打开的文件指针

返回值:成功返回写入字符的ascii值,失败返回EOF,并置位错误码 

int fgetc(FILE *stream);

功能:从指定文件中,读取一个字符

参数:打开的文件指针

返回值:从文件中读取的第一个字符的ascii值,失败返回EOF并置位错误码

有关错误码问题

strerror()

char *strerror(int errnum);

功能:将给定的错误码,转变成错误信息

参数1:错误码

返回值:错误码对应的错误信息的字符串

perror()

void perror(const char *s);

功能:向标准出错缓冲区中,写入最新的错误码对应的信息

参数:提示字符串,会自动提供一个冒号,并且输出结束后,会自动加一个换行

返回值:无

fputs\fgets:字符串输入输出

int fputs(const char *s, FILE *stream);

功能:将给定的字符串,写入到文件中

参数1:要写入的字符串起始地址

参数2:打开的文件指针 返回值:成功返回写入的字符个数(字符串长度),失败返回EOF

char *fgets(char *s, int size, FILE *stream);

功能:从stream所指向的文件中,最多读取size-1的字符到s中,在读取过程中,如果遇到回车或者文件结束,会结束本次读取,并且会把回车也放入容器中。在后面自动加上'\0'

参数1:存放数据的容器,一般是一个字符数组

参数2:读取的大小

参数3:文件指针

返回值:成功返回容器的起始地址,失败返回NULL

关于缓冲区

1> 标准IO提供了三种缓冲区:行缓存、全缓存、不缓存

2> 行缓存:有关标准输入、标准输出指针对应的缓冲区,其大小位1024字节

3> 全缓存:有关普通文件指针对应的缓冲区,其大小位4096字节

4> 不缓存:有关标准出错文件指针对应的缓冲区,其大小位 0

行缓存的刷新时机

1、换行会刷新行缓存

2、程序结束后,会自动刷新行缓存

3、当文件指针关闭后,会刷新行缓存

4、当使用fflush函数刷新文件指针时,会刷新行缓存

5、当输入输出切换时,会刷新行缓存 6、当缓存区满了后,再放数据时,会刷新行缓存

全缓存的刷新时机

2、程序结束后,会自动刷新全缓存

3、当文件指针关闭后,会刷新全缓存

4、当使用fflush函数刷新文件指针时,会刷新全缓存

5、当输入输出切换时,会刷新全缓存 6、当缓存区满了后,再放数据时,会刷新全缓存

练习:

使用fgets统计给定文件的行号

#include <myhead.h>
int main(int argc, char const *argv[])
{
    FILE *file;
    char line[1024]; // 假设每一行不一般超过1023个字符
    int count = 0;
    // 打开文件
    file = fopen(argv[1], "r");
    if (file == NULL)
    {
        printf("无法打开文件。\n");
        return 1;
    }
    // 逐行读取文件
    while (fgets(line, sizeof(line), file))
    {
        count++;
    }
    // 关闭文件
    fclose(file);
    printf("文件中有 %d 行\n", count);
    return 0;
}

使用fgets、fputs完成两个文件的拷贝

#include <myhead.h>
int main(int argc, char const *argv[])
{
    FILE *file1;
    FILE *file2;
    char line[1024]; // 假设每一行不一般超过1023个字符
    int count = 0;
    // 打开文件
    file1 = fopen(argv[1], "r");
    file2 = fopen(argv[2], "w");
    if (file1 == NULL || file2 == NULL)
    {
        printf("无法打开文件\n");
        return 1;
    }
    // 逐行读取文件
    while (fgets(line, sizeof(line), file1))
    {
        count++;
        fputs(line, file2);
    }
    // 关闭文件
    fclose(file1);
    fclose(file2);
    printf("文件中有 %d 行\n", count);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值