文件读写

1、文件的基本内容

(1)文件和流的关系

可以将顺序文件看作一个有限字符构成的顺序字符流,然后像对
cin, cout 一样的读写。

(2)创建文件

方式一:创建时直接关联文件(初始化)

#include <fstream> // 包含头文件
	ofstream outFile(“clients.dat”, ios::out|ios::binary);//创建文件

参数:

  • clients.dat”
    要创建的文件的名字
  • 文件打开方式:
    • ios:out:输出到文件, 删除原有内容。
    • ios::app:输出到文件, 保留原有内容,总是在尾部添加。
  • ios::binary 以二进制文件格式打开文件

方式二:先创建ofstream对象,再用 open函数打开

	ofstream fout;
	fout.open("test.out",ios::out|ios::binary);
(3)判断是否成功打开文件
if(!fout){
	cout << “File open error!<<endl;
}
(4)文件名的绝对路径和相对路径
  • 文件名可以给出绝对路径,也可以给相对路径。
  • 没有交代路径信息,就是在当前文件夹下找文件。
  • C++的文件分隔符为\ ,例如:“c:\tmp\mydir\some.txt”
(5)文件的读写指针
  • 对于输入文件,有一个读指针;
  • 对于输出文件,有一个写指针;
  • 对于输入输出文件,有一个读写指针;
  • 文件指针的作用:标识文件操作的当前位置, 该指针在哪里,读写操作就在哪里进行。

注意: 文件指针不同于普通的指针,它不是指针类型的,但是其功能与普通指针一样,都是指出某一位置。

文件指针举栗子:

void main(){
//写指针
	ofstream fout("a1.out",ios::app); 	//以添加方式打开
	long location = fout.tellp();		//取得写指针的位置
	location = 10;
	fout.seekp(location);				// 将写指针移动到第10个字节处
	fout.seekp(location,ios::beg);		//从头数location
	fout.seekp(location,ios::cur); 		//从当前位置数location
	fout.seekp(location,ios::end); 		//从尾部数location

//读写指针
	ifstream fin(“a1.in”,ios::ate);	//打开文件,定位文件指针到文件尾
	long location = fin.tellg();		//取得读指针的位置
	location = 10L;
	fin.seekg(location); 				// 将读指针移动到第10个字节处
	fin.seekg(location,ios::beg); 		//从头数location
	fin.seekg(location,ios::cur); 		//从当前位置数location
	fin.seekg(location,ios::end); 		//从尾部数location
}

注意:location可以为负数。
C++ 获取文件长度的方式:
将文件指针置于末尾,获取文件指针的位置。这个获取位置函数返回的值就是文件的长度,即文件的字节数。

(6)显式关闭文件

为什么要关闭文件?

  • 避免不能打开其他文件
    有些操作系统打开文件的数量是一定的,如果每打开一个文件不关闭的话,可能造成打不开其它任何文件问题。

  • 避免数据丢失
    直接向硬盘写入数据的话,硬盘的访问速度很慢。因此现在的操作系统一般先将数据写入到内存缓冲区中,达到一定的条件后( 刷新缓冲区或者缓冲区满了,或者其他条件),再写入硬盘中的文件内。此时才是真正的访问硬盘。如果没有关闭文件,如果我们是向硬盘中的文件写入数据的话,那么就有可能还有一部分数据在内存缓冲区中,没有写入到文件上。

void main(){
	ifstream fin(“test.dat”,ios::in);
	fin.close();
	
	ofstream fout(“test.dat”,ios::out);
	fout.close();
}

2、文件读写函数

(1) ifstream 和 fstream的成员函数
istream& read (char* s, long n);

功能: 将文件读指针指向的地方的n个字节内容,读入到内存地址s,然后将文件读指针向后移动n字节 (以ios::in方式打开文件时,文件读指针开始指向文件开头) 。

(2) ofstream 和 fstream的成员函数:
istream& write (const char* s, long n);

功能: 将内存地址s处的n个字节内容,写入到文件中写指针指向的位置,然后将文件写指针向后移动n字节(以ios::out方式打开文件时,文件写指针开始指向文件开头, 以ios::app方式打开文件时,文件写指针开始指向文件尾部 ) 。

注意: 因为文件流也是流,所以流的成员函数和流操作算子也同样适用于文件流。

3、字符文件读写

