IO:input/output,针对文件的输入输出。
Linux下的文件类型:
b (block块设备),
c (character字符设备),
d (directory目录),
- (普通文件),
l (link链接文件),
s (socket套接字文件),
p (pipe管道文件);
在C库中定义的一组用于输入输出的函数。
1. 有缓冲机制,通过缓冲机制减少系统调用的次数,提高效率
2. 围绕流进行操作,流用FILE *描述,FILE是一个保存文件信息的结构体
3. 默认打开了三个流,stdin(标准输入)、stdout(标准输出)、stderr(标准错误) ->结构体指针变量
刷新缓存的条件:
1) . 程序正常退出
2) . \n刷新缓存
3) . fflush强制刷新
4) . 缓存区满刷新
刷新缓存的条件:
1) . 程序正常退出
2) . fflush强制刷新
3) . 缓存区满刷新
练习:计算标准输出行缓存区的大小
方法一:用循环打印数据的方法,计算出缓存区大小
#include
int main(int argc, const char *argv[])
{
int i;
for (i = 0; i < 300; i++)
printf("%4d",i);
while(1);
return 0;
}
0-255,每个数字位宽占4位,共1024(1K)
方法二:用FILE结构体中成员计算缓存区大小。
#include
int main(int argc, const char *argv[])
{
printf("hello"); //先使用一下缓冲区 不然打印为0
printf(" %d\n",stdout->_IO_buf_end - stdout->_IO_buf_base);
return 0;
}
FILE * fopen(const char *path, const char *mode);
功能:打开文件
参数:path:打开文件路径
mode:打开方式:
r:只读,流定位到文件开头
r+:可读可写,流定位到文件开头
w:只写,文件不存在->创建,文件存在->清空
w+:可读可写,文件不存在->创建,文件存在->清空
a:追加,文件不存在->创建,文件存在->追加,流定位到文件末尾
a+:可读可写,文件不存在->创建,文件存在->追加,
当第一次读文件流定位到开头,写文件定位到末尾
返回值:成功:文件流,FILE *
失败:NULL,并设置errno
示例:
int main(int argc, char const *argv[])
{
FILE *fp;
fp = fopen("./a.c","r+"); //在当前路径打开a.c文件,(可读可写权限)
if(fp == NULL)
{
perror("open err\n");
return -1;
}
printf("open suc\n");
return 0;
}
int fgetc(FILE *stream)
功能:从文件中读一个字符
参数:stream:文件流
返回值:
成功:读到字符的ASCII码
失败或读到文件末尾:EOF
-------------------------------
int fputc(int c, FILE * stream)
功能:向文件中写入一个字符
参数:c:要写的字符
stream:文件流
返回值:成功:写的字符的ASCII
失败:EOF
练习:编程实现cat命令功能。
#include
int main(int argc, char const *argv[])
{
FILE *fp; //定义文件流
fp = fopen("test.c","r");
if(fp == NULL)
{
perror("open err\n");
return -1; //非正常退出 -1
}
printf("open suc\n");
int ch;
// while((ch = fgetc(fp)) != EOF)
// {
// printf("%c",ch);
// }
while(1) //也可以写成上述注释部分
{
ch = fgetc(fp); //读取
if (ch == EOF) //失败或读到文件末尾返回EOF
break;
printf("%c",ch); //打印
}
return 0;
}
char * fgets(char *s, int size, FILE * stream);
功能:从文件中每次读取一行字符串
参数:s:存放字符串的地址
size:一次读取的字符个数
stream:文件流
返回值:成功:s的地址
失败或读到文件末尾:NULL
特性:每次实际读取的字符个数为size-1个,会在末尾自动添加\0
遇到\n结束一次读
----------------------------------------------------
int fputs(const char *s, FILE * stream);
功能:向文件中写字符串
参数:s:要写的内容
stream:文件流
返回值:成功:非负整数
失败:EOF
练习:编程实现"wc -l 文件名"功能。通过fgets实现
计算文件的行数
#include
#include
int main(int argc, char const *argv[])
{
FILE *fp;
char buf[64] = "";
fp = fopen(argv[1],"r+"); //可读可写权限
if(fp == NULL)
{
perror("open err\n");
return -1;
}
int i = 0;
char *p = buf;
while(fgets(buf,sizeof(buf),fp) != NULL)
{
if(buf[strlen(buf)-1] == '\n')
i++;
}
printf("%d\n",i);
return 0;
}
int fclose(FILE *stream);
参数:stream:文件流
编程实现head功能。
如:head -15 test.c -> ./a.out -15 test.c ->argv[1]:"-15"
#include
#include
#include
int main(int argc, char const *argv[])
{
FILE * fp;
char buf[64] = " ";
int i = 1,count = 0;
if (argc != 3)
{
printf("usage:%s [-num] \n",argv[0]);
return -1;
}
int num = abs(atoi(argv[1]));
fp = fopen(argv[2],"r+");
if (NULL == fp)
{
printf("打开失败\n");
return -1;
}
while(fgets(buf,50,fp) != NULL) //统计文件的行数
{
if(buf[strlen(buf)-1] == '\n')
count++;
}
rewind(fp);
while(i <= num && i <= count) //保证要显示的行数不多于文件的行数
{
fgets(buf, 64, fp);
printf("%s",buf);
i++;
}
fclose(fp);
return 0;
}
int feof(FILE * stream);
功能:判断文件有没有到结尾
返回:到达文件末尾,返回非零值
----------------------------
int ferror(FILE * stream);
功能:检测文件有没有出错
返回:文件出错,返回非零值
可如下判断:
if(ferror(fp)) //判断读文件失败
printf("error\n");
if(feof(fp)) //判断读到末尾
printf("eof\n");
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);
功能:按对象写
参数:ptr :用来存放读取元素
size :元素大小 sizeof(数据类型)
nmemb :读取对象的个数
stream :要读取的文件
返回值:成功:写的元素个数
失败 :-1
Fread和fwrite函数注意:
1)两个函数的返回值为:读或写的对象数
2)对于二进制数据我们更愿意一次读或写整个结构。
示例:
#include
int main(int argc, char const *argv[])
{
FILE *fp;
int data[3] = {70, 80, 90};
int array[3] = {100};
fp = fopen("./test.c","r+");
if(fp == NULL)
{
perror("open err\n");
return -1; //非正常退出 -1
}
fwrite(array,sizeof(int),3,fp); //往fp文件流写入3个array里的int类型的数据
rewind(fp); //定位至开头
fread(data,sizeof(int),3,fp); //读出数据 被100 0 0覆盖
for(int i = 0; i < 3; i++)
printf("%d\n",data[i]);
fclose(fp);
return 0;
}
FILE * freopen(const char *pathname, const char *mode, FILE* fp)
功能:将指定的文件流重定向到打开的文件中
参数:path:文件路径
mode:打开文件的方式(同fopen)
fp:文件流指针
返回值:成功:返回文件流指针
失败:NULL
示例:
#include
int main(int argc, char const *argv[])
{
printf("hello\n");
//将标准输出重定向到打开的文件test.c中
freopen("./test.c","r+",stdout);
printf("world\n"); //即world重定向写入到test.c中
//将标准输出重定向到终端文件
freopen("/dev/tty","r+",stdout); ///dev/tty 当前的终端
printf("nihao\n");
return 0;
}
int fseek(FILE *stream, long offset, int whence);
功能:文件的定位操作
参数:stream:文件流
offset:偏移量:正数表示向后文件尾部偏移,负数表示向文件开头偏移
whence:相对位置:
SEEK_SET:相对于文件开头
SEEK_CUR:相对于文件当前位置
SEEK_END:相对于文件末尾
返回值:成功:0
失败:-1
注:当打开文件的方式为a或a+时,fseek不起作用
long ftell(FILE *stream);
功能:获取当前的文件位置
参数:要检测的文件流
返回值:成功:当前的文件位置,出错:-1
fseek(fp, 0, SEEK_SET); ==> rewind(fp);
示例:将test.c文件相对开头偏移10个字符,写入若干字符,计算当前指针所在位置
#include
int main(int argc, char const *argv[])
{
FILE *fp;
fp = fopen("./test.c","r+");
if(fp == NULL)
{
perror("open err\n");
return -1; //非正常退出 -1
}
//将文件读写位置指针相对开头偏移10个字符
fseek(fp,10,SEEK_SET);
fputc('a',fp); //写入a字符
fputs("hello",fp); //写入hello字符串
//计算位置指针当前所在的位置
long p = ftell(fp);
printf("%ld\n",p);
fclose(fp);
return 0;
}