引言
用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;
}结果如下。B
C
D
E
97
97
98
99
C++文件读写技巧
本文详细介绍使用C++进行文件读写的多种方法,包括字符流和字节流操作,以及如何利用string和stringstream处理文本文件。同时探讨了不同场景下的最佳实践,如逐字符、逐词、逐行和整文件读取。
886

被折叠的 条评论
为什么被折叠?



