中国大学MOOC程序设计与算法(三):C++ 面向对象程序设计 第七周 输入输出和模板 笔记 之 文件读写(二)

第七周 输入输出和模板
1.输入输出流相关的类
2.用流操纵算子控制输出格式
3.文件读写(一)
4.文件读写(二)
5.函数模板
6.类模板
7.类模板与派生、友元和静态成员变量

4.文件读写(二)

二进制文件读写

二进制读文件:
ifstream 和 fstream的成员函数:istream& read (char* s, long n);
将文件读指针指向的地方的n个字节内容,读入到内存地址s,然后将文件读指针向后移动n字节 (以ios::in方式打开文件时,文件读指针开始指向文件开头) 。

二进制写文件:
ofstream 和 fstream的成员函数:istream& write (const char* s, long n);
将内存地址s处的n个字节内容,写入到文件中写指针指向的位置,然后将文件写指针向后移动n字节(以ios::out方式打开文件时,文件写指针开始指向文件开头, 以ios::app方式打开文件时,文件写指针开始指向文件尾部 ) 。

例子:在文件中写入和读取一个整数

#include <iostream>
#include <fstream>
using namespace std;
int main() {
	ofstream fout("some.dat", ios::out | ios::binary);
	int x=120;
	fout.write( (const char *)(&x), sizeof(int) );
	fout.close();
	
	ifstream fin("some.dat",ios::in | ios::binary);
	int y;
	fin.read((char *) (&y),sizeof(int));
	fin.close();
	cout << y <<endl;
	return 0;
}

例子:从键盘输入几个学生的姓名的成绩,并以二进制文件形式保存

#include <iostream>
#include <fstream>
using namespace std;
struct Student {
	char name[20];//20个字节
	int score;//4个字节
};
int main() {
	Student s;
	ofstream OutFile( "c:\\tmp\\students.dat",ios::out|ios::binary);
	while( cin >> s.name >> s.score )
		OutFile.write( (char * ) & s, sizeof( s) );
	OutFile.close();
	return 0;
}
输入:
Tom 60↙
Jack 80↙
Jane 40^Z↙

则形成的 students.dat 为 72(每个学生24字节)字节,用记事本打开,呈现乱码:Tom 烫烫烫烫烫烫烫烫< Jack 烫烫烫烫烫烫烫蘌 Jane 烫烫烫烫烫烫烫?
乱码的原因:Tom Jack Jane是ASCII码写入的,所以记事本打开可以识别,而60 80 40是以这个整数的二进制形式,而不是字符形式的ASCII码写入,所以记事本无法正确读它们。

例子:将 students.dat 文件的内容读出并显示

#include <iostream>
#include <fstream>
using namespace std;
struct Student {
	char name[20];
	int score;
};
int main() {
	Student s;
	ifstream inFile("students.dat",ios::in | ios::binary );
	if(!inFile) {
		cout << "error" <<endl;
		return 0;
	}
	while( inFile.read( (char* ) (&s), sizeof(s) ) ) {
		int readedBytes = inFile.gcount(); //看刚才读了多少字节
		cout << s.name << " " << s.score << endl;
	}
	inFile.close();
	return 0;
}
输出:
Tom 60
Jack 80
Jane 40

例子:将students.dat 文件的Jane的名字改成Mike

#include <iostream>
#include <fstream>
using namespace std;
struct Student {
	char name[20];
	int score;
};
int main()
{
	Student s;
	fstream iofile( "c:\\tmp\\students.dat", ios::in|ios::out|ios::binary);
	if( !iofile) {
		cout << "error" ;
		return 0;
	}
	iofile.seekp( 2 * sizeof(s),ios::beg); //定位写指针到第三个记录
	iofile.write("Mike",strlen("Mike")+1);//+1是要写入'\0'
	iofile.seekg(0,ios::beg); //定位读指针到开头
	while( iofile.read( (char* ) & s, sizeof(s)) )
		cout << s.name << " " << s.score << endl;
	iofile.close();
	return 0;
}
输出:
Tom 60
Jack 80
Mike 40

例子:文件拷贝程序mycopy 示例
/*用法示例,在命令行中运行:mycopy src.dat dest.dat 即将 src.dat 拷贝到 dest.dat 如果 dest.dat 原来就有,则原来的文件会被覆盖 */

#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char * argv[])
{
	if( argc != 3 ) {
		cout << "File name missing!" << endl;
		return 0;
	}
	
	ifstream inFile(argv[1],ios::binary|ios::in); //打开文件用于读
	if( ! inFile ) {
		cout << "Source file open error." << endl;
		return 0;
	}
	
	ofstream outFile(argv[2],ios::binary|ios::out); //打开文件用于写
	if( !outFile) {
		cout << "New file open error." << endl;
		inFile.close(); //打开的文件一定要关闭
		return 0;
	}
	char c;
	while( inFile.get(c)) //每次读取一个字符,get每次读一个字节
		outFile.put(c); //每次写入一个字符,put每次写入一个字节
	outFile.close();
	inFile.close();
	return 0;
}

内存缓冲区的作用:inFile.get每次读一个字节,但实际是将它所在的扇区(4kb or 8kb)都读到内存里,下次get直接就在内存里读了,这样就很快,避免了频繁访问硬盘。

二进制文件和文本文件的区别

标明ios::binary就是以二进制打开,不写就是以文本方式打开。
Linux,Unix下的换行符号:’\n’(ASCII码: 0x0a)
Windows 下的换行符号:’\r\n’ (ASCII码:0x0d0a),endl 就是 ‘\n’
Mac OS下的换行符号: ‘\r’ (ASCII码:0x0d)
导致 Linux, Mac OS中的文本文件在Windows 记事本中打开时不换行
Unix/Linux/Mac OS下打开文件,用不用 ios::binary 没区别
Windows下打开文件,如果不用 ios::binary,则:
(1)读取文件时,所有的 ‘\r\n’会被当做一个字符’\n’处理,即少读了一个字符’\r’。
(2)写入文件时,写入单独的’\n’时,系统自动在前面加一个’\r’,即多写了一个’\r’。
所以,在windows上读写文件时,如果这个文件类型不可以直接用记事本打开的,一定要用 ios::binary

发布了53 篇原创文章 · 获赞 4 · 访问量 2006
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章