c++文件读写之fread和fwrite

更多2019年的技术文章,欢迎关注我的微信公众号:码不停蹄的小鼠松(微信号:busy_squirrel),也可扫下方二维码关注获取最新文章哦~

#fwrite和fread基本语法#
###二进制文件和文本文件的区别###
先贴出之前看到的一篇博文:http://www.cnblogs.com/zhangjiankun/archive/2011/11/27/2265184.html
这篇博文中算是比较详细的比较了文本文件和二进制文件,我看过之后,对文本文件和二进制文件的理解就是:
1 文本文件
基于字符编码的文件,一般的都是基于ASCII码。对于平时接触到的文本编辑器,editplus或者nodepad++,在打开一个文本文件的时候,都是首先寻找该文件所在的物理地址,然后从开始位置,以8个字节为单位,转换为字符,然后显示出来(可查阅ASCII码表)。
但是,在遇到一些特殊的字符(比如’\r\n’)时,文本编辑器做出相应的操作(回车、换行)。
2.二进制文件
二进制文件是基于值存储的。不仅可以存储字符信息,也可以存一些其他的结构,不局限于文本,所有的数据类型都可以存储(比如int,double, struct结构体,甚至是类)。
但是,如果用文本编辑器去打开二进制文件,会发现是乱码。原因很简单,因为文本编辑器总是定长的去识别0、1序列,遇到8个比特,就进行字符转化。而二进制文件是不定长的,比如,如果要存储一个int类型的数据,这时候需要用4个字节来表示该数据,eg:int a = 1; 其对应的二进制值00000000 00000000 00000000 00000001,这时候,文本编辑器就会解析为:NUL NUL NUL SOH。
其实,文本文件和二进制文件在物理存储上没什么区别,都是0、1序列。只是读取规则不同。
###fread & fwrite语法###
fread(object &obj, int size, int count, FILE *fp);
fwrite(object &obj, int size, int count, FILE *fp);
这两个函数总是配对使用。fwrite函数往里写的时候都是以二进制值的形式写入的,而最终该文件要以文本文件读出还是以二进制文件读出,取决于读该文件的函数。
对于fread函数,可以先用fseek函数将文件的位置指针放在序列最后,这样就可以用ftell函数得到该文件的长度(单位为字节),然后使用rewind函数使得光标复位,即回到文件开始处位置。
这里首先给出一个例子:我要往文件当中写入一个int类型的数据,int b = 2; 文件是放在工程的根目录下,文件名为text.txt.

代码如下:

#include<iostream>
using namespace std;

/*
*/
void write(int *p, char *path) {
	FILE *fp;
	if ((fp = fopen(path, "wb")) == NULL) {
		cout << "文件打开失败!" << endl;
		exit(0);
	}

	if (fwrite(p, sizeof(int), 1, fp) != 1) {
		cout << "写入失败!" << endl;
	}
	fclose(fp);
}

int read(char *path) {
	int a;
	FILE *fp;
	if ((fp = fopen(path, "r")) == NULL) {
		cout << "文件打开失败!" << endl;
	}

	fseek(fp, 0L, SEEK_END);
	int len = ftell(fp);
	rewind(fp);

	if (fread(&a, 1, len, fp) != len) {
		cout << "读取失败" << endl;
	}
	fclose(fp);

	return a;
}

int main() {
	//char *name = "I'm a student.李雷";
	char *path = "./test.txt";
	int b = 22;
	write(&b, path);

	//char *content;
	int a;
	a = read(path);

	cout << "content:" << a << endl;

	return 0;
}

代码中,只是把一个int类型的值22以二进制的方式放在了文件text.txt中,然后再读取该文件,并将读取结果打印到控制台。首先打开text.txt来看一下:
这里写图片描述
会发现是乱码,但是用函数fread()读取文件,可以还原文件的存取内容,下图是读取结果:
这里写图片描述
如果这里往test.txt中存取的是字符串,就同文本写入一样了。
这里给出写、读字符串的代码:

#include<iostream>
using namespace std;

