C语言文件输入输出
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>// 标准高级I/O standard high-level I/O
#include <string.h>
(资料图片)
#include <stdlib.h>
#include <ctype.h>
// 文件是存储设备上的一段已命名的存储区
void file_examine(void);
double average_data(char* filename);
void display1(int ch, char* filename);
void copy_file(char* dest_file, char* src_file);
FILE* open_file(char* filename,char* mode);
void close_file(FILE* fp, char* filename);
void to_upper(char* filename);
void concatenate(char* s1, char* s2);
void append(FILE* src, FILE* dest);
void addaword(char* filename);
void random_access(void);
void other(void);
int main(int argc, char* argv[])//argv储存的是指向参数字符串的指针
{
other();
return 0;
}
void file_examine(void) {
fputs("Enter filename:", stdout);//stdout标准输出文件,C将stdin(标准输入文件,是系统的普通输入设备,一般为输入设备键盘)和stdout(标准输出文件,是系统的普通输出设备,一般为输出设备屏幕)视为文件,所以函数将字符串输出到标准输出文件
char filename[64] = "";
char* res = fscanf(stdin,"%63s",filename);//fscanf比scanf多了第一个参数,文件指针,fscanf(stdin,...)和scanf等价
if (res==NULL)
{
fputs("错误:没有收到内容\n", stderr);//stderr标准错误,程序每次运行会自动打开stdin/stdout/stderr三个标准文件,stderr通常输出到屏幕,即便stdout重定向到文件,stderr也不受影响
exit(EXIT_FAILURE);
}
FILE* fp = fopen(filename, "r");// FILE*文件指针,指向的数据对象是一个C结构,包含文件信息。fopen(文件名字符串,模式字符串)返回文件指针,打开失败返回NULL,文件名字符串为相对路径
/*模式字符串有"w"(以文本模式、写模式打开文件,如果该文件不存在则创建,如果存在则清除内容)wb(和w区别是以二进制模式打开文件)w+ (和w区别是以更新模式打开文件,更新模式即可读写文件)wb+(对应wb)
"r"(文本模式、读模式,如果文件不存在返回NULL)rb(二进制模式)r+(可读写)rb+(对应rb)
"a"(文本模式,写模式,不存在则创建,存在则固定在文件末尾添加内容)ab(二进制)a+(更新模式,写入依然固定末尾添加)ab+(对应ab)
wx/wbx/w+x/wb+x/w+bx(C11标准,类似非x模式,但是如果文件已存在或以独占模式打开文件则打开文件失败)
*/
//由于各系统的文件格式有差异,使用文本模式会将输入和输出解释为C规定的统一格式,程序按照统一的格式处理内容(如将/r/n解释为/n一个字符),C实现将内容转换为系统所用的格式。而二进制模式将文件原始内容不做转换直接输入/输出
if (fp==NULL)
{
fprintf(stderr, "错误:无法打开文件%s\n",filename);//fprintf(文件指针,格式化字符串,待打印项123...) 比printf多一个参数,实际上printf就是使用的fprintf(stdout,...)
exit(EXIT_FAILURE);
}
char ch;
unsigned long count;
for (count = 0; (ch=getc(fp))!=EOF; count++)//getc(文件指针),从指定的文件中读取字符,getc(stdin)==getchar()
{
putc(ch, stdout);//putc(字符,文件指针),putc(...,stdout)==putchar(...)
}
putchar('\n');//文件的最后一行末尾没有换行符
int status = fclose(fp);//打开的文件用完必须要关闭,fclose(文件指针),关闭成功返回0,失败返回非0
if (status!=0)
{
fputs("错误:无法关闭文件", stderr);
}
printf("File %s has %lu characters\n", filename, count);
}
FILE* open_file(char* filename, char* mode) {
FILE* fp = fopen(filename, mode);// fopen()不仅打开一个文件,还创建了一个缓冲区(读写模式创建两个)以及一个包含文件信息和缓冲区数据的结构,fopen返回一个指向该结构的指针,把该指针赋给变量的过程称为fopen函数打开一个流stream,分为文本流和二进制流。
// 该结构通常包含一个指定流中当前位置的文件位置指示器、错误指示器、文件结尾指示器、一个指向缓冲区开始处的指针、一个文件标识符、一个统计实际拷贝进缓冲区字节数的计数器
if (fp == NULL)
{
fprintf(stderr, "文件%s打开失败", filename);
}
return fp;
}
void close_file(FILE* fp, char* filename) {
int status = fclose(fp);
if (status != 0)
{
fprintf(stderr, "文件%s关闭失败", filename);
}
return status;
}
void copy_file(char* dest_file, char* src_file) {
FILE* fp1, * fp2;//声明两个指针,第二个指针也要加*
if ((fp1 = open_file(src_file, "rb")) == NULL)
{
exit(EXIT_FAILURE);
}
if ((fp2 = open_file(dest_file, "wb")) == NULL)
{
close_file(fp1, src_file);
exit(EXIT_FAILURE);
}
char buffer[4096];//C规定char类型为1字节
int len;
long sum = 0L;
while (len = fread(buffer, 1, 4096, fp1))// fread(缓冲区,元素大小,元素数量,文件指针)从文件中读取二进制数据到指定的缓冲区,如果将buffer视为一个完整的数据对象,则元素大小为4096,元素数量为1,无论如何设定这两个参数,读取的字节数都是两个参数的乘积,函数返回读取到的元素数量,当读取到文件末尾时返回的数量会小于参数3
{
fwrite(buffer, 1, len, fp2);// fwrite(缓冲区,元素大小,元素数量,文件指针)将缓冲区的数据写入文件
sum += len;
}
close_file(fp1, src_file);
close_file(fp2, dest_file);
printf("%ldbytes\n", sum);
}
double average_data(char* filename) {
FILE* fp = fopen(filename, "rb");
if (fp)
{
double sum = 0;
int count = 0;
double buffer;
putchar('(');
while (fread(&buffer, sizeof(double), 1, fp)) //文件中原样保存着double数组,fread将其中的元素逐一读取
{
printf("%.2f ", buffer);
sum += buffer;
count++;
}
putchar(')');
fclose(fp);
return sum / count;
}
return 0;
}
void display1(int ch, const char* filename) {
FILE* fp = fopen(filename, "r");
if (fp)
{
char line[256];
char* ptr;
while (ptr = fgets(line, 256, fp))
if (strchr(line, ch))
fputs(line, stdout);
fclose(fp);
}
}
void to_upper(char* filename) { //将文件中所有字母转大写
FILE* fp = open_file(filename, "r+");//r+模式打开文件,可以读写,如果位置不是文件末尾,写操作会覆盖当前位置的字符
if (fp)
{
fpos_t pos;// fpos_t类型的变量或数据对象可以在文件中指定一个位置
fgetpos(fp, &pos);// 将文件当前位置存储到fpos_t变量的地址上(被调函数通过主调函数的变量的地址修改该变量的值),成功返回0,失败返回非0
char ch;
while ((ch=getc(fp))!=EOF)
{
fsetpos(fp, &pos);// 设定文件当前位置,成功返回0,失败返回非0
putc(toupper(ch), fp);//转换字符为大写存储
fflush(fp);//刷新输出流缓冲区,标准IO使用缓冲,fopen()打开文件时会生成缓冲区,一般当缓冲区被填满时才会将数据传给操作系统,而读写交替需要刷新缓冲才能正常执行,fflush(文件指针)用于刷新输出流,C标准未定义刷新输入流的情况,所以fflush用于写模式,如果是更新模式/+模式则上一次io操作必须为写操作
fgetpos(fp, &pos);//更新位置
}
close_file(fp, filename);
}
}
void concatenate(char* s1, char *s2) {
if (strcmp(s1,s2)==0)
{
puts("文件名不能冲突");
exit(EXIT_FAILURE);
}
FILE* fa, * fs;
int files = 0;
int ch;
if ((fs = open_file(s1, "r")) == NULL)
{
exit(EXIT_FAILURE);
}
if ((fa = open_file(s2, "a+")) == NULL)
{
close_file(fs, s1);
exit(EXIT_FAILURE);
}
if (setvbuf(fa, NULL, _IOFBF, 4096) != 0)// setvbuf()函数创建一个供标准IO函数替换使用的缓冲区,在打开文件后且未对流进行其他操作之前调用该函数有效。参数1为文件指针,参数2为供替换使用的缓冲区地址,传入NULL会使函数自动分配一个缓冲区,参数3为缓冲的模式,_IOFBF(完全缓冲IO full buffer,在缓冲区满或调用fflush函数时刷新)_IOLBF(行缓冲line,在写入\n或缓冲区满时刷新)_IONBF(无缓冲),参数4为缓冲区的大小,操作成功返回0,失败返回非0
{
fputs("Can't create output buffer\n", stderr);
exit(EXIT_FAILURE);
}
append(fs, fa);//将fs的内容拼接到fa的后面
if (ferror(fs)!=0)// ferror()函数用于判断io操作是否出现错误,当读或写出现错误返回非0,否则返回0。fs是读操作,出现错误(非0)说明fs的内容可能未完全读取,而输入出现错误时也会返回EOF
{
fprintf(stderr, "Error in reading file %s.\n", s1);
}
if (feof(fa) == 0)// feof()函数判断是否到达结尾,当上一次输入调用检测到文件结尾时,feof返回非0,否则返回0,所以如果返回0说明没到结尾、输入出现错误
{
fprintf(stderr, "Error in reading file %s.\n", s1);
}
rewind(fa);// rewind()函数将当前位置调回文件开头
printf("%s contents:\n", s2);
while ((ch=getc(fa))!=EOF)
{
putchar(ch);
}
close_file(fs, s1);
close_file(fa, s2);
}
void append(FILE* src, FILE* dest) {
size_t bytes;
char temp[4096];
while ((bytes=fread(temp,sizeof(char),4096,src))>0)// fread返回size_t类型
{
fwrite(temp, sizeof(char), bytes, dest);// fwrite返回成功写入项的数量,正常情况数量和bytes相等
}
}
void addaword(char* filename)
{
FILE* fp;
char words[41];
if ((fp=fopen(filename,"a+"))==NULL)//打开失败返回NULL
{
fprintf(stdout, "Can't open \"%s\"file.\n", filename);
exit(EXIT_FAILURE);
}
int num = 0;
while (fscanf(fp,"%40s",words)==1)//a+模式在写入之前位置位于文件开头
{
if (isdigit(words[0]))
num = atoi(words);//读取行号
}
puts("Enter words to add to the file; press the # key at the beginning of a line to terminate.");
while ((fscanf(stdin, "%40s", words) == 1) && (words[0] != '#'))
fprintf(fp, "%d.%s\n", ++num, words);
puts("File contents: ");
rewind(fp);//返回文件开头位置
while (fscanf(fp, "%40s", words) == 1)
puts(words);
puts("Done!");
if (fclose(fp)!=0)//关闭文件成功返回0
{
fprintf(stderr, "Error closing file\n");
}
}
void random_access(void)
{
puts("Enter filename:");
char filename[64] = "";
FILE* fp;
if ((scanf("%63s", filename) == 1)&&(fp=fopen(filename,"rb")))
{
long pos;
char ch;
while (puts("Enter a position:"),scanf("%ld",&pos)==1&&pos>=0)
{
if (fseek(fp,pos,SEEK_SET)==-1)//fseek(文件指针,偏移量,起始点模式)函数将文件的位置移动到任意字节处,从起始点出发移动偏移量指定的字节数,参数3设定起始点的模式,SEEK_SET为以文件开头作为起始点,SEEK_CUR为以当前位置为起始点,SEEK_END为以文件结尾(eof)为起始点,偏移量为正数即往后/下移动,负数则往回/上移动。
{
puts("pos out of range");// fseek()函数移动成功返回0,移动超出文件范围返回-1(在visual studio中即使超出范围也返回0)
continue;
}
putchar('\"');
while ((ch=getc(fp))!=EOF&&ch!='\r'&&ch!='\n')
{
putchar(ch);
}
puts("\"\n");
}
fseek(fp, 0L, SEEK_END);//SEEK_END模式设定起始点为文件末尾eof,这个位置getc会返回eof,往前一个字节/-1偏移量是文件中的最后一个字符
printf("range from 0 to %ld\n", ftell(fp)-1);//ftell(文件指针)返回当前位置距离文件开始的字节数/偏移量
fclose(fp);
fp = fopen(filename, "r");//在文本模式下测试fseek和ftell
while (!feof(fp))
{
printf("%ld %c\n", ftell(fp), getc(fp));//文本模式下将\r\n看作\n,但\n和\r前面一个字符的ftell()值依然相差2
}
}
}
void other(void)
{
FILE* fp;
char ch;
if (fp=fopen("data02.txt","r"))
{
putchar(ch=getc(fp));// 读取一个字符
if (ch=='\n')
{
ungetc(ch, fp);// ungetc(字符,文件指针)将字符放回缓冲,不只可以放回上一个读取的字符,也可以放任意字符,放回缓冲区并不会改变文件内容,作用同scanf()读取到不符合的字符放回输入队列
}
fclose(fp);
}
}
- 科学技术与资本加持 盼盼“椰子跳
- 世界今日报丨广西启动2023年度“走
- 环球快看点丨陕西省多举措助力中小
- 科技助力让春耕备耕更“智慧”
- 微资讯!河北省开展分类管理力促冬
- 科学技术与资本加持 盼盼“椰子跳
- 腾讯视频回应上海消保委:将提供便
- 广西持续推动农业农村经济发展助力
- 全球球精选!安徽休宁:春山雨霁
- 【天天报资讯】肉羊养殖的利润
- 当前热议!秦皇岛航空客运市场客座率
- 全球观速讯丨“千树万树梨花开”航
- 焦点要闻:小学班主任期末工作总结
- 全球观点:研究人员揭示了山楂如何
- 【速看料】LOL石头人天赋s6
- 鹦鹉鱼的饲养方法 鹦鹉鱼的饲养技
- 世界今亮点!二十四小时快报:8年来
- 桌面壁纸风景美女图片
- 深夜 高铁线上巡检人
- 02月14日从湖州出发到海北的防疫政策
- “时光无恙,星河滚烫”2023年凯美
- 玉溪烟草:一抹“新绿”开启物流新
- 国际油价下跌,应对俄罗斯减产,美
- 世界百事通!《山居秋暝》赏析
- 精选!云南红塔银行成功入选2022云
- 天天微头条丨聊城大步迈入“两河时
- 【环球聚看点】三八妇女节送礼物给
- 给自己考研时鼓励的话
- 【独家】安顺市:强化行政复议调解
- 两地突发地震!震感强烈!