C++(3):文件读写操作(含int型和char型变量的存储方式)

C++文件读写技巧
本文详细介绍使用C++进行文件读写的多种方法,包括字符流和字节流操作,以及如何利用string和stringstream处理文本文件。同时探讨了不同场景下的最佳实践,如逐字符、逐词、逐行和整文件读取。


引言


用C++读写文件,基本都是一些琐碎的东西。知道就知道,不知道就不知道。真的没什么可说的。

大概,写得多了,也就记住了吧。

首先,需要记住的是,流的方向。

所有的输入、输出,都是站在内存的角度的。

读入内存,从内存输出。从此,就不会把方向弄错了。

因为我先学的是JAVA,所以,学C++的文件操作的时候,总想拿去跟JAVA的做对比。

以下整理几个比较常见的案例。还是按JAVA的说法吧,分字节流和字符流。虽然C++里面好像,好像并不是这么分的……

以及,C++的string流。

案例有,以字符的方式读写TXT,以字节的方式读写TXT(当然,字节的方式,什么文件都可以读了)。

同时,要涉及输入和输出,所以所有给出的案例,都是文件的拷贝了。

其实好像在C++里面是不应该这么分的……


字符流


字符流。顾名思义,是处理字符的。下面,用字符流的方式,拷贝一个TXT文件。

一个一个字符地读写

#include "iostream"
#include "fstream"
#include "string"


using namespace std;


int main() {


	const string FILE_NAME_IN = "d:/a.txt";
	const string FILE_NAME_OUT = "d:/a_copy.txt";


	fstream ifile(FILE_NAME_IN,ios::in);
	fstream ofile(FILE_NAME_OUT,ios::out); // 如果写binary有什么影响?


	if(ifile && ifile.is_open() && ofile && ofile.is_open()) {


		cout<<FILE_NAME_IN<<" 已打开"<<endl;
		cout<<FILE_NAME_OUT<<" 已打开"<<endl;


		char ch;
		while (!ifile.eof()) // 文件还没有读到末尾
		{
			ifile.read(&ch,1); // read以后,指针会自动往后移动
			cout<<ch;
			ofile.write(&ch,1);
		}


		cout<<"\n";
		cout<<"文件复制完毕"<<endl;


	}


	if(ifile && ifile.is_open() && ofile && ofile.is_open()) {
		ifile.close();
		ofile.close();
		cout<<"ifile 关闭\n";
		cout<<"ofile 关闭\n";
	}


	system("pause");
	return 0;
}

其中,如果直接写 while(in>>ch) ,这样是读不了换行、空格等字符的!至于原因,我目前还不清楚!!!
如果指定输出流,fstream ofile("d:/1.txt",ios::app); 是追加的方式。默认是覆盖重写。

一个一个词地读写


因为getline和cin,对空格的处理方式不一样,当用控制台敲时,可以一个词一个词地读入。
while(cin>>s){
 // ... do sth.
}

一行一行字符地读写


一行一行地读,我不喜欢……
用一个 fstream.getline(char* , int size); 的函数。
问题就在于,目前为止,这个size,设置太大,似乎要多读一些东西,然后小了的话,一行内容又很多,好像又读不完。反正很神奇!
我目前还不知道怎么解决!顺便求助一下大家了!

可以用string!string和stringstream配合起来用,敲方便。
以下是代码!
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;

int main () {

	string path = "d:/a.txt";
	string outPath = "d:/a_copy.txt";

	fstream ifile(path,ios::in);
	fstream ofile(outPath,ios::out);

	if (ifile && ofile)
	{
		string s;
		stringstream ss;

		while (getline(ifile,s))
		{
			cout<<s<<endl;
			ss<<s<<endl;
		}

		ofile<<ss.str();

		if (ifile.is_open())
		{
			ifile.close();
		}
	}

	system("pause");
	return 0;
}
原来可以这么容易!!!
注意,我没有在循环中写ofile<<s,而是用了一个stringstream。
因为我觉得可能:频繁操作硬盘不太好吧,先操作内存吧……
收回原来“我不喜欢”这四个字!

指定字符数地读写

#include "iostream"
#include "fstream"
#include "string"

using namespace std;

int main() {

	const string FILE_NAME_IN = "d:/a.txt";
	const string FILE_NAME_OUT = "d:/a_copy_binary.txt";

	const int BUFFER_SIZE = 512;
	char buff[BUFFER_SIZE];

	fstream ifile(FILE_NAME_IN,ios::in);
	fstream ofile(FILE_NAME_OUT,ios::out);

	if(ifile && ifile.is_open() && ofile && ofile.is_open()) {
		cout<<"文件打开成功"<<endl;

		// 开始执行复制操作
		while (!ifile.eof())
		{
			// 第一件事,应该是把buff里的东西清空。
			memset(buff,0,sizeof(char)*BUFFER_SIZE);
			ifile.read(buff,BUFFER_SIZE);

			cout<<buff;
			ofile.write(buff,ifile.gcount()); // gcount()读到的字节数?
		}

		ofile.close();
		ifile.close();

		cout<<"文件复制完毕"<<endl;
	}


	system("pause");
	return 0;
}

