标准IO.

本文详细介绍了Linux中的文件类型(如块设备文件、字符设备文件等),以及标准IO和文件IO的区别,涵盖了fopen、fclose、getchar等函数的用法和原理。重点讨论了从文件读写数据的流程和特殊的文件流,还涉及了标准IO缓存机制的设置。
摘要由CSDN通过智能技术生成

IO  input  output
I: 键盘是标准输入设备 ====》默认输入就是指键盘  /dev/input
O: 显示器是标准输出设备 ==》默认输出就是指显示器
 

linux中一切都是文件。文件用来存储数据(数据,指令)。

IO输入输出,操作对象是文件

用 命令  ll 来查看

文件权限用一种特殊的符号表示法来描述,通常可以看到类似rwxrwxrwx这样的权限字符串,以及它们对应的数字表示法111111111。

这些符号和数字分别对应着文件或目录的读、写、执行权限,以及对这些权限的拥有者(用户)、所属组和其他用户的不同权限设定。

一、文件权限符号

•r:表示“读”权限,即有权限读取文件的内容或列出目录的内容。

•w:表示“写”权限,即有权限修改文件的内容或在目录中创建和删除文件。

•x:表示“执行”权限,对于文件意味着可以被执行,对于目录意味着可以进入该目录。

每种权限(读、写、执行)都可以用一个二进制位表示,而每个用户类别(用户、组、其他)的权限可以用三个二进制位表示,这样就有了一个八进制数。

具体如下:

•r对应1(二进制)

•w对应2(二进制)

•x对应4(二进制)

所以,rwx的权限用二进制表示就是1+2+4=7(十进制),rw-(无执行权限)就是1+2=3(十进制),以此类推。 

示例:

•rwx对应111(二进制),即7(十进制)。

•r-x对应101(二进制),即5(十进制)。

所以,完整的权限字符串rwxrwxrwx可以表示为数字777,而rwxr-xr-x可以表示为数字755。

777表示完全开放的权限,即所有人都有读、写、执行权限,这在生产环境中通常被认为是不安全的,除非有特别的需求。

初始时,文件默认权限:

rw_  rw_   rw_    662

原始权限为 mode,则最终建立文件的权限为:mode & ~umask。

umask带表被拿掉的权限,另外文件默认没有执行权限.

设 umask 为 002,则新建立的文件默认权限是什么()

rw-rw-r--

修改文件权限的命令  chmod +r/w/x 文件名

chmod 777  filename


二、Linux文件类型: b,c,d,-,l,s,p


        b   block       块设备文件
                        按块扫描设备信息的文件
                        存储设备

        c   character   字符设备文件
                        按字符扫描设备信息的文件 

        d   directory   目录文件 
                        存放文件

        -               普通文件 
                        存放数据
                        图片、音视频、压缩包、文本文件

        l   link        链接文件 
                        快捷方式

        s   socket      套接字文件
                        用来套接字通信

        p   pipe        管道文件
                        用来进程间通信


普通文件:
        1.ASCII码文件
            文件中所有的字符均为能够在终端上显示的字符
            文本文件、程序.c 
        2.二进制文件
            文件中存放数据的二进制形式
            图片、音视频、压缩包 

        ASCII码文件是特殊的二进制文件

标准IO、文件IO
        标准IO是库函数
        文件IO是系统调用

        系统调用:功能强大,应对复杂场景不够灵活
        库函数:针对系统调用的封装,使用方便灵活

        标准IO可以在Windows或者Linux平台使用
        文件IO只能在Linux系统平台使用
 

三、标准IO:

ANSI C 设计的一组用文件IO 封装的操作库函数
头文件: stdio.h  ==》标准输入输出头文件
         /usr/include/stdio.h

<>   是系统库函数,默认路径在/usr/include/
eg : ====》stdio.h  ===>stdio.c==>libc.so ==>/usr/lib     (so 动态库)
""   是用户自定义函数,默认是当前路径
eg : ===>xxx.h  ===>xxx.c


        getchar putchar scanf printf gets puts  -> 标准IO

        #include <stdio.h>      

        fopen/fclose 
        fgetc/fputc 
        fgets/fputs
        fscanf/fprintf
        fread/fwrite 
        fseek/rewind/ftell 

从文件中读写数据的流程:
        打开文件 -> 读写文件 -> 关闭文件

      fopen                   fclose
                    fgetc/fputc     单个字符的读写
                    fgets/fputs     字符串的读写
                    fscanf/fprintf  格式化字符串的读写
                    fread/fwrite    二进制文件的读写

  四、函数接口:


        1.fopen


          FILE *fopen(const char *pathname, const char *mode);
          功能:
            打开pathname对应的文件并与其建立一个文件流
          参数:
            pathname:要打开文件路径的字符串
            mode:
                r       只读            文件不存在报错,文件存在只读打开
                r+      读写            文件不存在报错,文件存在读写打开
                w       只写            文件不存在创建,文件存在将文件内容清空,只写打开
                w+      写读            文件不存在创建,文件存在将文件内容清空,写读打开
                a       追加只写        文件不存在创建,文件存在追加只写打开
                a+      追加写读        文件不存在创建,文件存在追加写读打开
          返回值:
              成功返回打开的文件流指针
              失败返回NULL

