IO与进线程

本文详细介绍了Linux中的IO机制,包括标准IO和文件IO的区别、缓冲的概念、文件打开与关闭的函数以及文件定位操作。此外,还探讨了Linux文件系统、文件描述符和进程间通信的方式,如管道、信号、消息队列、共享内存和信号量。最后,文章提到了进程和线程的基本概念,线程的创建、同步与互斥操作。
摘要由CSDN通过智能技术生成

一、系统调用的概念

​ OS负责管理和分配所有的计算机资源同时保护计算机硬件,为了更好地服务于应用程序,OS提供了一组特殊的接口,即系统调用。通过这组接口,用户程序可以使用OS内核提供的各种功能,如内存分配、进程创建、线程创建、进程间通信及线程间通信等。

二、Linux文件类型拾遗

​ Linux系统中,一切皆文件,操作设备时实际上是对文件进行操作。

Linux文件类型:

​ -:普通文件,linux中,如一般文件的文件类型为ASCII码文本文件,但a.out是elf文件

​ d:目录文件

​ b:块设备文件

​ c:字符设备文件

​ l:链接文件(软链接)

​ p:管道文件

​ s:套接字文件

三、Linux标准IO

3.1 流的概念

​ 标准IO的核心是流,当使用标准IO打开一个文件时,会创建一个FILE结构体用来描述该文件,通常称该FILE结构体为流,标准IO相关的函数都是基于流进行的操作。

3.2 缓冲的概念

标准IO又叫带缓冲的IO,流的缓冲类型主要有以下三种:

  • 全缓冲

    指的是系统在填满标准IO缓冲区之后才进行实际的IO操作。对于存放在磁盘上的普通文件用标准IO打开是默认是采用全缓冲的形式。当缓冲区满或者执行fflush函数时,才会进行实际的IO操作

  • 行缓冲

    标准IO在输入和输出中遇到换行符时执行实际的IO操作。如控制台终端通常使用的是行缓冲,也就是说标准输入流(stdin)和标准输出流(stdout)使用的是行缓冲

  • 无缓冲

    不对IO操作进行缓冲,即在对流的读写时会立即操作实际的文件。如标准出错处理流(stderr)是不带缓冲的,出错信息会立即显示在终端上,不管输出内容是否有\n符(换行符)。

3.3 文件打开与关闭(带缓冲)

​ 使用标准IO打开文件的函数有fopen()、fdopen()和freopen()。可以采用不同的模式打开文件,成功则返回一个文件流指针(FILE*),通过该文件流指针对文件进行读写操作。

​ 关闭文件时使用fclose()函数,该函数将流的缓冲区内的全部数据写入文件中并释放相关资源。

3.3.1 fopen()函数
头文件:
	#include <stdio.h>
函数原型:
	FILE* fopen(const char *path, const char *mode);
功能:
    以标准IO的方式打开文件,成功返回一个指向该文件的文件流指针。
参数:
    path: 要打开的文件的路径及文件名;
	mode: 文件打开方式;
返回值:
    成功返回一个指向该文件的流指针(FILE*),失败返回NULL;
mode取值说明:
    r或rb: 以只读的方式打开文件(文件必须存在);
	r+或r+b: 以可读可写的方式打开文件(文件必须存在);
	w或wb: 以只写方式打开文件,若文件存在会清空文件内容,文件不存在会创建新文件;
	a或ab: 以追加且只写的方式打开文件,若文件不存在会创建该文件,文件存在会从文件末尾开始增加写入的数据;
	a+或a+b: 以追加且读写的方式打开文件,若文件不存在会创建该文件,文件存在会从文件末尾开始增加写入的数据;

fdopen函数

函数原型:
	FILE* fdopen(int fd, const char *mode);
功能:
    打开已存在的文件描述符,使标准I/O流与该文件相结合。主要用于fopen不能打开的特殊文件(如管道和网路通信等),这时必须先调用设备专用函数以获得一个文件描述符,然后在用fdopen使一个标准I/O与该文件描述符相结合。

freopen函数

函数原型:
    FILE* freopen(const char *pathname, const char *mode, FILE *stream);
功能:
    在指定的流上打开一个指定的文件,如若该流已经打开,则先关闭该流。若该流已经定向,则使用freopen清除该定向。简单的说可以利用freopen函数重定向。此函数一般用于将一个指定的文件代开为一个预定义的流:stdout,stdin,stderr。可以利用freopen将标准流冲定向。不要在程序的一开始就使用freopen。因为标准输出流(标准输入流和标准错误输出流)是常量,是不可再分配文件描述符的。
3.3.2 fclose()函数
头文件:
    #include <stdio.h>
函数原型:
	int fclose(FILE *stream);
功能:
    关闭一个文件,将流的缓冲区内的全部数据写入文件中并释放相关资源。
参数:
    stream: 想要关闭的文件流指针
返回值:
    成功返回0,失败返回EOF,并且设置错误号。

3.4 文件读写(带缓冲)

3.4.1 字符输入函数

​ getc()和fgetc()函数从指定的流中读取一个字符,getchar()函数从stdin中读取一个字符。

头文件:
    #include <stdio.h>
函数原型:
    int getc(FILE* stream);
	int fgetc(FILE* stream);
	int getchar(void);
函数参数:
    stream: 要输入的文件流
