在了解标准IO之前,我们要先了解一些关键的概念。
此处的IO表示输入与输出;
目录
分类
基本分类
1. 文本文件(ascii文件):文件中的内容使用ascii码或者字符来表示,例如日常的txt文件
2.二进制文件:文件中存放二进制数据,例如我们经常打开的系统文件中有一些是看不懂的“乱码”。这些文件的内容是用二进制来记录的。
两个文件类型对于计算机来说在物理存储上没有区别(最终都会以二进制的形式处理),在逻辑上有所差别(文件的编码方式不同)
linux系统文件分类
-普通文件 -
-管道文件 p
-字符设备文件 c
-连接文件 l
-套接字文件 s
-块设备文件 b
-目录文件 d
可在linux终端上通过命令ls -l 查看当前目录下的各种文件类型和详细信息
ls -l
每一段的首字符就是该文件的类型表示。
lrwxrwxrwx 1 root root 7 8月 4 2021 bin -> usr/bin
drwxr-xr-x 4 root root 4096 6月 23 09:10 boot
drwxrwxr-x 2 root root 4096 8月 4 2021 cdrom
drwxr-xr-x 20 root root 4240 6月 17 09:05 dev
drwxr-xr-x 132 root root 12288 6月 22 13:48 etc
drwxr-xr-x 4 root root 4096 4月 29 14:15 home
lrwxrwxrwx 1 root root 7 8月 4 2021 lib -> usr/lib
lrwxrwxrwx 1 root root 9 8月 4 2021 lib32 -> usr/lib32
lrwxrwxrwx 1 root root 9 8月 4 2021 lib64 -> usr/lib64
lrwxrwxrwx 1 root root 10 8月 4 2021 libx32 -> usr/libx32
标准IO缓存分类
- 全缓存:文件的读写
- 刷新条件
- ffulsh刷新
- 程序结束
- 缓存区满
- 刷新条件
- 行缓存:标准输入与输出的缓存方式
- 刷新条件
- ffulsh刷新
- 程序结束
- 缓存区满
- 遇到'\n'
- 刷新条件
- 无缓存:直接输出(stderr)
标准IO:是由ANSI C标准提供的C语言标准函数库
文件流:表示数据像水流一样,不间断地进行传输,所有的I/O操作仅是简单的从程序移进或者移出,这种字节流,就称为流。
FILE *是文件指针类型,该类型是一个结构体,该结构体描述了文件相关的信息,每一个应用程序会默认定义三个文件流指针:stdin,stdout,stderr
- stdin 标准输入 在函数中使用可以从键盘接收输入的字符串
- stdout 标准输出
- stderr 标准错误
stdout与stderr都是将数据输出到终端上,不过stdout是行缓存,需要遇到换行时才进行输出。而stderr无缓存,会直接输出。例子如下,输出结果为“World !Hello”,各位不妨试试在“Hello”处加上一个“\n”或者在两个fprintf中间加上“fflush(stdout);”看看结果有什么不同
#include <stdio.h>
int main(int argc, char *argv[])
{
fprintf(stdout,"Hello ");
fprintf(stderr,"World!");
return 0;
}
man 手册使用简介
在IO阶段的学习中有大量的新函数需要学习,要时刻记住“有困难,找男人(man)”,man手册有三种打开方法
man 1 查看shell命令
man 2 查看系统调用
man 3 查看c标准库
文件基本操作:
在有了一些基本了解之后就来到了基本操作函数学习。
1.打开---------fopen()
FILE * fopen(const char * path,const char * mode);
参数path字符串包含欲打开的文件路径及文件名
参数mode字符串则代表着流形态
mode有下列几种形态字符串:
r 只读,不会创建新文件,默认从开头进行读取
r+ 读写,不会创建新文件,默认从开头进行读取
w 只写,会创建新文件,默认从头写入,清空原文内容
w+ 读写,会创建新文件,有则清空原文件内容再开始写入。
a 只写,会创建新文件、文件不会清空、会以追加的方式写入内容
a+ 读写,会创建新文件、文件不会清空、会以追加的方式写入内容
b 以二进制流方式,需要与前面相组合使用 "rb"此处的组合不必在意先后顺序,怎么好看怎么来
返回值:NULL:表示错误返回
正确返回文件流指针:该指针指向一个文件,后续可以直接使用该指针进行间接文件操作
使用fopen一定要进行错误判断,以防出现问题,例子如下:
假设当前目录下没有“1.txt”文件,此时有以下程序
int main()
{
FILE *fp=fopen("1.txt","r");
printf("end of file\n");
return 0;
}
此时终端正常返回end of file,但是程序已经出现错误。
因为当前目录下不存在1.txt文件,而“r”权限不会创建新文件,所以此处必定有错误
重新添加错误判断以后
int main()
{
FILE *fp=fopen("1.txt","r");
if(NULL == fp)
{
printf("fopen failed\n");
return -1;
}
printf("end of file\n");
return 0;
}
此时返回fopen failed,因为此时路径中根本没有1.txt
2.读取----------fread()等等.....
- int fgetc(FIEL*stream) :从指定的文件中读取一个字符,并且将字符返回
{
stream:文件流指针,上文fopen中创建的fp;
返回值:成功fgetc会返回读取到的无符号字符;
失败或者到达文件末尾返回“EOF”
}
此处有一个问题:为什么返回的是字符返回值却使用int类型呢?因为在使用char类型时fgetc读取数据的时候可能会遇到二进制换算值为255的符号,例如一张图片中,代表像素颜色深浅的数据有0到255的范围,255在char类型中可能会被认为是-1,而返回值为-1可能会导致某些程序中止。所以选用int类型,int类型的-1为0xfffffffff相对于char类型的0xff来说数据范围增大很多,几乎不可能遇见这个大小的符号。(此处可能有些表述不清晰,望见谅)
- char *fgets(char *s,int size,FILE *stream);从指定的文件中读取一行的数据遇到'\n'结束
size:想要读取一行文件内容的字节数
1. 当size的值小于等于文件中的一行数据大小时,显示读取size-1个数据,最后会默认添加一个'\0'
2. 当size-1的值大于文件中的一行数据大小时,遇到'\n'正常结束
3.两种情况都必须以'\0'为结束标志
s:数据首地址
**'\n'的ascii码为10,当fgets遇到10的字符时就会自动停止读取,在添加一个'\0'之后退出。此操作可能会导致文件内容出现丢失,所以不能将fgets用在文本文件(.txt)之外的文件读取。 - size_t fread(void *ptr,size_t size,size_t nmemb,FILE *stream);
支持任意类型的以及任意数量的数据读取
ptr:数据首地址
size:每一个数据的字节大小 eg:读取整数数据 size = sizeof(int)
nmemb:想要读取的数据个数
stream:文件流指针返回值:错误或者到达文件末尾:返回0或者比nmemb小的整数
正确:返回读取数据的个数
判断错误或者文件末尾情况有两个函数
feof():判断是否达到文件末尾
用法:if(foef(fp) != 0)
ferror():判断文件操作是否出错
用法:if(ferror(fp) != 0)
3.写入 fwrite()等等
- int fputc(int ch,FILE*stream) 一次写入一个字符
返回值:错误返回EOF
正确返回写入的字符
- int fputs(const char *s,FILE *stream)
向文件写入一串数据,s表示数据的首地址
错误返回EOP 正确返回非负数 - size_t fwrite(const void *ptr,size_t size,size nmemb,FILE *stream);
返回值 :错误 :0或者小于nmemb的数
正确:返回成功写入的数据个数
4.关闭 fclose()
int fclose(FILE *stream)
正常关闭返回0;否则返回EOF
一.清空相关的缓冲区
二.释放内存
其他标准IO介绍
fseek()
可以修改文件读写定位指针指向的位置
int fseek(FILE *stream, long offset, int whence);
offset:偏移量,可以为负数;
whence:
SEEK_SET:回到文件开头位置;
SEEK_CUR:在当前位置;
SEEK_END:转移至文件末尾;
返回值:成功0;失败-1.
ftell()
返回当前文件流指针的位置,通常与fseek(先移动到文件尾)一起使用来计算文件的大小
long ftell(FILE *stream);
rewind()
将文件流指针返回文件的开头,效果等同于,fseek(stream,0,SEEK_SET);
void rewind(FILE *stream);
fprintf()
int fprintf(FILE *stream, const char *format, ...);
将格式化的字符串写入到指定的文件当中
stream文件流指针;
format:格式控制字符串
....可变参数
sprintf()格式化字符串函数
int sprintf(char *str, const char *format, ...);
将最多大小的字节(包括终止的空字节('\0'))写入str。
例子:
//每次调用都往文件里面存一组数据
int main(int argc, char *argv[])
{
int tmp = 35;
int hum = 56;
int light = 1026;
char buf[1024] = {0};
sprintf(buf,"tmp:%d,hum:%d light:%d\n",tmp,hum,light);
//将数据存到buf中
FILE *fp1 = fopen("1.txt","a");
if(NULL == fp1)
{
perror("fopen fp1");
return -1;
}
if(EOF== fputs(buf,fp1));
return -1;
fclose(fp1);
return 0;
}
希望这些对你有所帮助,如文章有错误之处,欢迎斧正.