2.fclose 


          int fclose(FILE *stream);
          功能:
            关闭文件,释放文件流指针
          参数:
            stream:文件流指针
          返回值:
            成功返回0 
            失败返回EOF(-1)

#include <stdio.h>

int main(void)
{
	FILE *fp = NULL;

	fp = fopen("a.txt", "r");
	if (NULL == fp)
	{
		perror("fail fopen");
		return -1;
	}

	printf("fopen success!\n");

	fclose(fp);

	return 0;
}

 3. fputc


        int fputc(int c, FILE *stream);
功能:
        向流中写入一个字符
参数:
        c:要写入的字符
        stream:文件流指针
返回值:
        成功返回写入的字符ASCII码值
        失败返回EOF

4.fgetc


        int fgetc(FILE *stream);
功能:
        从流中读取一个字符
参数:
        stream:文件流指针
返回值:
        成功返回读到字符的ASCII码值
        读到文件末尾返回EOF

用fgetc和fputc实现文件的拷贝

#include <stdio.h>

int main(void)
{
	FILE *src = fopen("1.txt","r");
	FILE *dst = fopen("2.txt","w");
	if(	NULL == src || NULL == dst)
	{
		printf("fopen is error\n");
		return 1;
	}

	char c = 0;
	while(1)
	{
		c = fgetc(src);
		if(EOF == c)
		{
			break;
		}
		fputc(c,dst);
	}

	fclose(src);
	fclose(dst);

	return 0;
}

 5.文件流:


        1.具有方向性(读写)
        2.具有连续性
        3.具有顺序性

        句柄:操作对象的一个抽象

特殊的三个文件流:
        stdin   标准输入流          从终端读取数据
        stdout  标准输出流          向终端打印数据
        stderr  标准出错流          向终端打印数据 

        getchar、scanf、gets 通过stdin来读取终端数据
        putchar、printf、puts通过stdout来向终端输出数据
        perror通过stderr来向终端输出数据

#include <stdio.h>

int main(void)
{
	fclose(stdin);
	fclose(stdout);
	fclose(stderr);
	getchar();
	
	printf("hello world!\n");
	perror("hello world!\n");

	return 0;
}

6.fgets

fgets()函数用于从流中读取一行文本,最多读取n-1个字符,并在遇到换行符、EOF(文件结束)或其他错误时停止读取。读取的字符串会被自动添加一个空字符\0作为字符串的终止符。

char *fgets(char *str, int n, FILE *stream);

参数

•str:指向一个字符数组的指针,用于存储读取的字符串。

•n:要读取的最大字符数(不包括终止符\0)。(n的大小最好比要读的一行文本刚好大一点。)

•stream:指向一个打开的文件流的指针。

返回值        fgets()函数成功时返回str,失败时返回NULL。

#include <stdio.h>
int main(void)
{
	FILE *fp = fopen("/etc/passwd","r");

	if(NULL == fp)
	{
		printf("fopen error\n");
		return 1;
	}
	while(1)
	{
		char buf[512] = {0};
		char *p = fgets(buf,sizeof(buf),fp);
		if(NULL == p)
		{
			break;
		}
		printf("%s",buf);
	}
	fclose(fp);
	return 0;

}

7.fputs() 

fputs()函数用于向流中写入一个字符串,直到遇到空字符\0为止。

int fputs(const char *restrict str, FILE *restrict stream);

参数

•str:指向一个字符串的指针,要写入的字符串。

•stream:指向一个打开的文件流的指针。

返回值        fputs()函数在成功时返回EOF以外的值,在发生错误时返回EOF。

#include<stdio.h>
int main(void)
{
	FILE * fp = fopen("1.txt","w");
	if(NULL == fp)
	{
		printf("fpopen is error\n");
		return 1;
	}
	char buff[] = "hello";
	fputs(buff,fp);
	fputs(",xiao ming1",fp);

	fclose(fp);

	return 0;

}

用fgets和fputs实现文本文件的拷贝

#include <stdio.h>
// ./a.out /etc/passwd 222
int main(int argc,char *argv[])
{
//	FILE *src = fopen("/etc/passwd","r");
//	FILE *dst = fopen("2.txt","w");

	if(argc < 3)
	{
		printf("usage: ./ a.out srcfile dstfile \n");
		return 1;
	}
	FILE *src = fopen(argv[1],"r");   // 这里的argv不能带 “” 因为argv 是一个指针 
	FILE *dst = fopen(argv[2], "w");
	
	if(	NULL == src || NULL == dst)
	{
		printf("fopen is error\n");
		return 1;
	}

	while(1)
	{
		char buf[128] = {0};

		char *p = fgets(buf,sizeof(buf),src);
		if(NULL == p)
		{
			break;
		}
		fputs(buf,dst);
	}

	fclose(src);
	fclose(dst);

	return 0;
}

