Linux 学习记录20(IO篇)

Linux 学习记录20(IO篇)

在这里插入图片描述

本文目录

  • Linux 学习记录20(IO篇)
  • IO大纲
  • 一、IO知识
    • 1. 最先接触的io知识: #include
    • 2. IO种类
    • 3. 什么是库函数?什么是系统调用
    • 4. 常用的函数接口的种类
  • 二、标准IO
    • 1. 什么是FILE结构体
    • 2. 如何找到FILE结构体
    • 3. 特殊的文件指针
    • 4. fopen的使用
    • 5. fclose的使用
    • 6. 关于错误码的问题
    • 7. fgetc/fputc函数的使用
      • (1. fputc
      • (2. fgetc
    • 8. fgets/fputs函数的使用
      • (1. stdout,stdin和stderr
      • (2. fputs
      • (3. fgets
  • 三、缓冲区
    • 1. 缓冲区的大小
    • 2. 缓冲区的刷新时间
      • (1. 行缓存
      • (1. 全缓存
  • 思维导图
  • 练习
    • 1. 使用fgets统计一个文件的行号
    • 2. 使用fgets、fputs拷贝文件

IO大纲

  1. IO
  1. 标准IO,文件IO
  1. 进程
  1. 进程的创建,线程间通讯
  1. 线程的创建和线程同步互斥
  1. Linux系统库
  1. 静态库,动态库

一、IO知识

1. 最先接触的io知识: #include

1> std:标准的
2> lO:输入输出,目前接触的是向终端进行输入输出
/usr/include <-----库文件存放文件目录

2. IO种类

1> 标准IO: 库函数实现
2> 文件IO:系统调用实现 函数库:#include

3. 什么是库函数?什么是系统调用

1> 系统调用:
从用户空间到内核空间的一次切换过程
不同的系统,进入内核空间的方式是不同的,所以,接口函数有所不同
但是,只要从用户空间,切换到内核空间,就会发生系统调用,效率比较低
2> 库函数:
库函数是对系统调用的封装: 缓冲区+系统调用
库函数有缓冲区,系统调用没有缓冲区

Linux 学习记录20(IO篇)_第1张图片

4. 常用的函数接口的种类

  1. 标准IO: printf、scanf、puts、 gets、 getchar、 putchar; fopen、 fclose、 fprintf、 fscanf、fputs、fgets、fgetc、fputc、fread、fwrit。。。。
  2. 文件lO: open、close、read、write。。。

二、标准IO

1. 什么是FILE结构体

什么是FILE结构体

在Linux中,FILE结构体是一个用于管理文件I/O操作的结构体。它包含有关打开文件的信息,如文件描述符、缓冲区指针、读/写位置和错误状态等。在C语言中,FILE结构体通常以指针形式进行处理,用于访问文件。通过FILE结构体,可以进行文件的读写操作,以及控制文件的位置和状态等。在标准C库中,定义了一组用于处理文件I/O的函数,如fopen()、fclose()、fread()、fwrite()等,这些函数使用FILE结构体进行文件操作。

2. 如何找到FILE结构体

1. cd 到 /usr/include 目录下
2. 创建索引文件: ctags -R
3. 追代码: vi -t 函数/变量名
4. 使用: ctrl +],进行继续深层追代码
5. 返回上一级: ctrl +t
6. 在/usr/include 路径下: sudo ctags -R 生成索引文件 (tags)
7. 在当前目录下: vi -t FILE 追该名字的出处
struct _IO_FIFE{
char* _IO_read_end;
char* _IO_read_base;
}

3. 特殊的文件指针

1. 对于文件的操作,都需要使用文件指针来完成
2. 自定义文件指针: FILE*fp;
3. 系统提供的特殊文件指针: stdin(标准输入)、stdout (标准输出指针)、stderr (标准出错)

4. fopen的使用

头文件 :<stdio.h>
函数原型 :FILE *fopen(const char *pathname,const char *mode);
函数功能 :使用标准TO打开一个文件
参数1 :文件路径,字符串
参数2 :也是一个字符串,打开模式 r,r+,w,w+,a,a+
返回值 :打开成功返回文件地址,失败返回NULL,并置位错误码
输入参数 模式
r 只读模式,如果文件不存在,则打开失败,指针定位在文件开头
r+ 可读+可写,指针定位在文件开头
w 只写模式,如果文件不存在,则创建文件;如果文件已经存在,则清除文件内容,指针定位在文件开头
w+ 读写模式,如果文件不存在,则创建文件;如果文件已经存在,则清除文件内容,指针定位在文件开头
a 追加模式,如果文件不存在,则创建文件;如果文件已经存在,则在文件末尾追加内容,指针定位在文件末尾
a+ 追加模式,如果文件不存在,则创建文件;如果文件已经存在,则在文件末尾追加内容,读指针定位在文件开头,写指针定位在文件末尾,
fopen函数的使用>>

FILE* fp = NULL;

fp = fopen("./file01.txt","w");//第一个参数为文件的路径,第二个参数为文件的打开方式
//如果改路径下没有改文件则创建文件

/*不同的打开方式*/
//fp = fopen("./file01.txt","w+");
//fp = fopen("./file01.txt","r");
//fp = fopen("./file01.txt","r+");
//fp = fopen("./file01.txt","a");
//fp = fopen("./file01.txt","a+");

if(fp == NULL)
{//如果是读文件,如果文件不存在
	printf("Couldn't open file\r\n");
	return -1;
}
printf("file : %p\r\n",fp);

执行后可以看到文件夹下多创建了一个file01.txt文件

5. fclose的使用

头文件 :<stdio.h>
函数原型 :int fclose(FILE *stream);
函数功能 :关闭给定指针指向的文件
参数1 :要关闭的文件指针
返回值 :成功返回0。失败返回-1,并置位错误码
===========================================
	FILE* fp = NULL;
    fp = fopen("./file01.txt","r");//打开文件
    if(fp == NULL)
    {
        printf("Couldn't open file\r\n");
        return -1;
    }
    printf("file : %p\r\n",fp);

    if(fclose(fp)==0)//判断关闭文件是否关闭成功
    {
        printf("close file\r\n");
    }else if(fclose(fp)==-1)
    {
        printf("Couldn't close file\r\n");
    }

6. 关于错误码的问题

错误码

在文件I0或标准I0相关接口被调用是,如果出错了,操作系统会给应用程序返回一个错误码,一共有4096个,每一个代表不同的错误,错误码返回的是负数如下是部分错误码
Linux 学习记录20(IO篇)_第2张图片

errno为头文件以定义的全局变量,可以直接使用无需定义

错误码头文件 :#include <errno.h>
函数 :strerror(errno);
输入错误码
输出错误码对于的错误信息
=======================================================================
fp = fopen("./file02.txt","r");//该路径下没有此文件,并且以只读模式打开
if(fp == NULL)//因为打开失败更新了错误码
{
	printf("%s\r\n",strerror(errno));//打印错误码对应的错误
	return -1;
}
输出>>
No such file or directory
=======================================================================
函数 :perror(const* p);
输入信息
如:
perror("open file");
当错误码更新时,该函数执行效果>>
open file: No such file or directory

7. fgetc/fputc函数的使用

(1. fputc

函数原型 :int fputc(int c,FILE*stream);
功能 :从程序中向指定文件中输出一个字符/向文件在中输入一个字符
输入参数1 :被输出字符的ASCII码值/被写入文件字符的ASCII码值
输入参数2 :指定文件指针
返回值 :成功返回ascii值,失败返回EOF/-1
===========================================================
FILE* fp = NULL;
if((fp=fopen("./file01.txt","w")) == NULL)
{//判断文件是否打开成功
    perror("open file");
    return -1;
}
fputc('h',fp);//向指定文件内输入单个字符
fputc('e',fp);
fputc('l',fp);
fputc('l',fp); 
fputc('o',fp); 
fputc('\n',fp);
fclose(fp);
运行完成后使用cat命令在终端查看被写入的文件
>>cat file01.txt
终端输出>>可以看到文件内已经写入了hello
hello

(2. fgetc

函数原型 :int fgetc(FILE *stream);
功能 :从指定文件中读取一个字符到程序
输入参数1 :指定的文件指针
返回值 :成功返回ascii值,读取失败或文件结束返回EOF/-1
===========================================================
文件file01.txt内已保存字符串hello带换行

char ch = 0;
FILE* fp = NULL;
if((fp=fopen("./file01.txt","r")) == NULL)
{//判断文件是否打开成功
    perror("open file");
    return -1;
}
while ((ch=fgetc(fp)) != EOF)//直到文件读取失败或文件结束
{//循环读取文件中的字符并赋值输出
    printf("%c",ch);
}

8. fgets/fputs函数的使用

(1. stdout,stdin和stderr

stdout

stdout是一个Linux系统中的标准输出流,它指向屏幕或是其他输出设备。我们可以使用各种编程语言和命令行工具来将输出写入stdout,如echo命令。在Linux中,stdout有一个文件描述符(file descriptor)为1。

stdin

stdin代表标准输入流,是Linux系统中的一个预定义文件流。在Linux系统中,程序可以从stdin读取输入数据。stdin通常用于从终端(例如键盘)读取输入数据。当用户在终端上输入一些数据时,它们会被发送到stdin流中,程序可以从stdin中读取这些数据。

stderr

tderr是Linux中的一个特殊文件描述符,它代表标准错误流(Standard Error)。它用于将程序中产生的错误信息输出到屏幕或日志文件中。通常,若程序执行成功,其标准错误流不会有任何输出。当程序发生错误时,其标准错误流将输出相应的错误信息。

(2. fputs

函数原型 :int fputs(const char *s, FILE *stream);
功能 :将指定的字符串s,写入到给定的文件中
输入参数1 :要写入的文件字符串
输入参数1 :文件指针
返回值 :成功返回成功写入字符的个数(非负整数),读取失败或文件结束返回EOF/-1
===========================================================
FILE* fp1 = NULL;
if((fp1=fopen("./file01.txt","w")) == NULL)
{
    perror("open file");
    return -1;
}
fputs("asd\r\n",fp1);
fclose(fp1);
运行完成后使用cat命令在终端查看被写入的文件
>>cat file01.txt
终端输出>>可以看到文件内已经写入了asd
asd
===========================================================
fputs("asd\r\n",stdout);

(3. fgets

函数原型 :char *fgets(char*s. int size. FILE *stream);
功能 :从给定的文件stream中,读取至少小于size个字符,放入到给定字符数组s中
遇到换行或者EOF停止读取,换行符号也会被读取到s中,在全部读取结束后,会自定加一个"\0"
输入参数1 :要存放数据的字符数组
输入参数2 :读取的大小(读取的字符串实际长度为size-1)
输入参数3 :文件指针
返回值 :成功返回s数组,失败返回NULL
===========================================================
char str1_buff[255] = {0};
//从终端获取字符串
fgets(str1_buff, sizeof(str1_buff), stdin);
printf("%s",str1_buff);

三、缓冲区

1. 缓冲区的大小

1. 全缓存:跟自定义文件指针有关的缓冲区,其大小为4096字节
2. 行缓存:跟终端相关的操作使用的是行缓存(stdin、stdout),其大小为1024字节
3. 不缓存:跟标准出错有关的操作是不缓存(stde),其大小为0
int i = 0;
FILE* fp1 = NULL;
if((fp1=fopen("./file01.txt","w")) == NULL)
{
     perror("open file");
     return -1;
 }
printf("\r\n");
scanf("%d",&i);//输入任意值
printf("stdin行缓存:%ld\r\n",stdin->_IO_buf_end - stdin->_IO_buf_base);
printf("stdout行缓存:%ld\r\n",stdout->_IO_buf_end - stdout->_IO_buf_base);
printf("不缓存:%ld\r\n",stderr->_IO_buf_end - stderr->_IO_buf_base);
printf("文件全缓存:%ld\r\n",fp1->_IO_buf_end - fp1->_IO_buf_base);
输出>>
stdin行缓存:1024
stdout行缓存:1024
不缓存:0
文件全缓存:4096

2. 缓冲区的刷新时间

(1. 行缓存

  1. 遇到‘\n’会刷新行缓存
printf("hello\n");
while(1)
  1. 程序结束后会刷新行缓存
printf("hello");
  1. 当缓冲区进行切换时也会刷新缓存区
printf("hello");
int n;
scanf("%d",&n);
while(1);
  1. 当关闭文件指针时,也会刷新行缓存
printf("hello world");
fclose(stdout);//关闭文件指针
while(1);
  1. 手动刷新缓存区时,行缓存会进行刷新
printf("hello world");
fflush(stdout);//手动刷新缓存区
while(1);
  1. 当缓存区满了后,会自动刷新缓存区
for(int i=0; i<1025; i++)
{
	printf("%c","a');
}
while(1);

(1. 全缓存

  1. 全缓存遇到’\n’不会刷新缓冲区
  2. 程序结束后会刷新行缓存
  3. 当输入输出缓冲区发送切换时会刷新
fputc('A',fp);
fgetc(fp);
while(1);
  1. 当关闭文件时,会刷新全缓存
fputc('A',fp);
fclose(fp);
while(1);
  1. 手动刷新缓存区时,行缓存会进行刷新
  2. 当缓存区满了后,会自动刷新缓存区

思维导图

Linux 学习记录20(IO篇)_第3张图片

练习

1. 使用fgets统计一个文件的行号

#include 
#include 
#include 
#include 
#include 
int main(int argc, char const *argv[])
{
    int cnt = 0;
    char ch = 0;
    char str_buff[255] = {0};
    FILE* fp1 = NULL;
    if((fp1=fopen("./file01.txt","r")) == NULL)
    {
        perror("open file");
        return -1;
    }
    while(fgets(str_buff,3,fp1) != NULL)
    {
        if(str_buff[strlen(str_buff)-1] == '\n') cnt++;
    }
    fclose(fp1);
    printf("行数为 %d\r\n",cnt);
    return 0;
}

2. 使用fgets、fputs拷贝文件

#include 
#include 
#include 
#include 
#include 
int main(int argc, char const *argv[])
{
    int cnt = 0;
    char ch = 0;
    char str_buff[255] = {0};
    FILE* fp1 = NULL;
    FILE* fp2 = NULL;
    if((fp1=fopen("./file01.txt","r")) == NULL)
    {//打开要被拷贝的文件
        perror("open file");
        return -1;
    }
    if((fp2=fopen("./file02.txt","w")) == NULL)
    {//打开拷贝文件
        perror("open file");
        return -1;
    }
    while(fgets(str_buff,3,fp1) != NULL)
    {
        fputs(str_buff,fp2);
    }
    fclose(fp1);
    fclose(fp2);
    return 0;
}

你可能感兴趣的:(Linux学习记录,linux,学习,bash)