/*
*/
void write(char *name, char *path) {
	FILE *fp;
	if ((fp = fopen(path, "wb")) == NULL) {
		cout << "文件打开失败!" << endl;
		exit(0);
	}

	if (fwrite(name, sizeof(char), strlen(name) + 1, fp) != (strlen(name) + 1)) {
		cout << "写入失败!" << endl;
	}
	fclose(fp);
}

char *read(char *path) {
	static char content[100];
	FILE *fp;
	if ((fp = fopen(path, "r")) == NULL) {
		cout << "文件打开失败!" << endl;
	}

	fseek(fp, 0L, SEEK_END);
	int len = ftell(fp);
	rewind(fp);

	if (fread(content, 1, len, fp) != len) {
		cout << "读取失败" << endl;
	}
	fclose(fp);

	return content;
}

int main() {
	char *name = "I'm a student.李雷";
	char *path = "./test.txt";
	write(name, path);

	char *content;
	content = read(path);

	cout << "content:" << content << endl;

	return 0;
}

也可以读取struct结构体,即把结构体的对象作为一个整体,存入文件当中。

#include<iostream>
using namespace std;
#define SIZE 1

struct attribute{
	int element;
	attribute *next;
};

struct test {
	char name[20];
	int age;
	attribute *head;
};

/*
	将信息以二进制的方式写入txt文件中
*/
void write(test *p1, char *path) {
	FILE *fp;
	if ((fp = fopen(path, "w")) == NULL) {
		cout << "Can't open this file!" << endl;
		exit(0);
	}
	for (int i = 0; i < SIZE; i++) {
		if (fwrite(p1, sizeof(struct test), 1, fp) != 1) {
			cout << "file write error!" << endl;
		}
	}
	fclose(fp);
}

/*
	读文件
*/
void read(test *p1, char *path) {
	FILE *fp;
	if ((fp = fopen(path, "r")) == NULL) {
		cout << "can't open this file!!" << endl;
		exit(0);
	}

	char buffer[100];
	fseek(fp, 0L, SEEK_END);	//将文件的位置指针放在最后
	int len = ftell(fp);	//得到文件中所有文本的长度
	rewind(fp);		//重新恢复位置指针的位置,回到文件的开头

	for (int i = 0; i < SIZE; i++) {
		if (fread(p1, sizeof(test), 1, fp) != 1) {
			cout << "can't read this file." << endl;
		}

		cout << "name:" << p1->name << "\t" << "age:" << p1->age << endl;
	}
	fclose(fp);
}

/*
	创建链表
*/
attribute *createLink(int *element, int count){
	attribute *head = new attribute;
	head->next = NULL;
	attribute *tail;
	attribute *newNode;

	for (int i = 0; i < count; i++) {
		newNode = new attribute;
		newNode->next = NULL;
		if (head->next == NULL) {
			head->next = newNode;
		} else {
			tail->next = newNode;
		}
		tail = newNode;
	}

	return head;
}

int main() {

	int *element;
	element = (int *)malloc(sizeof(int) * 2);	//动态申请2个int大小的空间
	for (int i = 0; i < 2; i++) {
		element[i] = i + 1;
	}

	test *p;
	char *path = "./sss.txt";
	for (int i = 0; i < SIZE; i++) {
		p = new test;
		cin.getline(p->name, 20);	//输入姓名和年龄
		cin >> p->age;
		getchar();
		p->head = createLink(element, 2);
	}
	write(p, path);

	read(p, path);

	return 0;
}

sss.txt中仍然是乱码:
这里写图片描述

如果以16进制查看该文件,可看到如下结果:
这里写图片描述

更多2019年的技术文章,欢迎关注我的微信公众号:码不停蹄的小鼠松(微信号:busy_squirrel),也可扫下方二维码关注获取最新文章哦~

在这里列出与之相关的资料:

  1. http://www.cnblogs.com/zhangjiankun/archive/2011/11/27/2265184.html
  2. http://www.cnblogs.com/witxjp/archive/2011/03/21/1990519.html
  3. http://blog.csdn.net/athenaer/article/details/7876614
  4. http://blog.csdn.net/kingstar158/article/details/6859379
  5. http://blog.csdn.net/borenbao/article/details/849640
  6. http://www.cnblogs.com/witxjp/archive/2011/03/21/1990519.html
  • 21
    点赞
  • 103
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值