拷贝之后  可以用vimdiff  filename1 filename2 命令 来查看两个文件一致不一致 。

fgets和fputs 不能拷贝照片 , 为什么?

它们内部对输入输出进行了特殊处理,比如 fgets 会在遇到换行符或达到缓冲区大小限制时停止读取,而 fputs 则会自动添加一个换行符(如果原字符串末尾没有的话),这在处理二进制数据如图片、音频或视频文件时会产生问题。


二进制文件的读写: fread()/fwrite()

不常用 ,常用的是 write()和read()。

8.fseek

int fseek(FILE *stream, long offset, int whence);

功能:将stream流文件中的文件指针从whence位置开始偏移offset字节的长度。
参数:stream  要移动文件指针的目标文件流对象。注意:不支持设备文件,一般用于普通文件。
           offset  要在文件内偏移的距离,单位字节。
             如果值为整数,则向文件末尾偏移
                  值为负数,则向文件开头偏移
  whence  偏移的起始位置,由系统定义的三个宏开始。
        SEEK_SET  文件的开头位置 
        SEEK_CUR  文件的当前位置
        SEEK_END  文件的末尾位置
返回值:
        成功: 返回 0
        失败:  -1;

9.ftell

它的主要作用是确定与以二进制模式或文本模式(在区分这两种模式的系统上)打开的流相关联的输入/输出指针的当前位置(以字节为单位)。
 

long ftell(FILE *stream);

ftell 返回流的当前位置作为一个 long 类型的整数值。如果发生错误,则返回 LONG_MIN(可表示的最小 long 值),并且设置全局变量 errno 来指示错误。

统计文件所占字节数:

#include<stdio.h>
int main(int argc, const char *argv[])
{
	if(argc !=2)
	{
		printf("enter error");
		return -1;
	}

	FILE *fp = fopen(argv[1],"r");
	if(NULL == fp)
	{
		printf("fopen is error\n");
		return 1;
	}

	fseek(fp,0,SEEK_END);
	long size = ftell(fp);
	printf("size = %ld\n",size);

	fclose(fp);

	return 0;
}

 10.rewind

void rewind(FILE *stream);

 用于将文件流的读写位置指针重置到文件的开头。

五、标准IO缓存

缓存分为3类:
            1.全缓存  4k
                缓存区满刷新
                
                刷新条件:
                    1.缓存区存满刷新(全缓存大小:4096)
                    2.fflush函数强制刷新
                    3.程序结束/fclose刷新

                与文件建立的缓存

            2.行缓存  1k
                遇到\n刷新  

                刷新条件:
                    1.缓存区存满刷新(行缓存大小:1024)
                    2.遇到\n刷新 
                    3.fflush函数强制刷新
                    4.程序结束/fclose刷新

                与终端建立的缓存            stdin   stdout 

            3.不缓存
                直接刷新

                缓存区大小 0k               stderr

                人机交互、界面控制、出错处理

fflush()

它的主要作用是清除(刷新)与特定流相关联的输出缓冲区,如果参数设置为 NULL 则会刷新所有流。

int fflush(FILE *stream);

            4.setvbuf
              int setvbuf(FILE *stream, char *buf, int mode, size_t size);
              功能:
                改变一个流的缓存类型
              参数:
                stream:文件流指针
                buf:指定缓存空间的首地址
                mode:
                    _IONBF  不缓存
                    _IOLBF  行缓存
                    _IOFBF  全缓存
                size:
                    设定缓存区的大小
              返回值:
                成功返回0 
                失败返回非0 

#include <stdio.h>

int main(void)
{
	char tmpbuff[4096] = {0};

//	setvbuf(stdout, NULL, _IONBF, 0);		//设置成不缓存
//	setvbuf(stdout, tmpbuff, _IOFBF, 4096);	//设置成全缓存
	setvbuf(stdout, tmpbuff, _IOLBF, 1024);	//设置成行缓存

	printf("hello world\n");
	
	while (1)
	{
		
	}

	return 0;
}

vim 编辑器对齐操作

选中代码 然后按 =  

练习:1.统计一个本本文件中 字母a~z 的个数

#include <stdio.h>
#include <string.h>

int do_count(char *buf,int arr[])
{
	while(*buf) // 遇到字符串末尾的 /0 时跳出循环
	{
		char c = *buf;
		arr[c]++;
		buf++;
	}

	return 0;
}
int main(void)
{
	FILE * fp = fopen ("/etc/passwd" , "r");
	if(NULL == fp )
	{
		printf("fopen error\n");
		return -1;
	}

	int array[256] = {0};
	while(1)
	{
		char buf[512] = {0};
		if(NULL == fgets(buf,sizeof(buf),fp))
		{
			break;
		}
		do_count(buf,array);
	}
	fclose(fp);
	
	int i = 0;
	for(i = 97;i<=122;++i)
	{
		printf(" %c have %d\n",i,array[i]);
	}

	return 0;
}

vim t.c -> vim编辑器:main -> tab 健补全

    int main(int argc,char *argv[]){
    return 0;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值