写一个程序,将文件 in.txt 里面的整数排序后,输出到out.txt

例如,若in.txt 的内容为:
1 234 9 45 6 879
则执行本程序后,生成的out.txt的内容为:
1 6 9 45 234 879

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
	vector<int> v;
	ifstream srcFile("in.txt",ios::in);
	ofstream destFile("out.txt",ios::out);
	int x;
	while( srcFile >> x )
		v.push_back(x);
	sort(v.begin(),v.end());
	for( int i = 0;i < v.size();i ++ )
		destFile << v[i] << " ";
	destFile.close();
	srcFile.close();
	return 0;
}

3、二进制文件读写

(1)在文件中写入和读取一个整数
#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;
}
(2)从键盘输入几个学生的姓名的成绩,并以二进制文件形式保存
#include <iostream>
#include <fstream>
using namespace std;
struct Student {
	char name[20];
	int score;
};
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字节,用 记事本打开,呈现:
Tom 烫烫烫烫烫烫烫烫< Jack 烫烫烫烫烫烫烫蘌 Jane 烫烫烫烫烫
烫烫?

*/
(3)将 students.dat 文件的内容读出并显示
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
*/
(4)将 students.dat 文件的Jane的名字改成Mike
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);//这里要多写入一个字节'\0'
	iofile.seekg(0,ios::beg); //定位读指针到开头
	while( iofile.read( (char* ) & s, sizeof(s)) )
		cout << s.name << " " << s.score << endl;
	iofile.close();
	return 0;
}
(5)文件拷贝程序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)) //每次读取一个字符
		outFile.put(c);//每次写入一个字符
	outFile.close();
	inFile.close();
	return 0;
}
/*
输出:
Tom 60
Jack 80
Mike 40
*/

4、字符文件与二进制文件的区别

文件格式指的是创建文件和使用文件的人的一个约定,即约定文件的每一部分内容是什么形式的(二进制的、字符串的等),一起其他一些约定。本质上,不同格式的数据最终都是二进制串。只是格式不同(数据的约定不同),解析的方式就不同。比如二进制文件就不能采用记事本取解析。

字符格式文件,存储数据的格式就是字符串的格式,此时我们用记事本打开的话,我们是可以看懂的。二进制格式文件,其中的字符部分我们还是能够看懂的,但是其他数据类型是二进制的形式,只有知道这些数据是怎么排布的人,才能够知道怎么使用这些数据。(通过类型强转)。因此如果用字符编码进行解码的话就会出现乱码现象。 而记事本一般就是采用字符编码进行解析数据,因而我们使用记事本打开二进制文件,就会显示乱码。

(1)二种格式的内存差异:

一般二进制文件比纯文本文件更加节约内存。因为纯文本文件需要将空格、换行符存入。另一方面,对于比较大整型数字,比如1000000000,使用纯文本文件需要存10个字节,而使用二进制形式只需要存4个字节。

(2)查找差异:

二进制文件可以以固定空间进行存储,可以采用二分查找,查找速度更快。而文本文件,不行样本信息差异大,空间上不固定,查找麻烦。 (空间固定才可以使用二分查找)

不同的平台,有些操作的符号是不同的,因此处理同一类型的文件,代码上可能会有差异,下面是平台差异。

(3)不同平台的换行符差异
  • Linux,Unix下的换行符号:'\n' (ASCII码: 0x0a)
  • Windows 下的换行符号:'\r\n' (ASCII码: 0x0d0a) (endl 就是 '\n')
  • Mac OS下的换行符号: '\r' (ASCII码:0x0d)

上述不同导致 Linux, Mac OS 文本文件在Windows 记事本中打开时不换行。

(4)不同平台下打开文件方式有所差异
  • Unix/Linux下打开文件,用不用 ios::binary 没区别。
  • Windows下打开文件,如果不用 ios::binary,则:读取文件时,所有的 '\r\n’会被当做一个字符'\n'处理,即少读了一个字符'\r'。写入文件时,写入单独的'\n'时,系统自动在前面加一个'\r',即多写了一个'\r'。(有时这样违背我们的本意,例如图像处理里面,也许数据本身就真的是\r\n 或者\n。)

注意: 我们处理的大部分文件都是二进制文件,而不是文本文件。

posted @ 2019-12-11 15:27  江南又一春  阅读(229)  评论(0编辑  收藏  举报