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;
}