返回值:
    成功返回读取到的字符,失败返回EOF
3.4.2 字符输出函数

​ putc()和fputc()函数向指定流中输出一个字符,putchar()函数向stdout输出一个字符。

头文件:
    #include <stdio.h>
函数原型:
    int putc(int c, FILE *stream);
	int fputc(int c, FILE *stream);
	int putchar(int c);
函数参数:
    c: 要输出的字符
    stream: 文件流
返回值:
    成功返回输出的字符,失败返回EOF
3.4.3 行输入函数

​ gets()函数从stdin中读取一个字符串(以\n结尾)并存储到自定义的缓冲区中,并且将\n从输入缓冲区一并读走。

​ fgets()函数从指定流中读取指定字节,若遇见\n时会提前返回。

头文件:
    #include <stdio.h>
函数原型:
    char* gets(char *s);
	char* fgets(char *s, int size, FILE *stream);
函数参数:
    s: 用户自定义的缓冲区(字符数组)
    size: 将要读取的字节数
    stream: 指定的流
返回值:
    成功返回读取到的字符串,失败返回NULL
3.4.4 行输出函数

​ puts()函数将指定的字符串输出到stdout上,fputs()函数将指定的字符串输出到指定的流中。

头文件:
    #include <stdio.h>
函数原型:
    int puts(const char *s);
	int fputs(const char *s, FILE *stream);
函数参数:
    s: 指定要输出的字符串的首地址
    stream: 要输出的流
返回值:
    成功返回一个大于0的数,失败返回EOF
3.4.5 文件读写函数(带缓冲)

fread()函数

​ 从指定的文件流 读取指定字节数(size * nmemb)到用户自定义缓冲区buf中。

头文件:
    #include <stdio.h>
函数原型:
    size_t fread(void *buf, size_t size, size_t nmemb, FILE* stream);
函数参数:
    buf: 存放读出记录的缓冲区
    size: 读取的每个记录的大小
    nmemb: 读取的记录个数
   	stream: 要读取的文件流
返回值:
    成功返回实际读到的nmemb个数,失败返回EOF

fwrite()函数

​ 将用户自定义缓冲区中数据写入指定字节数(size * nmemb)到指定文件流中

头文件:
    #include <stdio.h>
函数原型:
    size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream);
函数参数:
    buf: 存放写入记录的缓冲区
    size: 想要写入的每个记录的大小
    nmemb: 写入的记录数
    stream: 要写入的文件流
返回值:
    成功返回实际写入的nmemb个数,失败返回EOF
3.4.6 文件流的定位

​ 每个打开的文件流内部都有一个当前读写位置,当流打开时当前读写位置为0,表示文件开始位置。每读写一次,当前文件位置根据实际读写大小自动增加。可以认为对流进行定位。

fseek()函数

头文件:
    #include <stdio.h>
函数原型:
    int fseek(FILE *stream, long offset, int whence);
函数参数:
    stream: 要定位的文件流
    offset: 相对于基准值的偏移量
    whence: 基准值
        SEEK_SET:文件的起始位置
		SEEK_END:文件的结束位置
		SEEK_CUR:文件当前读写位置
返回值:
   	成功返回0,失败返回EOF

ftell()函数

​ ftell()函数返回当前读写位置。

头文件:
    #include <stdio.h>
函数原型:
    long ftell(FILE *stream);
函数参数:
    stream: 要定位的文件流
返回值:
    成功返回当前读写位置,失败返回EOF

rewind()函数

​ rewind()函数可以将指定文件流的读写位置重新指向文件开始位置。

头文件:
    #include <stdio.h>
函数原型:
    void rewind(FILE *stream);
参数:
    stream: 文件流指针
返回值:
    无返回值
3.4.7 格式化输入输出函数

​ 格式化输入函数:scanf()、fscanf()、sscanf()

头文件:
    #include <stdio.h>
函数原型:
    int scanf(const char *format, ....);
	int fscanf(FILE *fp, const char *format, ....);
	int sscanf(char *buf, const char *format, ....);
函数参数:
    format: 输入格式
    fp: 输入的流
    buf: 输入的缓冲区
返回值:
    成功返回正确按指定格式输入变量的个数,失败返回EOF

​ 格式化输出函数:printf()、fprintf()、sprintf()

头文件:
    #include <stdio.h>
函数原型:
    int printf(const char *format, ....);
	int fprintf(FILE *fp, const char *format, ....);
	int sprintf(char *buf, const char *format, ....);
函数参数:
    format: 输出格式控制
    fp: 接收输出的流
    buf: 接收输出的缓冲区
返回值:
    成功返回输出字符数,失败返回EOF
3.4.8 练习

使用标准IO实现文件复制功能

#include <stdio.h>

#define SIZE 512

int main(int argc, char *argv[])
{
   
    if(argc < 3)
    {
   
        printf("Usage:%s <src_file> <dest_file>\n",argv[0]);
        return -1;
    }

    char buf[SIZE] = {
   0};
    FILE *fps = fopen(argv[1],"r");//只读方式打开文件
    if(NULL == fps)
    {
   
        perror("fopen src file");//打印errno对应的错误信息
        return -1;
    }

    FILE *fpd = fopen(argv[2],"w");//只写方式打开文件
    if(
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值