其中,有几点需要注意。
使用了memset()函数。memset(char * str, 要设置的内容xxx,从str开始往后走多少字节都设置为xxx)
如果是char ch, 就要填 &ch,如果是 char ch[10],填ch就是了。
ifile.gcount();返回读了多少内容。在output的时候,应该也加上需要从buffer里抓多少内容写入目标文件,以免写一些神奇的内容!


字节流


字节流,以字节的形式读写。任何文件都可以这样。
代码和上面差不多,就是在构建fstream并打开文件的时候,指定文件模式为binary。
个人感觉这种标志位像是 bit 上有些是0,有些是1,所以可以用 | ,也可以直接加起来吧?为什么?
我只能说,这是语感了……………………………………

指定字节数地读写
#include "iostream"
#include "fstream"
#include "string"

using namespace std;

int main() {

	const string FILE_NAME_IN = "d:/a.exe";
	const string FILE_NAME_OUT = "d:/a_copy_binary.exe";

	const int BUFFER_SIZE = 1024;
	char buff[BUFFER_SIZE];

	fstream ifile(FILE_NAME_IN,ios::in+ios::binary);
	fstream ofile(FILE_NAME_OUT,ios::out+ios::binary);

	if(ifile && ifile.is_open() && ofile && ofile.is_open()) {
		cout<<"文件打开成功"<<endl;

		// 开始执行复制操作
		while (!ifile.eof())
		{
			// 第一件事,应该是把buff里的东西清空。
			memset(buff,0,sizeof(char)*BUFFER_SIZE);
			ifile.read(buff,BUFFER_SIZE);

			cout<<buff;
			ofile.write(buff,ifile.gcount()); // gcount()读到的个数
		}

		ofile.close();
		ifile.close();

		cout<<"文件复制完毕"<<endl;
	}


	system("pause");
	return 0;
}
这个指定字节数和上面指定字符数,差不多。我好像在C++里面没有找到JAVA里面的byte那种数据类型。
JAVA的话,好像直接写 byte[] buffer = new byte[512]; 这种就好……语法好像差不多吧?好久没写,忘了…
不过,C++里面,一个char也正好是1个byte。至少在windows 8的VS 2012下,是这样……
所以应该和JAVA的byte差不多。

一次性把整个文件读入

有时候,可能需要把整个文件一次性读入。
如果文件很大,注意,尽量在heap上开辟空间,最后要delete!
不然,stack不够用啊!
#include <fstream>
#include <iostream>
#include <string>

using namespace std;

int main(int argc, char *argv){

	ifstream infh;  // our file stream
	char *buffer;
	const string FILE_NAME_IN = "D:/a.pdf";
	// const string FILE_NAME_OUT = "d:/a_copy_binary.txt";

	infh.open(FILE_NAME_IN);

	//Error out if the file is not open
	if(!infh){
		cerr << "Could not open file: "<< FILE_NAME_IN << endl;
	}

	//Get the length of the file 
	infh.seekg(0, ios::end);
	int length = infh.tellg();

	cout<<length<<endl;

	//reset the file pointer to the beginning
	infh.seekg(0, ios::beg);

	//Create our buffer
	buffer = new char[length];

	cout<<sizeof(char)*length/1024/1024<<" MB"<<endl;

	// Read the entire file into the buffer
	infh.read(buffer, length);

	//Cycle through the buffer, outputting every other char
// 	for(int i=0; i < length; i+= 2){
// 		cout << buffer[i]; 
// 	}

	infh.close();


	system("pause");

	//Clean up
	delete[] buffer;


	system("pause");

	return 0;
}
用一个大一点的文件,来测试整个文件的读入,再开个任务管理器。可以明显地看到程序占用内存的变化!
所以……一定要做好内存管理!

【补充】
char型变量,是把其ASCII码,存在内存中的,占1个Byte。
本质上,是8个格子,每个格子里面可以填0或者1。
在C语言中,如果以%d输出,会输出8位二进制对应的十进制数。
int型,和char型一样,只是占4了个字节。
在C语言中,如果用%c输出,如果能找到ASCII码表上对应的字符,则会输出对应的字符。
#include<iostream>
using namespace std;

int main () {

	char c ;
	c = 65;
	while( c < 70 ) {
		cout<<c<<endl;
		c++;
	}

	int i = 'a';
	cout<<i<<endl;

	while(i<100) {
		cout<<i<<endl;
		i++;
	}

	system("pause");
	return 0;
}
结果如下。
A
B
C
D
E
97
97
98
99

评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qcyfred

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值