Linux 分层(内核架构)
标准IO
标准IO只能操作普通文件。
文件类型:
b: 块设备文件
c: 字符设备文件
d: 目录文件
-: 普通文件
l: 链接文件
s: 套接字文件
p: 管道文件
概念
在 C库 中定义的一组用于 输入输出的函数。
特点
1、通过缓冲机制减少系统调用。
2、围绕流进行操作,流用 FILE * 表示。
3、标准IO 默认打开了3个流,stdin(标准输入)、stdout(标准输出)、stderr(标准错误)。
ctags 索引:
1)vi -t <要追踪的内容>,可以查找宏、数据类型等;
2)输入前面序号,回车;
3)继续追踪:将光标定位到要追踪的内容上,Ctrl + ]
4)回退:Ctrl + T
缓冲区
分类
1、全缓冲:跟文件相关
全缓冲区刷新条件:
① : 程序正常退出
② : 缓冲区满刷新
③ : 强制刷新 int fflush(FILE *stream);
2、行缓冲:跟终端相关
行缓冲区刷新条件:
① : \n
② : 程序正常退出
略。
③ : 缓冲区满刷新
见下面“写满缓冲区”。
④ : 强制刷新 int fflush(FILE *stream);
3、不缓冲:没有缓冲区,标准错误
测试行缓冲区大小:
1、写满缓冲区
缓冲区满则全部释放,故缓冲区大小 = 128 * 8bytes = 1024B = 1KB
2、stdout->_IO_buf_end 减去 stdout->_IO_buf_base
函数接口
打开文件(fopen)、perror
FILE *fopen(const char *path, const char *mode);
功能:打开文件
参数:
path:打开的文件
mode:打开的方式
r/rb: 只读,当文件不存在时报错,文件流定位到文件开头
r+/r+b:可读可写,当文件不存在时报错,文件流定位到文件开头
w/wb: 只写,文件不存在创建,存在清空重写
w+/w+b:可读可写,文件不存在创建,存在清空重写
a/ab: 追加(在末尾写),文件不存在创建,存在追加,文件流定位到文件末尾
a+/a+b:读和追加, 文件不存在创建,存在追加, 读文件流定位到文件开头,写文件流定位到文件末尾
注:当以 a 的方式打开文件时,写只能在末尾进行追加,
定位操作无法改变写的位置,但是可以改变读的位置
返回值:成功:文件流
失败:NULL,并且会设置错误码
void perror(const char *s);
功能:根据errno值打印对应的错误信息
参数:
s:提示语句
返回值:空
关闭文件(fclose)
int fclose(FILE* stream);
功能:关闭文件
参数:stream:文件流
读写操作
每次读写一个字符(fgetc / fputc)
int fgetc(FILE * stream);
功能:从文件中读取一个字符
参数:stream:文件流
返回值:成功:读到的字符
失败或读到文件末尾:EOF(-1)
int fputc(int c, FILE * stream);
功能:向文件中写入一个字符
参数:c:要写的字符
stream:文件流
返回值:成功:写的字符的ASCII
失败:EOF
// 实现 cat 功能
#include <stdio.h>
int main(int argc, char const *argv[])
{
FILE *p = fopen("./test.txt", "r"); // 若从终端读入路径,"./test.txt" --> argv[1]
if (p == NULL){
perror("Failed:");
return -1;
}
char ch;
while (1) // while ((ch = fgetc(p)) != EOF) {fputc(ch, stdout);}
{
ch = fgetc(p);
if (feof(p)) // if (ch == EOF)
break;
else // 可以省略
fputc(ch, stdout);
}
putchar(10);
fclose(p);
return 0;
}
若只允许从终端输入两个参数,则将下图的代码添加在main函数内最前面。
feof、ferror
int feof(FILE * stream);
功能:判断文件有没有到结尾
返回:到达文件末尾,返回非零值
int ferror(FILE * stream);
功能:检测文件有没有出错
返回:文件出错,返回非零值
每次读写一串字符(fgets / fputs)
char * fgets(char *s, int size, FILE * stream);
功能:从文件中每次读取一行字符串
参数:s:存放字符串的地址
size:一次读取的字符个数
stream:文件流
返回值:成功:s的地址
失败或读到文件末尾:NULL
特性:每次实际读取的字符个数为size-1个,会在末尾自动添加\0
每次读一行,遇到 \n 后不再继续读下一行
int fputs(const char *s, FILE *stream);
fputs() writes the strings to stream, without its terminating null byte ('\0').
fputs() return a nonnegative number on success, or EOF on error.
实现“wc -l 文件名”功能
// 若最后空行个数 n>1,只记录 n-1 行
#include <stdio.h>
int main(int argc, char const *argv[])
{
if (argc != 2){
printf("Please input %s <filename>.", argv[0]);
return -1;
}
FILE *p = fopen(argv[1], "r");
char buf[1024]; // 每次获取字符的长度必须足够大(容纳一整行)才可以,不建议此法
char *q; // 并不需要定义q
int count = 0;
while ((q = fgets(buf, 1024, p)) != NULL){
count++; // while (fgets(buf, 1024, p) != NULL) 即可
} // while (fgets(buf, 1024, p)) 即可
printf("%d\n", count);
return 0;
}
(计算 ‘\n’ 的个数:)
实现“head -n 文件名”功能
#include <stdio.h>
int main(int argc, char const *argv[])
{
if (argc != 2){
printf("Please input %s <filename>.", argv[0]);
return -1;
}
FILE *p = fopen(argv[1], "r");
if (p == NULL){
perror("Failed:");
return -1;
}
char buf[1024];
int n, count = 0;
scanf("%d", &n);
while (count < n){ // 不建议如此
fgets(buf, 1024, p); // 读取长度必须足够大,每次读完一整行才可以
fputs(buf, stdout);
count++;
}
fclose(p);
return 0;
}
(依据 ‘\n’ 计算行数👆)
(因为要输入 -n,所以要指向 argv[1] 串的第二个字符) int atoi(const char *nptr);
二进制读写(fread / fwrite)
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:从文件流读取多个元素
参数: ptr :用来存放读取元素
size :元素大小 sizeof(数据类型)
nmemb :读取元素的个数
stream :要读取的文件
返回值: 成功: 读取的元素的个数;
读到文件尾: 0
失败: -1
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:按对象写
参数:同上
返回值: 成功 :写的元素个数
失败 :-1
实现 cp 功能
23 // while ((s = fgets(arr, 1024, p)) != NULL)
24 // fputs(arr, q);
定位操作
rewind(将文件位置指针定位到起始位置)
void rewind(FILE *stream);
功能:将文件位置指针定位到起始位置
fseek(SEEK_SET、SEEK_CUR、SEEK_END)
打开方式 “a”、“a+” 不支持 fseek函数。
int fseek(FILE *stream, long offset, int whence);
功能:文件的定位操作
参数:stream:文件流
offset:偏移量:正数表示向后文件尾部偏移,负数表示向文件开头偏移
whence:相对位置:
SEEK_SET:相对于文件开头
SEEK_CUR:相对于文件当前位置
SEEK_END:相对于文件末尾
返回值:成功:0
失败:-1
注:当打开文件的方式为a或a+时,fseek不起作用
ftell(获取当前的文件位置)
long ftell(FILE *stream);
功能:获取当前的文件位置
参数:要检测的文件流
返回值:成功:当前的文件位置,出错:-1
打开文件 2.0(freopen)
FILE * freopen(const char *pathname, const char *mode, FILE* fp);
功能:将指定的文件流重定向到打开的文件中
参数:path:文件路径
mode:打开文件的方式(同fopen)
fp:文件流指针
返回值:成功:返回文件流指针
失败:NULL