10.C语言(文件操作)
1.FILE*文件指针讲解
FILE所有平台得名字都一样,FILE是一个结构体类型,里面得成员功能一样,不同平台成员得名字不一样,这个结构体可以在stdio.h中找到
typedef struct {
//缓冲区“满”或者“空”得程度
short level;
//文件状态标志
unsigned flags;
//文件描述符
char fd;
//如无缓冲区不读取字符
unsigned char hold;
//缓冲区大小
short bsize;
//数据缓冲区得位置
unsigned char *buf;
//指针,当前得指向
unsigned ar;
//临时文件,指示器
unsigned istemp;
//用于有效性得检查
short token;
}FILE;
FILE *fp
1.fp指针,调用fopen(),在堆区分配空间,把地址返回给fp
2.fp指针不是指向文件,fp指针和文件关联,fp内部成员保存了文件得状态
3.操作fp指针,不能像一般指针类型那样操作,比如说*fp操作内存等等,必须通过文件库函数进行操作
4.通过库函数操作fp指针,对文件得任何操作,fp里面成员会相应得变化(系统自动完成)
2.文件分类
1)磁盘文件
指一组相关数据的有序集合,通常存储在外部介质上(磁盘),使用时才调入内存
2)设备文件
在操作系统中把每一个与主机相连得输入输出设备看作是一个文件,把对他们得输入输出等同于对磁盘文件得读和写
3)从用户或者操作系统使用的角度(逻辑上)把文件分为:
文本文件:基于字符编码的文件
二进制文件:基于值编码得文件
特殊的文件指针
由系统默认打开,用户无需定义即可直接使用
stdin:标准输入,默认为当前终端(键盘),我们使用得scanf,getchar函数默认从此终端获取数据
stdout:标准输出,默认当前终端(屏幕),我们使用得printf,puts函数默认输出信息到此终端
stderr:标准出错,默认为当前终端(屏幕),我们使用得perror函数默认输出信息到此终端
关闭标准函数指针后
//#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
//1.关闭标准输出函数指针,导致无法再打印到屏幕
printf("aaaaaaaaaaa\n");
fclose(stdout);
printf("bbbbbbbbbb\n");
//2.关闭标准错误函数指针,导致无法打印错误信息
perror("ren");
fclose(stderr);
perror("zhen");
//2.关闭标准输入函数指针,导致无法再输入
int a = 10;
printf("a = %d\n", a);
printf("请输入a\n");
fclose(stdin);
scanf("%d", &a);
printf("a = %d\n", a);
system("pause");
}
#include <stdio.h>
#include <unistd.h>
int main() {
//printf函数的内部实现,是往标准输出设备1写内容
printf("before close..");
//fclose(stdout);
//1代表标准输出设备,关闭了,1就是空闲的数组
close(1);
//打印一下你会发现fd值就是1
int fd = open("01.txt",O_WRONLY,0777);
//printf函数的内部实现,往1写内容,但是1现在和01.txt关联
//所以会把内容写入到01.txt中
printf("fd = %d\n",fd);
printf("after close bbbbbbbb");
system("pause");
}
3.打开文件fopen
任何文件使用之前都要先打开
#include <stdio.h>
FILE *fopen(const char *filename,const char *mode);
参数:
filename:需要打开的文件名,根据需要加上路径
mode:打开文件的模式设置
返回值:文件指针,失败返回NULL
w:如果文件不存在,新建,如果文件存在,清空文件再打开
r:如果文件不存在,打开失败
a:如果文件不存在,新建,如果文件存在,将光标放在文件末尾并打开
//fopen不安全
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
FILE *fp = NULL;
fp = fopen("./a.txt","r");
if (fp == NULL) {
perror("open failed:");
return 0;
}
fclose(fp);
fp = NULL;
system("pause");
}
4.相对路径
相对路径相对于可执行程序,在不同平台各有各的规则
VS:
a.编译同时运行程序,相对路径相对于xxx.vcxproj(项目文件)所在的目录
b.如果直接运行程序,相对路径,相对于debug文件夹所在的目录
Qt:
a.编译同时运行程序,相对路径相对于debug所在的路径
b.如果直接运行程序,相对路径相对于可执行程序
5.写文件fputc() [按照字符写]
include <stdio.h>
int fputc(int ch,FILE *stream);
功能:将ch转换为unsigned char 后写入stream指定的文件中
参数:
ch:需要写入的文件字符
stream:文件指针
返回值:
成功:返回成功写入的字符
失败:返回-1
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
//1.打开文件
FILE *fp = NULL;
fp = fopen("D:/b.txt","w");
if (fp == NULL) {
perror("open failed:");
return 0;
}
//2.写入文件,fputc一次只能写一个字符
fputc('a', fp);
fputc('b', fp);
fputc('c', fp);
fputc('d', fp);
//3.关闭文件
fclose(fp);
fp = NULL;
system("pause");
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
//1.打开文件
FILE *fp = NULL;
fp = fopen("D:/b.txt","w");
if (fp == NULL) {
perror("open failed:");
return 0;
}
//2.写入文件,fputc一次只能写一个字符
char ch = 'a';
while (ch < 'z') {
fputc(ch, fp);
ch++;
}
char buf[] = "ABCDEF";
int i = 0;
//获取数组长度等价于 sizeof(buf)/sizeof(buf[0]),
// 因为char只占一个字节,可以这样计算
int n = strlen(buf);
for (; i < n; i++) {
fputc(buf[i], fp);
}
//3.关闭文件
fclose(fp);
fp = NULL;
system("pause");
}
6.读文件fgetc() [按照字符读]
include <stdio.h>
int fgetc(FILE *stream);
功能:从stream指定的文件中读取一个字符
参数:
stream 文件指针
返回值:
成功返回读取到的字符
失败返回-1
注意,如果在写入完成后立即进行文件读取(没有重新以r的形式打开文件),是读不到内容的,如下这种方式不行
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
//1.打开文件
FILE *fp = NULL;
fp = fopen("D:/b.txt","w");
if (fp == NULL) {
perror("open failed:");
return 0;
}
//2.写入文件,fputc一次只能写一个字符
char ch = 'a';
while (ch < 'z') {
fputc(ch, fp);
ch++;
}
//3.读取写入的字符
char temp;
while (1) {
temp = fgetc(fp);
printf("ch = %s\n", temp);
if (temp == EOF) {
break;
}
}
char buf[] = "ABCDEF";
int i = 0;
//获取数组长度等价于 sizeof(buf)/sizeof(buf[0]),
// 因为char只占一个字节,可以这样计算
int n = strlen(buf);
for (; i < n; i++) {
fputc(buf[i], fp);
}
//3.关闭文件
fclose(fp);
fp = NULL;
system("pause");
}
只有在写入完成后关闭这个文件,然后重新以只读的形式打开才能读取到
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
//1.打开文件
FILE *fp = NULL;
fp = fopen("D:/b.txt","w");
if (fp == NULL) {
perror("open failed:");
return 0;
}
//2.写入文件,fputc一次只能写一个字符
char ch = 'a';
while (ch < 'z') {
fputc(ch, fp);
ch++;
}
char buf[] = "ABCDEF";
int i = 0;
//获取数组长度等价于 sizeof(buf)/sizeof(buf[0]),
// 因为char只占一个字节,可以这样计算
int n = strlen(buf);
for (; i < n; i++) {
fputc(buf[i], fp);
}
//3.关闭文件
fclose(fp);
fp = NULL;
FILE *fp2 = NULL;
fp2 = fopen("D:/b.txt", "r");
if (fp2 == NULL) {
perror("open failed:");
return 0;
}
//3.读取写入的字符
char temp;
while (1) {
temp = fgetc(fp2);
printf("ch = %d\n", temp);
if (temp == EOF) {
break;
}
}
system("pause");
}
7.判断文件结尾的方式
1).如果是文本文件,可以通过-1(EOF)判断文件是否结尾
2).如果是二进制文件,不能以-1判断文件结尾
3).feof()判断文件是否在结尾,任何文件都能判断
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
//1.打开文件
FILE *fp = NULL;
fp = fopen("D:/b.txt", "w");
if (fp == NULL) {
perror("open failed:");
return 0;
}
//2.写入文件,fputc一次只能写一个字符
fputc('a',fp);
fputc('c', fp);
fputc('d', fp);
fputc('-1', fp);
fputc('e', fp);
fputc('-1', fp);
fputc('f', fp);
//3.关闭文件
fclose(fp);
fp = NULL;
FILE *fp2 = NULL;
fp2 = fopen("D:/b.txt", "r");
if (fp2 == NULL) {
perror("open failed:");
return 0;
}
//4.读取写入的字符
char temp;
while (1) {
temp = fgetc(fp2);
printf("ch = %d\n", temp);
if (feof(fp2)) {
break;
}
}
system("pause");
}
feof(FILE *fp):如果到文件结尾,返回真
1)如果第一次没有对文件进行读操作,直接调用此函数永远返回真
2)此函数只有先读取文件再调用才有意义
3)调用此函数,文件状态中当前所在位置不会往后移动
4)必须读取后,才能判断是否结束,判断的是当前读取的字符
上边的程序稍作改动就可以验证这一点,去掉fputc的那行代码,你会发现,没有读取的操作,就用于不会到文件结尾
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
//1.打开文件
FILE *fp = NULL;
fp = fopen("D:/b.txt", "w");
if (fp == NULL) {
perror("open failed:");
return 0;
}
//2.写入文件,fputc一次只能写一个字符
fputc('a', fp);
fputc('c', fp);
fputc('d', fp);
fputc('-1', fp);
fputc('e', fp);
fputc('-1', fp);
fputc('f', fp);
//3.关闭文件
fclose(fp);
fp = NULL;
FILE *fp2 = NULL;
fp2 = fopen("D:/b.txt", "r");
if (fp2 == NULL) {
perror("open failed:");
return 0;
}
//4.读取写入的字符
char temp;
while (1) {
//temp = fgetc(fp2);
printf("文件没有到结尾\n");
if (feof(fp2)) {
break;
}
}
system("pause");
}
8.使用fgetc完成简单的cat命令
将此代码编译成一个可执行文件,然后像cat 文件名 那样运行,就可以实现我们自己定义的cat命令,cat其实内部也是这样实现的
#include <stdio.h>
int main(int argc,char *argv[]) {
//打开文件
FILE *fp = fopen(argv[1], "r");
//读取文件内容显示到屏幕
char ch;
while (1) {
ch = fgetc(fp);
if (feof(fp))
{
break;
}
printf("%c", ch);
}
//关闭文件
fclose(fp);
}
9.使用fputc fgets完成简单的vi命令
#include <stdio.h>
int main(int argc,char *argv[]) {
//以写的方式打开一个文件
FILE *fp = fopen(argv[1], "w");
//从键盘读取内容使用fgets()(按行读取,以换行符为结尾),
//因为scanf遇到空格和回车会结束,gets遇到回车会结束,所以不适合这个场景
//读取到字符后,一个一个写入文件
char buf[1024];
while (1) {
//默认遇到换行符结束读取,换行符都放在buf
fgets(buf, sizeof(buf), stdin);
//如果用户输入内容为:wq,结束,保存文件
//比较前3个字符是否相同
if (strncmp(buf,":wq",3))
{
break;
}
int i = 0;
while (buf[i] != '\0') {
fputc(buf[i], fp);
i++;
}
}
fclose(fp);
}
10.fputs的使用 [按照行写]
#include <stdio.h>
int main() {
FILE *fp = fopen("ren.txt", "w");
//指针数组,指针组成的数组,它的每个元素都是指针
char *p[] = {"hello\n","world\n","beauty\n"};
int i = 0;
int n = sizeof(p) / sizeof(p[0]);
for (i = 0; i < n; i++) {
fputs(p[i], fp);
}
fclose(fp);
}
11.fgets的使用 [按照行读]
可以看到打印结果中最后一个字符串打印了两次,为什么会这样呢,其实这时feof函数的问题,feof函数必须先读取然后才能判断是否到达末尾。也就是说,都是先读取一次,再判断一次,当读取到最后一个的时候,读取+判断,还没有到达末尾,然后再次读取+判断,而此时由于没有内容可以读取了,但是文件缓冲区中还有一个保存的上次读取到的内容,所以会把上次的东西再打印一次,导致beauty打印了两次,所以最好是将结尾的判断放在打印的前边,避免重复打印
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
FILE *fp = fopen("ren.txt", "w");
//指针数组,指针组成的数组,它的每个元素都是指针
char *p[] = {"hello\n","world\n","beauty\n"};
int i = 0;
int n = sizeof(p) / sizeof(p[0]);
for (i = 0; i < n; i++) {
fputs(p[i], fp);
}
fclose(fp);
FILE *read = fopen("ren.txt", "r");
char buf[100];
//1.从fp关联的文件读取内容,放到buf中,一次最大读取sizeof(buf)-1
//2.遇到换行符,文件到达结尾,结束本地读取
while (1) {
fgets(buf, sizeof(buf), fp);
printf("buf = %s", buf);
if (feof(read)) {
break;
}
}
fclose(read);
system("pause");
}
打印结果
buf = hello
buf = world
buf = beauty
buf = beauty
请按任意键继续. . .
正确的读取方式
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
FILE *fp = fopen("ren.txt", "w");
//指针数组,指针组成的数组,它的每个元素都是指针
char *p[] = {"hello\n","world\n","beauty\n"};
int i = 0;
int n = sizeof(p) / sizeof(p[0]);
for (i = 0; i < n; i++) {
fputs(p[i], fp);
}
fclose(fp);
FILE *read = fopen("ren.txt", "r");
char buf[100];
//1.从fp关联的文件读取内容,放到buf中,一次最大读取sizeof(buf)-1
//2.遇到换行符,文件到达结尾,结束本地读取
while (1) {
fgets(buf, sizeof(buf), fp);
if (feof(read)) {
break;
}
printf("buf = %s", buf);
}
fclose(read);
system("pause");
}
打印
buf = hello
buf = world
buf = beauty
请按任意键继续. . .
12.feof()判断文件结尾标准写法
这样的写法既可以保证不会重复打印最后一个字符串,也可以保证在最后一个字符串不管是不是存在换行符的情况下,都能正确打印
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void write_file() {
FILE *fp = fopen("1.txt","w");
fputs("10+10 = \n", fp);
fputs("10-10 = \n", fp);
fputs("10*10 = \n", fp);
fputs("10/10 = \n", fp);
fputs("10+5 = \n", fp);
fputs("10-5 = \n", fp);
fputs("10*3 = \n", fp);
fclose(fp);
}
void read_file() {
FILE *fp = fopen("1.txt", "r");
char buf[1024];
while (1) {
//fgets在文件中读取一行放在buf数组中,为了防止读取到文件末尾
//读取到空时再次打印buf缓冲区中上一次读到的内容,每次读取之前
//先清空一次
//sizeof(buf)数组的大小 1024
memset(buf, 0, sizeof(buf));
fgets(buf, sizeof(buf), fp);
//直接这样打印,导致一个问题,读取到结尾后仍然会在最后打印一个kong,
//所以我们加一层判断,如果buf为空的时候就不再打印
//printf("buf = %s\n", buf);
if (strlen(buf) > 0) {
printf("buf = %s\n", buf);
}
if (feof(fp)) {
break;
}
}
}
int main() {
write_file();
read_file();
system("pause");
}
打印
buf = 10+10 =
buf = 10-10 =
buf = 10*10 =
buf = 10/10 =
buf = 10+5 =
buf = 10-5 =
buf = 10*3 =
请按任意键继续. . .
13.提取文件中运算并得出结果重新写入文件
这段代码首先将一些四则运算以“a运算符b=“的规则写入到一个文件中,我们要做的就是把这些运算得出结果并重新写入这个文件,具体的思路就是使用fgets一行一行的从文件中读取内容,读取出来之后按照我们设定的规则“%d%c%d=\n”从每行中提取其中参与计算的ab两个值和运算符,这样我们就可以得到运算结果,有了运算结果然后再将它们格式化成一个字符串,一个一个的将这些包含运算结果的字符串重新写入文件中即可完成。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void write_file() {
FILE *fp = fopen("1.txt","w");
fputs("10+10 = \n", fp);
fputs("10-10 = \n", fp);
fputs("10*10 = \n", fp);
fputs("10/10 = \n", fp);
fputs("10+5 = \n", fp);
fputs("10-5 = \n", fp);
fputs("10*3 = \n", fp);
fclose(fp);
}
int calc(int a, int b, char ch) {
switch (ch)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a*b;
case '/':
return a / b;
default:
return 0;
}
return 0;
}
void read_file() {
FILE *fp = fopen("1.txt", "r");
char buf[1024];
char temp[1024 * 4] = {0};
while (1) {
//fgets在文件中读取一行放在buf数组中,为了防止读取到文件末尾
//读取到空时再次打印buf缓冲区中上一次读到的内容,每次读取之前
//先清空一次
//sizeof(buf)数组的大小 1024
memset(buf, 0, sizeof(buf));
fgets(buf, sizeof(buf), fp);
//直接这样打印,导致一个问题,读取到结尾后仍然会在最后打印一个空,
//所以我们加一层判断,如果buf为空的时候就不再打印
//printf("buf = %s\n", buf);
if (strlen(buf) > 0) {
//printf("buf = %s\n", buf);
int a, b;
char ch;
sscanf(buf, "%d%c%d=\n", &a, &ch, &b);
//printf("%d%c%d=%d\n", a, ch, b,calc(a,b,ch));
sprintf(buf,"%d%c%d=%d\n", a, ch, b, calc(a, b, ch));
strncat(temp,buf,sizeof(buf));
printf(temp);
printf("---------------------\n");
}
if (feof(fp)) {
break;
}
}
printf("---------------------\n");
printf(temp);
fclose(fp);
//关闭文件后,重新以w方式打开文件,目的是清空文件
//然后将含有计算结果的内容写入,这一整个流程下来,
//就将计算结果和四则运算表达式一块写了进去
fp = fopen("1.txt", "w");
fputs(temp, fp);
fclose(fp);
}
int main() {
write_file();
read_file();
system("pause");
}
14.提取文件中所有数字并进行排序后重新写入文件
假设文件中数据如下
12
34
1
43
34
2
32
454
76
4565
3
43
2342
2
34
35
4564
6
54
65
67
5
52434
32
5
4
6
546
5
467
5
7
54
35
45
2
43
34
23
543
25
43
6
54
645
67
54
76
57
56
78
4
63
4543
452
3
4
32
42
34
23
4
35
43
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void read_file() {
FILE *fp = fopen("1.txt", "r");
char buf[1024];
int temp[1024 * 4] = { 0 };
int i = 0;
while (1) {
memset(buf, 0, sizeof(buf));
fgets(buf, sizeof(buf), fp);
if (strlen(buf) > 0) {
int a;
sscanf(buf, "%d", &a);
//printf("a= %d\n", a);
temp[i] = a;
i++;
}
if (feof(fp)) {
break;
}
}
//数组元素个数
int n = i;
printf("数组元素个数:%d\n", n);
printf("排序前的数组:");
for (i = 0; i < n; i++) {
printf("%d,", temp[i]);
}
int j = 0;
int k = 0;
//排序
int value = 0;
for (j = 0; j < n; j++) {
for (k = 0; k < n - 1 - j; k++) {
if (temp[k] > temp[k + 1]) {
value = temp[k];
temp[k] = temp[k + 1];
temp[k + 1] = value;
}
}
}
printf("\n排序后的数组:");
for (i = 0; i < n; i++) {
printf("%d,", temp[i]);
}
if (fp != NULL) {
fclose(fp);
fp = NULL;
}
//重新打开文件写入
char arr[1024 * 4] = {0};
fp = fopen("1.txt", "w");
for (i = 0; i < n; i++) {
sprintf(buf, "%d,", temp[i]);
strncat(arr, buf, sizeof(buf));
}
fputs(arr, fp);
if (fp != NULL) {
fclose(fp);
fp = NULL;
}
}
int main() {
read_file();
system("pause");
}
打印结果
数组元素个数:64
排序前的数组:12,34,1,43,34,2,32,454,76,4565,3,43,2342,2,34,35,4564,6,54,65,67,5,52434,32,5,4,6,546,5,467,5,7,54,35,45,2,43,34,23,543,25,43,6,54,645,67,54,76,57,56,78,4,63,4543,452,3,4,32,42,34,23,4,35,43,
排序后的数组:1,2,2,2,3,3,4,4,4,4,5,5,5,5,6,6,6,7,12,23,23,25,32,32,32,34,34,34,34,34,35,35,35,42,43,43,43,43,43,45,54,54,54,54,56,57,63,65,67,67,76,76,78,452,454,467,543,546,645,2342,4543,4564,4565,52434,请按任意键继续. . .
1.txt文件中:
1,2,2,2,3,3,4,4,4,4,5,5,5,5,6,6,6,7,12,23,23,25,32,32,32,34,34,34,34,34,35,35,35,42,43,43,43,43,43,45,54,54,54,54,56,57,63,65,67,67,76,76,78,452,454,467,543,546,645,2342,4543,4564,4565,52434,
15.fprintf() [按照格式化文件写]
#include <stdio.h>
int fprintf(FILE *stream,const char &format,...);
根据参数format来转换并格式化数据,然后将结果输出到stream指定的文件中,指定出现字符串结束符为止
对比一下:
printf :操作屏幕 stdout流,向屏幕输出内容
sprintf :格式化字符串保存在数组中
fprintf :格式化字符串写入文件中
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include<time.h>
int main() {
//以写的方式打开文件
FILE *fp = fopen("1.txt","w");
//fprintf写入
int i = 0;
int n = 10;
int num = 0;
//设置随机种子
srand((unsigned int)time(NULL));
for (i = 0; i < n; i++) {
//产生10个1000以内的随机数
num = rand() % 1000;
//输出到屏幕
//printf("%d\n", num);
//比fputc fputs更方便,如果使用他们,需要先以只读的方式打开文件
//然后都到一个写入一个,而使用fprintf则可以一步到位
//输出到文件
fprintf(fp, "%d\n", num);
}
//关闭文件
if (fp != NULL)
{
fclose(fp);
fp = NULL;
}
system("pause");
}
16.fscanf [按照格式化文件读](同样注意feof文件结尾产生的问题)
从文件中按照某种格式读取内容,fpintf是将内容按某种格式写入文件
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
//以写的方式打开文件
FILE *fp = fopen("1.txt","r");
int num;
while (1) {
fscanf(fp, "%d\n", &num);
printf("num = %d\n", num);
if (feof(fp))
{
break;
}
}
//关闭文件
if (fp != NULL)
{
fclose(fp);
fp = NULL;
}
system("pause");
}
17.fwrite[按照块写文件]
#include <stdio.h>
size_t fwrite(const void*ptr,size_t size,size_t nmemb,FILE*stream);
以数据块的方式给文件写入内容
ptr:准备写入文件数据的地址
size: size_t 为unsigned int类型,此参数指定写入文件内容的块数据大小
nmemb:写入文件的块数,写入文件数据总大小为size*nmemb
stream:已经打开的文件指针
执行成功返回写入文件数据的块数目,和nmemb相等
失败返回0
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//定义一个结构体,sizeof = 60
typedef struct Student {
int age;
char name[50];
int score;
} Student;
int main() {
FILE *fp = fopen("1.txt", "w");
Student s = { 18,"zhangsan",59 };
//结构体大小为60,使用下边几种方式把结构体中内容写入文件,你会发现
//结果是相同的,使用fwrite进行写入,是按照一块一块写的,你可以分成
//好多块去写,但是最终的结果都是一样的
//int result = fwrite(&s, 15, 4, fp);
//int result = fwrite(&s, 20, 3, fp);
//int result = fwrite(&s, 1,sizeof(Student), fp);
int result = fwrite(&s, sizeof(Student), 1, fp);
printf("result=%d,sizeof(Student)=%d\n", result, sizeof(Student));
fclose(fp);
system("pause");
}
18.fread[按照块读文件]
#include <stdio.h>
size_t fread(void *ptr,size_t size,size_t nmemb,FILE *stream);
以数据块的方式从文件中读取内容
ptr:存放读取出来的数据的内存空间
size:size_t为unsigned int 类型,此参数指定读取文件内容的块数据大小
nmemb:读取文件的块数,读取文件总数据大小为:size*nmemb
stream:已经打开的文件指针
执行成功,返回实际成功读取到内容的块数,如果此值比nmemb小,但大于0,说明督导文件的结尾,失败则返回0
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//定义一个结构体,sizeof = 60
typedef struct Student {
int age;
char name[50];
int score;
} Student;
int main() {
//写入
FILE *fp = fopen("1.txt", "w");
Student s = { 18,"zhangsan",59 };
int result = fwrite(&s, sizeof(Student), 1, fp);
printf("result=%d,sizeof(Student)=%d\n", result, sizeof(Student));
fclose(fp);
//读取
FILE *fp2 = fopen("1.txt", "r");
Student s2[10];
int net = fread(s2, sizeof(Student), 1, fp2);
printf("net = %d\n", net);
printf("%d,%s,%d\n", s2->age, s2->name, s2->score);
system("pause");
}
19.fread fwrite结合实现拷贝命令
先使用gcc编译成可执行文件,然后就可以在Linux命令行中使用命令拷贝了。这是在Linux命令行下的代码,可以执行,那么如果在windows确是优点差别的,Windows下需要将打开文件的r w改为rb wb才行,并且这种方式在Linux下也是可行的,所以为了兼容两个平台,最好将r w 都写作rb wb。为什么r 和w的写法在windows不行呢,因为如果不是rb wb Windows在打开文件的时候会把文件当作文本文件处理,所以如果遇到特殊字符就会有问题
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
/*
模仿Linux cp命令 cp 源文件 目标文件
第一个参数是不需要我们传入的,我们传入的参数
会被放入argv这个数组中
*/
int main(int argc,char *argv[]) {
//第一个参数是cp 第二个参数是要拷贝的源文件路径
//第三个参数是要拷贝到的目标文件
//argc表示参数的个数
if (argc != 3)
{
printf("error:参数不正确");
return 0;
}
//打开源文件
FILE *src = fopen(argv[1], "r");
//打开目标文件
FILE *dst = fopen(argv[2], "w");
//从源文件中读取内容写入到目标文件
char buf[4 * 1024];
int len;
while (1) {
len = fread(buf, 1, sizeof(buf), src);
printf("len = %d\n", len);
if (len == 0) {
break;
}
fwrite(buf, 1, len, dst);
}
//关闭文件
fclose(src);
fclose(dst);
system("pause");
}
20.Linux和Windows下文本的区别
为什么会发生上边那种问题,其实是因为Windows和Linux针对文本的不同处理导致的
b是二进制模式的意思,b只是在Windows有效,在Linux用r和rb的结果是一样的
Unix和Linux下所有的文本文件行都是\n结尾,而Windows所有文本文件都是\r\n结尾
在Windows平台下,以文本的方式打开文件时,不加b:
当读取文件的时候,系统会将所有的\r\n转换成\n
当写入文件的时候,系统会将\n转换成\r\n写入
当以二进制的方式打开文件,则读写都不会进行这样的转换
在Unix/Linux平台下,文本与二进制模式没有区别,\r\n作为两个字符原样输入输出
21.判断当前平台是Windows还是Linux
1.png22.文件的随机读写
fseek
#include <stdio.h>
int fseek(FILE *stream,long offset,int whence);
功能:移动文件流(文件光标)的读写位置
参数:stream 已经打开的文件指针
offset 根据whence来移动的位移数(偏移量),可以是正数也可以是负数,如果是整数,则相对于whence往右移动,如果是负数,则相对于whence往左移动,如果向前移动的字节数超大过了文件开头则出错返回,如果向右移动的字节数超过了文件末尾,再次写入时将增大文件尺寸
whence 取值如下
SEEK_SET 从文件开头移动offset个字节
SEEK_CUR 从当前位置移动offset个字节
SEEK_END 从文件末尾移动offset个字节
返回值:成功0,失败-1
fseek(fp,0,SEEK_SET) :在开头偏移0个字节,也就是回到文件开始的位置
fseek(fp,100,SEEK_SET):在开头向右偏移100个字节
fseek(fp,100,SEEK_CUR):在当前位置向右偏移100个字节
fseek(fp,-100,SEEK_CUR):在当前位置左右偏移100个字节
fseek(fp,0,SEEK_END):移动到文件结尾
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(int argc,char *argv[]) {
FILE *fp = fopen("1.txt","r");
//文件中写了一个单词hello,偏移一个后读取,得到的就是e
fseek(fp, 1, SEEK_SET);
char arr[100];
fread(arr, 1, 1, fp);
printf("读取到一个字节:%c\n", arr[0]);
fseek(fp, 0, SEEK_SET);
fread(arr, 1, 1, fp);
printf("回到开头后读取到一个字节:%c\n", arr[0]);
char arr2[100];
fseek(fp, 4, SEEK_SET);
fread(arr2, 1, 1, fp);
printf("读取到最后一个字节:%c\n", arr2[0]);
rewind(fp);
char arr3[100];
fseek(fp, 0, SEEK_CUR);
fread(arr3, 1, 1, fp);
printf("rewind读取到最一个字节:%c\n", arr3[0]);
//获取文件大小要将光标移动到最后
fseek(fp, 0, SEEK_END);
printf("文件大小:%d\n",ftell(fp));
fclose(fp);
system("pause");
}
ftell
#include <stdio.h>
long ftell(FILE *stream);
获取文件流(文件光标)的读写位置
参数
stream 已经打开了的文件指针
返回值
成功 返回当前文件流位置
失败-1
#######rewind
#include <stdio.h>
void rewind(FILE *stream);
把文件流的读写位置移动到文件开头
23.获取文件状态
#include <sys/types.h>
#include <sys/stat.h>
int stat(const char *path,struct stat *buf);
struct stat
{
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink; //连到该文件的硬链接数据,刚建立的文件值为1
uid_t st_uid; //用户id
gid_t st_gid; //组id
dev_t st_rdev; //设备类型,若此文件为设备文件,则为其编号
off_t st_size; //文件字节数(文件大小)
unsigned long st_blksize;//块大小(文件系统的IO缓冲区大小
unsigned long st_blocks;//块数
time_t st_atime; //最后一次访问时间
time_t st_mtime;//最后一次修改时间
time_t st_ctime;//最后一次改变时间,指属性
};
获取文件的状态信息
参数 path 文件名
buf 保存文件信息的结构体
返回值成功0 失败-1
删除文件,重命名文件
#include <stdop.h>
int remove(const char *pathname);
删除文件
参数pathname:文件名
返回值:0成功 -1失败
#include <stdio.h>
int rename (const char *oldpath,const char *newpath);
把oldpath的文件名改为newpath
成功0 失败-1
刷新缓冲区
#include <stdio.h>
int fflush(FILE *stream);
更新缓冲区,让缓冲区数据立马写入文件中
成功0 失败-1
未完,待续....