目录
函数接口
1》打开文件fopen
2》关闭文件fclose
3》文件读写操作
1> 每次读写一个字符:fgetc(),fputc()
针对文件读写
针对终端读写
练习:实现 cat 命令功能 格式:cat 文件名
2> 每次一个字符串的读写 fgets() 和 fputs()
针对终端读写
针对文件读写
练习:通过fgets实现"wc -l 文件名"命令功能(计算文件行数)
函数接口
1》打开文件fopen
man 3 fopen
FILE *fopen(const char *path, const char *mode);
功能:打开文件
参数:
path:打开的文件路径
mode:打开的方式
r:只读,当文件不存在时报错,文件流定位到文件开头
r+:可读可写,当文件不存在时报错,文件流定位到文件开头
w:只写,文件不存在创建,存在则清空
w+:可读可写,文件不存在创建,存在则清空
a:追加(在末尾写),文件不存在创建,存在追加,文件流定位到文件末尾
a+:读和追加,文件不存在创建,存在追加,读文件流定位到文件开头,写文件流定位到文件末尾
注:当a+的方式打开文件时,写只能在末尾进行追加,定位操作是无法改变写的位置,但是可以改变读的位置
返回值:
成功:文件流
失败:NULL,并且会设置错误码
#include <stdio.h>
int main(int argc, char const *argv[])
{
FILE *fp;
fp = fopen("test.txt", "r");//只读方式打开文件
if (NULL == fp)//文件不存在,返回-1
{
perror("fopen err");
return -1;
}
printf("fopen success\n");//文件存在,返回成功
return 0;
}
#include <stdio.h>
int main(int argc, char const *argv[])
{
FILE *fp;
fp = fopen("test.txt", "w");//只写方式打开文件
if (NULL == fp)//文件不存在,创建,存在则清空
{
perror("fopen err");
return -1;
}
printf("fopen success\n");//文件存在,返回成功
return 0;
}
#include <stdio.h>
int main(int argc, char const *argv[])
{
FILE *fp;
fp = fopen("test.txt", "a");//追加方式打开文件,文件不存在,创建,读定位到开头,写定位到末尾
if (NULL == fp)
{
perror("fopen err");
return -1;
}
printf("fopen success\n");//文件存在,返回成功
return 0;
}
补充:
perror( )用来将上一个函数发生错误的原因输出到标准设备 (stderr) 。参数 s 所指的字符串会先打印出, 后面再加上错误原因字符串。此错误原因依照全局变量errno 的值来决定要输出的字符串。在库函数中有个errno变量,每个errno值对应着以字符串表示的错误类型。当你调用"某些"函数出错时,该函数已经重新设置了errno的值。perror函数只是将你设置的一些信息和现在的errno所对应的错误一起输出。
2》关闭文件fclose
int fclose(FILE* stream);
功能:关闭文件
参数:stream:文件流
#include <stdio.h>
int main(int argc, char const *argv[])
{
FILE *fp;
//1.打开文件
//fp = fopen("test.txt", "r"); //如果不存在会错误,因为只读r模式
fp = fopen("test.txt", "w");
if (NULL == fp)
{
perror("fopen err");
// while(1); //标准错误不缓存,错误信息会打印
return -1;
}
printf("fopen success\n");
//2.关闭文件
fclose(fp);
return 0;
}
3》文件读写操作
1> 每次读写一个字符:fgetc(),fputc()
每次读一个字符fgetc()
int fgetc(FILE * stream);
功能:从文件中读取一个字符,并将当前文件指针位置向后移动一个字符。
参数:stream:文件流
返回值:成功:读到的字符
失败或读到文件末尾:EOF(-1)
每次写一个字符fputc()
int fputc(int c, FILE * stream);
功能:向文件中写入一个字符, 成功写入后文件指针会自动向后移动一个字节位置。
参数:c:要写的字符
stream:文件流
返回值:成功:写的字符的ASCII
失败:EOF(-1)
针对文件读写
#include <stdio.h>
int main(int argc, char const *argv[])
{
FILE *fp;
//1.打开文件
fp = fopen("test.txt", "r+");//可读可写方式打开
if (NULL == fp)
{
perror("fopen err");
return -1;
}
printf("fopen success\n");
char ch = fgetc(fp);//定义一个char类型变量接收读取的字符 每读取一次光标都会向后移
printf("%d %c\n", ch, ch); //104 h
ch = fgetc(fp);
printf("%d %c\n", ch, ch); //101 e
//写的时候会先把光标移到末尾
fputc('a', fp); //向文件中写个a
fputc('b', fp); //向文件中写个b
//因为光标移动到末尾了,所以打印是EOF
ch = fgetc(fp);
printf("%d %c\n", ch, ch); //-1 EOF 因为以及到末尾了
//2.关闭文件
fclose(fp);
return 0;
}
针对终端读写
#include <stdio.h>
int main(int argc, char const *argv[])
{
char ch;
ch = fgetc(stdin); //相当于getchar()
printf("%d %c\n", ch, ch);
fputc(ch, stdout); //相当于putchar()
fputc(10, stdout);
fputc('b', stdout);
return 0;
}
补充:feof 和 ferror
int feof(FILE * stream);
功能:判断文件有没有到结尾,也就是当前所在位置后面还有没有字符。
返回:如果到达文件末尾,返回非零值。如果后面还有字符则返回0。
#include <stdio.h>
int main()
{
FILE *fp;
fp = fopen(argv[1], "r");//打开命令行中输入的文件,
if (NULL == fp)
{
perror("fopen error\n");
return -1;
}
printf("fopen success\n");
char ch = fgetc(fp);//定义一个字符变量接收读取的内容
printf("%d %c\n", ch, ch);//打印
if (feof(fp))//判断此时光标是否在末尾
{
printf("end\n");
return -1;
}
//文件的末尾默认还有一个\0 EOF,读到最后一个有效数据时,不算末尾,需要再读一个才算光标到达末尾
ch = fgetc(fp);
printf("%d %c\n", ch, ch);
if (feof(fp))//判断此时光标是否在末尾
{
printf("end\n");
return -1;
}
return 0;
}
int ferror(FILE * stream);
功能:检测文件有没有出错
返回:文件出错,返回非零值。如果没有出错,返回0。
#include <stdio.h>
int main()
{
FILE *fp;
fp = fopen(argv[1], "w");//w 只写,不可读
if (NULL == fp)
{
perror("fopen error\n");
return -1;
}
printf("fopen success\n");
char ch = fgetc(fp);//w 只写,不可读,这个操作在读文件,属于操作错误,这时用ferror函数去判断就会返回非零值
printf("%d %c\n", ch, ch);
if (ferror(fp))//ferror进行判断之前的操作是否有误
{
printf("error\n");
return -1;
}
return 0;
}
练习:实现 cat 命令功能 格式:cat 文件名
#include <stdio.h>
/* cat 文件名:查看文件内容,显示到终端。
步骤:
1.打开文件 fopen
2.循环用fgetc获取文件内容
3.当读到文件末尾标志EOF时结束
4.将读取文件内容用fputc打印到终端
5.关闭文件
*/
int main(int argc, char const *argv[])
{
if (argc != 2)//命令行文件名个数是否等于 2
{
printf("err: %s <filename>\n", argv[0]); //提示一下正确的格式
return -1;
}
//1.打开文件
FILE *fp = fopen(argv[1], "r");//打开命令行中输入的文件名
if (NULL == fp)
{
perror("fopen err");
return -1;
}
char ch = fgetc(fp);//读取文件中的字符
while (!feof(fp))//当读取的光标处不是EOF时,说明没到末尾
{
fputc(ch, stdout);//输出一个字符
ch = fgetc(fp);//读取字符,光标继续向后移动
}
//3. 关闭文件
fclose(fp);
return 0;
}
2> 每次一个字符串的读写 fgets() 和 fputs()
char * fgets(char *s, int size, FILE * stream);
功能:从文件中每次读取一行字符串
参数: s:存放字符串的地址
size:期望一次读取的字符个数
stream:文件流
返回值:成功:s的地址
失败或读到文件末尾:NULL
特性: 每次实际读取的字符个数为size-1个,会在末尾自动添加\0
每次读一行,遇到\n或者到达文件末尾后不再继续读下一行
并把它存储在s所指向的字符串内。
int fputs(const char *s, FILE * stream);
功能:向文件中写字符串
参数:s:要写的内容
stream:文件流
返回值:成功:非负整数
失败:EOF
针对终端读写
#include <stdio.h>
int main(int argc, char const *argv[])
{
char buf[32] = "";
//输入操作
fgets(buf, 32, stdin); //输入hello\n, 此时buf中存入内容: hello\n\0
printf("buf: %s\n", buf);
//每次输入都是从头开始写,,写完会自动补 0,会覆盖掉之前的内容,但\0 后的内容仍然存在
fgets(buf, 32, stdin); //输入66\n, 此时buf中内容: 66\n\0o\n\0,
printf("buf: %s\n", buf);
//输出操作
fputs("world", stdout);//把字符串输入到标准输出里
fputs(buf, stdout);//把buf里的内容输入到标准输出里
return 0;
}
针对文件读写
#include <stdio.h>
int main(int argc, char const *argv[])
{
FILE *fp;
char buf[32] = "";
fp = fopen("test.txt", "r+");//test.txt 文件中内容:hello\n world\n 66\n\0
if (NULL == fp)
{
perror("fopen err");
return -1;
}
printf("fopen success\n");
//读写操作
fgets(buf, 32, fp); //遇到\n或到达末尾后不再继续读 buf:hello\n\0
fputs(buf, stdout);
fgets(buf, 32, fp); // 继续读下一行 buf:world\n\0
fputs(buf, stdout);
fgets(buf, 32, fp); //buf: 66\0ld\n\0
fputs(buf, stdout);
//关闭文件
fclose(fp);
return 0;
}
练习:通过fgets实现"wc -l 文件名"命令功能(计算文件行数)
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
FILE *fp;
char buf[32] = "";
if (argc != 2)//判断命令行指针数组的元素个数
{
printf("err: %s <filenme>\n",argv[0]);
return -1;
}
fp = fopen(argv[1], "r");//打开该文件
if (NULL == fp)
{
perror("fopen err");
return -1;
}
//循环fgets读文件, 只要读到就判断是否有\n, 如果有就累加行数
int len = 0;
while (fgets(buf, 32, fp) != NULL)
{
if (buf[strlen(buf) - 1] == '\n')
len++;
}
printf("%d %s\n", len, argv[1]); //wc -l会少一行,因为最后一行没有换行
fclose(fp);
return 0;
}
今天的分享就到这里结束啦,如果有哪里写的不好的地方,请指正。
如果觉得不错并且对你有帮助的话请给个三连支持一下吧!