c语言IO函数
1.fgets、fputs文件操作,文件加密, 逐行读写
1) 文件使用方式由r,w,a,t,b,+六个字符拼成,各字符的含义是:
r(read): 读
w(write): 写
a(append): 追加
t(text): 文本文件,可省略不写
b(banary): 二进制文件
rb+:可读可写
+: 读和写
2) 凡用“r”打开一个文件时,该文件必须已经存在,且只能从该文件读出。
3) 用“w”打开的文件只能向该文件写入。若打开的文件不存在,则以指定的文件名建立该文件,若打开的文件已经存在,则将该文件删去,重建一个新文件。
4) a 打开只写文件,如果文件不存在,建立文件, 写入追加
5) 在打开一个文件时,如果出错,fopen将返回一个空指针值NULL。在程序中可以用这一信息来判别是否完成打开文件的工作,并作相应的处理
r windows下文本文件,\r\n代表换行,使用fputss函数写入\n,函数自动会在\n前面加\r,读出来以后只有\n,自动去掉\r
rb二进制来读文本文件,那么不会对\r\n进行省略
unix\linux文本文件中,\n表示换行
\r: ascII d 13
\n: a 10
代码:
#include <stdio.h>
#include <string.h>
// 输入内容写文件
int main01(void)//写文件
{
char s[1024] = { 0 };
FILE *p = fopen("D:\\temp\\a.txt", "w");//用写的方式打开一个文件
//"w"意思就是如果文件不存在,就建立一个人间,如果文件存在就覆盖
while(1)
{
memset(s, 0, sizeof(s));
//scanf("%s", s);
//scanf和 gets的区别:scanf如果 判断输入空格,那么会换行,gets可以接收空格
gets(s);
if (strcmp(s, "exit") == 0)
break;//如果用户输入的是exit,那么循环退出
int len = strlen(s);
s[len] = '\n';
fputs(s, p);
}
fclose(p);//关闭这个文件
//操作一个文件的步骤和把大象放冰箱是一样的
printf("end\n");
return 0;
}
// 逐行读取内容
int main02()
{
char s[1024] = { 0 };
FILE *p = fopen("D:\\temp\\main.c", "r");//用读的方式打开一个文件
//feof(p);//如果已经到了文件结尾,函数返回真
while(!feof(p))//如果没有到文件结尾,那么就一直循环,如果是文件末尾,返回0
{
memset(s, 0, sizeof(s));
fgets(s, sizeof(s), p);//第一个参数是一个内存地址,第二个参数是这块内存的大小,第三个参数是fopen返回的文件指针
printf("%s", s);
}
fclose(p);
return 0;
}
void code(char *s)
{
while(*s)//遍历一个字符串
{
(*s)++; // 文件的 加密,为每一个字符串都加1
s++;
}
}
void decode(char *s)
{
while(*s)//遍历一个字符串
{
(*s)--;
s++;
}
}
// 这里实现文件的加密功能
int main03()
{
char s[1024] = { 0 };
FILE *p = fopen("D:\\temp\\a.txt", "r");//用读的方式打开一个文件
FILE *p1 = fopen("D:\\temp\\b.txt", "w");//用写的方式打开一个文件
//feof(p);//如果已经到了文件结尾,函数返回真
while(!feof(p))//如果没有到文件结尾,那么就一直循环
{
memset(s, 0, sizeof(s));
fgets(s, sizeof(s), p);//第一个参数是一个内存地址,第二个参数是这块内存的大小,第三个参数是fopen返回的文件指针
code(s);//
fputs(s, p1);
}
fclose(p);
fclose(p1);
return 0;
}
// 这里 实现对加密 后的 文件 进行解密 功能 解密功能
int main()
{
char s[1024] = { 0 };
FILE *p = fopen("D:\\temp\\b.txt", "r");//用读的方式打开一个文件
FILE *p1 = fopen("D:\\temp\\c.txt", "w");//用写的方式打开一个文件
//feof(p);//如果已经到了文件结尾,函数返回真
while(!feof(p))//如果没有到文件结尾,那么就一直循环
{
memset(s, 0, sizeof(s));
fgets(s, sizeof(s), p);//第一个参数是一个内存地址,第二个参数是这块内存的大小,第三个参数是fopen返回的文件指针
decode(s);//
fputs(s, p1);
}
fclose(p);
fclose(p1);
return 0;
}
2.getc、putc, 逐字节读写
#include <stdio.h>
int main01(void)
{
FILE *p = fopen("D:\\temp\\a.txt", "r");
if (p == NULL)
{
printf("error\n");
}else
{
char c = 0;
while( (c = getc(p)) != EOF)//EOF代表文件最后的一个结束标示
// -1 表示文件的结尾
// EOF就是-1,一个宏
{
//c = getc(p);//一次只读取一个字符
printf("%c", c);
}
fclose(p);
}
return 0;
}
int main02(void)//写一个字符
{
FILE *p = fopen("D:\\temp\\a.txt", "w");
if (p == NULL)
{
printf("error\n");
}else
{
putc('a', p);
putc('b', p);
putc('c', p);
fclose(p);
}
return 0;
}
#define SEC 5
int main03(void)//加密
{
FILE *p = fopen("D:\\temp\\a.txt", "r");
FILE *p1 = fopen("D:\\temp\\b.txt", "w");
if (p == NULL)
{
printf("error\n");
}else
{
char c = 0;
while( (c = getc(p)) != EOF)//EOF代表文件最后的一个结束标示,系统api
{
c += SEC;
putc(c, p1);
}
fclose(p);
fclose(p1);
}
return 0;
}
int main(void)//解密
{
FILE *p = fopen("D:\\temp\\b.txt", "r");
FILE *p1 = fopen("D:\\temp\\c.txt", "w");
if (p == NULL)
{
printf("error\n");
}else
{
char c = 0;
while( (c = getc(p)) != EOF)//EOF代表文件最后的一个结束标示
{
c -= SEC;
putc(c, p1);
}
fclose(p);
fclose(p1);
}
return 0;
}
3.bin-file: 二进制文件操作
二进制文件加密
fread
fwrite
fread指定读取字节数,
如果一次读取内容越大,拷贝花费时间越少,占用内存大
// 每一个文件用UltraEdit 打开都有固定的格式,特定的文件头,可以百度查一下文件格式
3.1.二进制API:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main01(void)
{
FILE *p = fopen("D:\\temp\\bin-file.exe", "rb");//用读二进制的方式打开一个文件
// 加上b: window下是以\r\n结尾,不会丢失\r
// 读的时候会把\r去掉, 写的时候会自动加上\r, 在window下
// char buf[1024] = { 0 };
// 一次读sizeof(buf)个字节
// size_t res = fread(buf, sizeof(char), sizeof(buf), p);//第一个参数是缓冲区,第二个参数是读取的时候最小单位大小,第三个参数是一次读几个单位,第四个参数是打开的文件指针
// //fread返回值代表读取了多少记录数
// printf("res = %u\n", res);
// res = fread(buf, sizeof(char), sizeof(buf), p);//第一个参数是缓冲区,第二个参数是读取的时候最小单位大小,第三个参数是一次读几个单位,第四个参数是打开的文件指针
// //fread返回值代表读取了多少记录数
// printf("res = %u\n", res);
while(!feof(p)) // 判断文件是否到头了
{
char buf[1024] = { 0 };
int res = fread(buf, sizeof(char), sizeof(buf), p);//第一个参数是缓冲区,第二个参数是读取的时候最小单位大小,第三个参数是一次读几个单位,第四个参数是打开的文件指针
int i;
for(i = 0; i < res; i++)
{
printf("buf[%d] = %x\n", i, buf[i]);
}
}
fclose(p);
return 0;
}
int main02()
{
FILE *p = fopen("D:\\temp\\a.dat", "wb");
// char buf[1024] = { 0 };
// buf[0] = 'a';
// buf[1] = 'b';
// buf[2] = 'c';
// buf[3] = 'd';
// fwrite(buf, sizeof(char), sizeof(buf), p);
int a = 0x12345678;
fwrite(&a, 0, 4, p);
fclose(p);
return 0;
}
void code(char *p, size_t n)
{
size_t i;
for(i = 0; i < n; i++)
{
p[i] += 3;
}
}
void decode(char *p, size_t n)
{
size_t i;
for(i = 0; i < n; i++)
{
p[i] -= 3;
}
}
int main03()//二进制加密
{
FILE *p = fopen("D:\\temp\\a.wmv", "rb");
FILE *p1 = fopen("D:\\temp\\b.wmv", "wb");
// FILE *p = fopen("D:\\temp\\a.txt", "rb");
// FILE *p1 = fopen("D:\\temp\\b.txt", "wb");
char buf[1024 * 4];//4k,每次读取4k字节
//如果一次读取内容越大,拷贝花费时间越少,占用内存大
while(!feof(p))
{
memset(buf, 0, sizeof(buf));
size_t res = fread(buf, sizeof(char), sizeof(buf), p);//返回从源文件中读取的字节数
code(buf, res);
fwrite(buf, sizeof(char), res, p1);//从源文件中读取多少字节,那么就往目标文件中写入多少字节
}
fclose(p);
fclose(p1);
printf("end\n");
return 0;
}
int main()//二进制解密
{
clock_t c1 = clock();
FILE *p = fopen("D:\\temp\\b.wmv", "rb");
FILE *p1 = fopen("D:\\temp\\c.wmv", "wb");
// FILE *p = fopen("D:\\temp\\b.txt", "rb");
// FILE *p1 = fopen("D:\\temp\\c.txt", "wb");
char buf[1024 * 4];
while(!feof(p))
{
memset(buf, 0, sizeof(buf));
size_t res = fread(buf, sizeof(char), sizeof(buf), p);//返回从源文件中读取的字节数
//decode(buf, res);
fwrite(buf, sizeof(char), res, p1);//从源文件中读取多少字节,那么就往目标文件中写入多少字节
}
fclose(p);
fclose(p1);
clock_t c2 = clock();
printf("end , %u\n", c2 - c1);
return 0;
}
3.2.fscanf: 从文件中输入 fprintf: 字节打印到文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//
int main01(void)
{
FILE *p = fopen("D:\\temp\\a.txt", "r");
while(!feof(p))
{
char buf[100] = { 0 };
//fgets(buf, sizeof(buf), p);
//fscanf(p, "%s", buf);//fscanf与scanf用法基本一致,fscanf是从一个文件读取输入,scanf是从键盘读取输入
int a = 0;
int b = 0;
fscanf(p, "%d + %d =", &a, &b);
printf("a = %d, b = %d\n", a, b);
//printf("%s\n", buf);
}
fclose(p);
return 0;
}
int main()
{
FILE *p = fopen("D:\\temp\\a.txt", "w");
int array[10] = {1,2,3,4,5,6,7,8,9,10};
int i;
for(i = 0; i < 10; i++)
{
fprintf(p, "array[%d] = %d\n", i, array[i]);
}
// char buf[100] = "hello world";
// int a = 6;
// int b = 7;
//fprintf(p, "%s,%d, %d", buf, a, b);//和printf功能一样,fprintf将输入到文件里面
fclose(p);
return 0;
}
3.3.state大文件拷贝,获取文件属性
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
int main(void)
{
clock_t c1 = clock();//得到系统当前时间,单位:毫秒
struct stat st = { 0 };//定义一个结构,名字叫st
stat("D:\\temp\\a.wmv", &st);//调用完stat函数之后,文件相关的信息就保存在了st结构中了
//st.st_size得到文件的大小
// printf("%u\n", st.st_size);
// printf("Hello World!\n");
char *array = malloc(st.st_size);//根据文件大小在堆中动态的分配一块内存
FILE *p = fopen("D:\\temp\\a.wmv", "rb");
fread(array, sizeof(char), st.st_size, p);//相当于一下把整个文件放入了内存
fclose(p);
p = fopen("D:\\temp\\b.wmv", "wb");
fwrite(array, sizeof(char), st.st_size, p);//将堆中的信息一下都写入文件
fclose(p);
clock_t c2 = clock();//得到系统当前时间,单位:毫秒
printf("end, %u\n", c2 - c1);
return 0;
}
3.4.struct-file: 二进制读写操作结构体
#include <stdio.h>
#include <string.h>
struct student
{
char name[100];
int age;
};
int main01(void)
{
// 把结构的内存地址写入磁盘中
struct student st = {"刘德华", 30};
FILE *p = fopen("D:\\temp\\a.dat", "wb");
fwrite(&st, sizeof(st), 1, p);
fclose(p);
return 0;
}
int main(void)
{
struct student st = {0};
FILE *p = fopen("D:\\temp\\a.dat", "rb");
fread(&st, sizeof(st), 1, p);
fclose(p);
printf("name = %s, age = %d\n", st.name, st.age);
return 0;
}
读写基本数据类型:
FILE* file = fopen("D:\\bb.txt", "wb");
if (file == NULL){
printf("文件打开失败");
}
else
{
int a = 5;
fwrite(&a, sizeof(int), 1, file);
fwrite(&a, sizeof(int), 1, file);
fwrite(&a, sizeof(int), 1, file);
fwrite(&a, sizeof(int), 1, file);
fflush(file);
fclose(file);
}
FILE* file = fopen("D:\\bb.txt", "rb");
int a,b,c,d = 0;
while (fread(&a, sizeof(int), 1, file)!=0)
{
printf("%s", "a");
printf("%d\n", a);
}
fclose(file);
3.5.file-seek: seek 函数的使用
// 把 结构体 使用二进制 的方式读取出来,然后根据年龄使用冒泡 排序,然后打印出来
fseek的返回值为0表示成功,-1表示失败,
如果往后移动文件指针,超过文件大小,fseek返回0
如果往前移动文件指针,超过文件开始位置,返回-1
不能用于判断指针是否越界文件内容
#include <stdio.h>
#include <string.h>
struct student
{
char name[10];
int age;
};
// 准备文件:把struct student st[5]这个 结构体做为5行保存到文件中
int main05(void)
{
struct student st[5] = { 0 };
int i;
for(i = 0; i < 5; i++)
{
printf("please name:");
scanf("%s", st[i].name);
printf("please age:");
scanf("%d", &st[i].age);
}
FILE *p = fopen("D:\\temp\\a.dat", "wb");
fwrite(st, sizeof(struct student), 10, p);
fclose(p);
return 0;
}
//
int main02()
{
struct student st = { 0 };
FILE *p = fopen("D:\\temp\\a.dat", "rb");
//fseek(p, sizeof(struct student) * 2, SEEK_SET);//从文件开始位置向后偏移结构student这么多的字节
memset(&st, 0, sizeof(struct student));
fread(&st, sizeof(struct student), 1, p);
printf("name = %s, age = %d\n", st.name, st.age);
fseek(p, 0 - sizeof(struct student), SEEK_CUR);//从当前位置往回偏移,偏移一个结构,一共5个结构
memset(&st, 0, sizeof(struct student));
fread(&st, sizeof(struct student), 1, p);
printf("name = %s, age = %d\n", st.name, st.age);
fseek(p, 0 - sizeof(struct student), SEEK_END);//从文件结尾位置往回偏移, 一个结构
memset(&st, 0, sizeof(struct student));
fread(&st, sizeof(struct student), 1, p);
printf("name = %s, age = %d\n", st.name, st.age);
// while(1)
// {
// memset(&st, 0, sizeof(struct student));
// if (fread(&st, sizeof(struct student), 1, p) == 0)
// break;
// printf("name = %s, age = %d\n", st.name, st.age);
// }
fclose(p);
return 0;
}
//a.txt 的内容是 abcdefj
int main03()
{
FILE *p = fopen("D:\\temp\\a.txt", "rb");
//abcdef, 偏移2个字节,那么只能读取cdef
fseek(p, 2, SEEK_SET);
char buf[100] = { 0 };
fgets(buf, sizeof(buf), p);
printf("buf = %s\n", buf);
fgets(buf, sizeof(buf), p);
printf("ftell = %d\n", ftell(p)); // ftell()是以字节为单位的,当前指针位置
fclose(p);
return 0;
}
int main04()
{
FILE *p = fopen("D:\\temp\\a.txt", "rb");
while(!feof(p))
{
fseek(p, 0, SEEK_END);//偏移到文件最后
char buf[100] = { 0 };
fgets(buf, sizeof(buf), p);
printf("buf = %s", buf);
}
fclose(p);
return 0;
}
void swap(struct student *a, struct student *b)
{
struct student tmp = *a;
*a = *b;
*b = tmp;
}
// 冒泡排序
void bubble(struct student *p, int n)
{
int i;
int j;
for(i = 0; i < n; i++)
{
for(j = 1; j < n - i; j++)
{
if (p[j - 1].age > p[j].age)
{
swap(&p[j - 1], &p[j]);
}
}
}
}
int main(void)
{
struct student st[5] = { 0 };
FILE *p = fopen("D:\\temp\\a.dat", "rb");
int i;
// for(i = 0; i < 5; i++)//读取文件的代码
// {
// fread(&st[i], sizeof(struct student), 1, p);
// }
fread(st, sizeof(struct student), 5, p);
fclose(p);
// 把 结构体 使用二进制 的方式读取出来,然后根据年龄使用冒泡 排序,然后打印出来
bubble(st, 5);
// for(i = 0; i < 5; i++)
// {
// printf("name = %s, age = %d\n", st[i].name, st[i].age);
// }
p = fopen("D:\\temp\\b.dat", "wb");
// for(i = 0; i < 5; i++)
// {
// fwrite(&st[i], sizeof(struct student), 1, p);
// }
fwrite(st, sizeof(struct student), 5, p);
fclose(p);
return 0;
}
3.6练习:如果一个文件保存大量数据,排序那么读取到栈中首先,堆中可以存储不了,太大了
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void swap(int *a, int *b)//交换参数的值
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void pupple(int *p, int n)//冒泡排序
{
int i;
int j;
for(i = 0; i< n; i++)
{
for(j = 1; j < n - i; j++)
{
if (p[j - 1] > p[j])
{
swap(&p[j - 1], &p[j]);
}
}
}
}
int main01(void)//在栈中建立一个数组对文件内容进行排序
{
int index = 0;//这是个计数器
int array[100] = { 0 };
char buf[100];
FILE *p = fopen("D:\\temp\\a.txt", "r");
while(!feof(p))//如果没有到达文件结尾,那么循环继续
{
memset(buf, 0, sizeof(buf));//每次读取文件一行之前都把这个buffer清空
fgets(buf, sizeof(buf), p);//从文件中读取一行
array[index] = atoi(buf);//将读取到的一行转化为int,赋值给数组成员
index++;
}
fclose(p);
pupple(array, index);//将数组排序
p = fopen("D:\\temp\\b.txt", "w");//用写的方式打开b.txt
int i;
for(i = 0; i < index; i++)
{
memset(buf, 0, sizeof(buf));//每次操作之前都把buffer清空
sprintf(buf, "%d\n", array[i]);//将数组的成员转化为字符串
fputs(buf, p);
}
fclose(p);
return 0;
}
int main(void)//在堆建立一个数组对文件内容进行排序
{
int index = 0;//这是个计数器
char buf[100];
FILE *p = fopen("D:\\temp\\a.txt", "r");//第一次打开a.txt目的是要知道这个文件有多少行
while(!feof(p))//如果没有到达文件结尾,那么循环继续,第一次循环的时候并不是要处理文件的内容,只是统计文件的行数
{
memset(buf, 0, sizeof(buf));//每次读取文件一行之前都把这个buffer清空
fgets(buf, sizeof(buf), p);//从文件中读取一行
index++;
}
fclose(p);
int *array = calloc(sizeof(int), index);//在堆中建立一个动态数组,动态数组的成员数量和a.txt文件的行一样多
p = fopen("D:\\temp\\a.txt", "r");
index = 0;//计数器从0重新开始
while(!feof(p))//如果没有到达文件结尾,那么循环继续
{
memset(buf, 0, sizeof(buf));//每次读取文件一行之前都把这个buffer清空
fgets(buf, sizeof(buf), p);//从文件中读取一行
array[index] = atoi(buf);//将读取到的一行转化为int,赋值给数组成员
index++;
}
fclose(p);
pupple(array, index);//将数组排序
p = fopen("D:\\temp\\b.txt", "w");//用写的方式打开b.txt
int i;
for(i = 0; i < index; i++)
{
memset(buf, 0, sizeof(buf));//每次操作之前都把buffer清空
sprintf(buf, "%d\n", array[i]);//将数组的成员转化为字符串
fputs(buf, p);
}
fclose(p);
return 0;
}
不用读取到堆中,使用快速排序,把数据做为数组角标索引
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main(void)
{
srand((unsigned int)time(NULL));
int i;
FILE *p = fopen("D:\\temp\\a.txt", "w");
for(i = 0; i < 100000; i++)
{
fprintf(p, "%d\n", (int)rand() % 513);
}
//文本文件,每行代表一个整数,整数是从0到512之间一个随机数
//对这个文件进行排序,不能用堆内存,只能用栈内存
fclose(p);
p = fopen("D:\\temp\\a.txt", "r");
int array[513] = { 0 };
while (!feof(p))
{
char buf[100] = { 0 };
fgets(buf, sizeof(buf), p);//得到一行
if (buf[0] != 0)//如果读取的行不是空行,那么就执行代码
{
int value = atoi(buf);//将得到的行转化为int
array[value]++;
}
}
fclose(p);
p = fopen("D:\\temp\\b.txt", "w");
int j;
for(i = 0; i < 513; i++)
{
for(j = 0; j < array[i]; j++)
{
fprintf(p, "%d\n", i);
}
}
fclose(p);
printf("end\n");
return 0;
}
//int main(void)
//{
// return 0;
//}
4. 文件的其他操作 file-fflush、remove、rename
** 如何明确调用fclose关闭一个文件,那么在进程退出以后,操作系统会自动调用fclose
--不建议
#include <stdio.h>
#include <stdlib.h>
int main01(void)
{
FILE *p = fopen("D:\\temp\\a.txt", "w");
while(1)
{
char buf[100] = { 0 };
scanf("%s", buf);
if (strcmp(buf, "exit") == 0)
break;
fprintf(p, "%s\n", buf);
fflush(p);//fflush将缓冲区的内容立刻写入文件
//优势是,不会因为停电,或者电脑死机等故障导致缓冲区的内容丢失
//不好的,硬盘读写次数增加,导致程序效率低下,同时硬盘寿命变短
//修改配置文件的时候,有时候会使用,或者做一些不经常修改的数据,但很重要数据,那么用fflush
}
fclose(p); // 调用fclose 才把数据写入到 磁盘中去
return 0;
}
int main()
{
//remove("D:\\temp\\b.txt");//删除d:\temp\b.txt
rename("D:\\temp\\c.txt", "D:\\temp\\a.txt");//将指定文件改名
return 0;
}