C++文件输入和输出

简单的文件I/O

简单理解,把文件当作显示屏,把f当作c(fin->cin)

  • 写入文件

1.创建一个ofstream对象来管理输出流;
2.将该对象与特定的文件关联起来;
3.以使用cout的方式使用该对象,唯一的区别是输出将进入文件,而不是屏幕;

ofstream fout;//create an ofstream object named fout
fout.open("jar.txt");//associate fout with jar.txt
//ofstream fout("jar.txt");//also ok
fout<<"Dull Data";

注意:以这种方式打开文件来进行输出时,如果没有这样的文件,将创建一个新文件;如果有这样的文件,则打开文件将清空文件,输出将进入到一个空文件中。(以默认模式打开文件进行输出将自动把文件长度截短为0,相当于删除已有内容。)

  • 读取文件

1.创建一个ifsteam对象来管理输入流;
2.将该对象与特定的文件关联起来;
3.以使用cin的方式使用该对象;

//two statements
ifstream fin;
fin.open("jellyjar.txt");
//else
ifstream fis("jar.txt");
//use like cin
char ch;
fin>>ch;//read a character from the jellyjar.txt file
char buff[80];
fin>>buff;//read a word from the jellyjar.txt file
fin.getline(buf, 80);//read a line from jellyjar.txt file
//getline的80表示读取字符串最大长度,实际79,末尾'\0'

close()方法可以显示的关闭到文件的连接。

fout.close();//close output connection to file
fin.close();//close input connection to file

关闭这样的连接并不会删除流,只是断开流到文件的连接,然而流管理装置仍被保留,fin对象与它管理的输入缓冲区仍然存在,可以将流重新连接到同一个文件或者另一个文件。
详细例子:

#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int main() {
	string filename;
	cout << "Enter name for new file: ";
	cin >> filename;
	//create output stream object for new file and call it fout
	ofstream fout(filename.c_str());
	fout << "For your eyes only!\n";
	cout << "Enter your secret number: ";
	float secret;
	cin >> secret;
	fout << "Your secret number is " << secret << endl;
	fout.close();
	//create input stream object for new file and call it fin
	ifstream fin(filename.c_str());
	cout << "Here are the contents of " << filename << endl;
	char ch;
	fin >> ch;
	cout << ch << endl;
	while (fin.get(ch))
		cout << ch;
	cout << "Done\n";
	fin.close();
	system("pause");
	return 0;
}
  • 流状态检查和is_opne()

较新的C++实现提供了一种更好的检查文件是否被打开的方法----is_open()方法。可以理解为检查文件是否存在

if(!fin.is_open())//open attempt failed
{
...
}
  • 打开多个文件
ifstream fin;
fin.open("a.txt");
fin.close();
fin.clear();//reset fin(may not be needed)
fin.open("b.txt")
fin.close();
fin.clear();

命令行模式:

#include<iostream>
#include<fstream>
#include<cstdlib>
using namespace std;
int main(int argc, char* argv[]) {
	if (argc == 1) {
		cerr << "Usage: " << argv[0] << "filemane[s]\n";
		exit(EXIT_FAILURE);
	}
	ifstream fin;//open stream
	long count;
	long total = 0;
	char ch;
	for (int file = 1;file < argc;file++) {
		fin.open(argv[file]);//connect stream to argv[file]
		if (!fin.is_open()) {
			cerr << "could not open" << argv[file] << endl;
			fin.clear();
			continue;
		}
		count = 0;
		while (fin.get(ch))
			count++;
		cout << count << "characters in " << argv[file] << endl;
		total += count;
		fin.clear();
		fin.close();
	}
	cout << total << "characters in all files\n";
	system("pause");
	return 0;
}

linux系统下,编译成a.out文件,然后分别处理pairs和rome两个文件。

$ a.out
$ a.out pairs rome
  • 文件模式

文件模式描述文件如何被使用,如读、写、追加等。

ifstream fin("banjo", mode1)//constructor with mode argument
ofstream fout();
fout.open("harp",mode2)//open()with mode argument

文件模式常量 之后使用一直是ios::不是ios_base::

常量含义
ios_base::in打开文件,以便读取
ios_base::out打开文件,以便写入
ios_base::ate打开文件,并移到文件尾
ios_base::app打开文件,追加到文件尾
ios_base::trunc如果文件存在,则截短文件
ios_base::binary二进制文件

与C语言文件打开模式类比

C++模式C模式含义
ios_base::in“r”打开以读取
ios_base::out“w”等价于ios_base::out|ios_base::trunc
ios_base::out|ios_base::trunc“w”写入并截短
ios_base::out|ios_base::app“a”追加写入
ios_base::in|ios_base::out“r+”打开以读写,在文件允许位置写入
ios_base::in|ios_base::out|ios_base::trunc“w+”打开以读写,如果已经存在则截短
C++mode|ios_base::binary“cmodeb”以C++mode和二进制模式打开
C++mode|ios_base::ate“cmode”以指定模式打开,并移到文件尾

注意: ios_base::ate和ios_base::app都将文件指针指向打开的文件尾。二者的区别在于,ios_base::app模式只允许将数字添加到文件尾,而ios_base::ate模式将指针放到文件尾。
具体例子:

#include<iostream>
#include<fstream>
#include<string>
#include<cstdlib>
using namespace std;
const char* file = "guests.txt";
int main() {
	char ch;
	//show initial contents
	ifstream fin;
	fin.open(file);
	if (fin.is_open()) {
		cout << "Here are the current contents of the " << file << " file:\n";
		while (fin.get(ch))
			cout << ch;
		fin.close();
	}
	//add new names
	ofstream fout(file, ios::out | ios_base::app);//ios和ios_base都可以
	if (!fout.is_open()) {
		cerr << "Cant open" << file << " for output.\n";
		exit(EXIT_FAILURE);
	}
	cout << "Enter guest names(enter a blank line to quit):\n";
	string name;
	while (getline(cin, name) && name.size() > 0) {
		fout << name << endl;
	}
	fout.close();
	//show revised file
	fin.clear();
	fin.open(file);
	if (fin.is_open()) {
		cout << "Here are the new contents of the " << file << " file:\n";
		while (fin.get(ch))
			cout << ch;
		fin.close();
	}
	cout << "Done.\n";
	system("pause");
	return 0;
}
  • 二进制文件
  • 文本文件:便于读取
  • 二进制文件:对于数字来说比较精确,因为它存储的是值的内部表示,因此不会有转换误差或舍人误差。以二进制格式保存数据的速度更快,因为不需要转换,并可以大块存储数据。
    例如:
const int LIM = 20;
struct planet{
char name[LIM];
double population;
double g;}
planet p1;
//文本文件
ofstream fout("planet.dat",ios_base::out|ios_base::app);
fout<<p1.name<<" "<<p1.population<<" "<<p1.g<<endl;
//二进制文件
ofstream fout("planet.dat",ios_base::out|ios_base::app|ios_base::binary);
fout.write((char *)&p1, sizeof p1);

二进制文件下主要做了两个修改:1.使用二进制文件模式 2.使用成员函数write()
对于使用文件恢复信息的情况,可以使用read()方法:

ifstream fin("planet.dat",ios_base::in|ios_base::binary);
fin.read((char*)&p1,sizeof p1);

二进制文件操作例子:

#include<iostream>
#include<fstream>
#include<iomanip>
#include<cstdlib>//for exit
using namespace std;
inline void eatline() { while (std::cin.get() != '\n') continue; }
struct planet {
	char name[20];
	double population;
	double g;
};
const char* file = "planets.dat";
int main() {
	planet p1;
	cout << fixed << right;
	//show initial contents
	ifstream fin;
	fin.open(file, ios_base::in | ios_base::binary);
	if (fin.is_open()) {
		cout << "Here are the current contents of the " << file << " file:\n";
		while (fin.read((char*)& p1, sizeof p1)) {
			cout << setw(20) << p1.name << ": " << setprecision(0) << setw(12)
				<< p1.population << setprecision(2) << setw(6) << p1.g << endl;
		}
		fin.close();
	}
	//add new data
	ofstream fout(file, ios_base::out | ios_base::app | ios_base::binary);
	if (!fout.is_open()) {
		cerr << "Cant open " << file << " file for output:\n";
		exit(EXIT_FAILURE);
	}
	cout << "Enter planet name(enter a blank line to quit):\n";
	cin.get(p1.name, 20);
	while (p1.name[0] != '\0') {
		eatline();
		cout << "Enter planetary population: ";
		cin >> p1.population;
		cout << "Enter planet's acceleration of gravity: ";
		cin >> p1.g;
		eatline();
		fout.write((char*)&p1, sizeof p1);
		cout << "Enter planet name(enter a blank line to quit):\n";
		cin.get(p1.name, 20);
	}
	fout.close();
	//show revised file
	fin.clear();
	fin.open(file, ios_base::in | ios_base::binary);
	if (fin.is_open()) {
		cout << "Here are the current contents of the " << file << " file:\n";
		while (fin.read((char*)& p1, sizeof p1)) {
			cout << setw(20) << p1.name << ": " << setprecision(0) << setw(12)
				<< p1.population << setprecision(2) << setw(6) << p1.g << endl;
		}
		fin.close();
	}
	cout << "Done.\n";
	system("pause");
	return 0;
}

此处string对象不能用来表示planet结构的name成员。因为string对象本身并没有包含字符串,而是包含一个指向字符串的内存单元的指针。因此将结构复制到文件中时,复制的将不是字符串数据,而是字符串的存储地址。

  • 随机存取

fstream类为此继承了两个方法:seekg()和seekp(),前者将输入指针移到指定的文件位置,后者将输出指针移到指定的文件位置。
istream& seekg(streamoff, ios_base::seekdir);
istream& seekg(streampos);
第一个原型定位到离第二个参数指定的文件位置的特定距离处;第二个原型定位到离文件开头特定距离的位置。

fin.seekg(30,ios_base::beg);//30 bytes beyond the beginning
fin.seekg(-1,ios_base::cur);//back up one byte
fin.seekg(0,ios_base::end);//go to the end of the file
fin.seekg(112)//文件指针指向第112个字节,这是文件的第113个字节

random.cpp

#include<iostream>
#include<fstream>
#include<iomanip>
#include<cstdlib>
using namespace std;
const int LIM = 20;

struct planet {
	char name[LIM];
	double population;
	double g;
};
const char* file = "planets.dat";
inline void eatline() { while (cin.get() != '\n') continue; }
int main() {
	planet p1;
	cout << fixed;
	//show initial contents
	fstream finout;
	finout.open(file, ios_base::in | ios_base::out | ios_base::binary);
	int ct = 0;
	if (finout.is_open()) {
		finout.seekg(0);//go to beginning
		cout << "Here are the current contents of the " << file << " file:\n";
		while (finout.read((char*)&p1, sizeof p1)) {
			cout << ct++ << ":" << setw(LIM) << p1.name << ": "
				<< setprecision(0) << setw(12) << p1.population
				<< setprecision(2) << setw(6) << p1.g << endl;
		}
		if (finout.eof())
			finout.clear();
		else
		{
			cerr << "Error in reading " << file << ".\n";
			exit(EXIT_FAILURE);
		}
	}
	else
	{
		cerr << file << " could not be opened--bye.\n";
		exit(EXIT_FAILURE);
	}
	//change a record
	cout << "Enter the record number you wish to change: ";
	long rec;
	cin >> rec;
	eatline();//get rid of newline
	if (rec < 0 || rec >= ct)
	{
		cerr << "Invalid record number--bye\n";
		exit(EXIT_FAILURE);
	}
	streampos place = rec * sizeof p1;//convert to streampos type
	finout.seekg(place);//select a access
	if (finout.fail())
	{
		cerr << "Error on attempted seek\n";
		exit(EXIT_FAILURE);
	}
	finout.read((char*)&p1, sizeof p1);
	cout << "your selection:\n";
	cout << rec << ": " << setw(LIM) << p1.name << ": "
		<< setprecision(0) << setw(12) << p1.population
		<< setprecision(2) << setw(6) << p1.g << endl;
	if (finout.eof())
		finout.clear();//clear eof flag
	cout << "Enter planet name: ";
	cin.get(p1.name, LIM);//这里指定长度了,当然要eatline
	eatline();
	cout << "Enter planetary population: ";
	cin >> p1.population;
	cout << "Enter planet's acceleration of gravity: ";
	cin >> p1.g;
	finout.seekg(place);//go back
	finout.write((char*)&p1, sizeof p1) << flush;
	if (finout.fail())
	{
		cerr << "Error on attempted write\n";
		exit(EXIT_FAILURE);
	}
	//show revised file
	ct = 0;
	finout.seekg(0);
	cout << "Here are the new content of the " << file << " file:\n";
	while (finout.read((char*)&p1, sizeof p1)) {
		cout << ct++ << ":" << setw(LIM) << p1.name << ": "
			<< setprecision(0) << setw(12) << p1.population
			<< setprecision(2) << setw(6) << p1.g << endl;
	}
	finout.close();
	cout << "Done.\n";
	system("pause");
	return 0;
}
  • 临时文件
  • 生成10个临时文件名
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
	cout << "This system can generate up tp" << TMP_MAX << " temporary names of up to " << L_tmpnam << "characters.\n";
	char pszName[L_tmpnam] = { '\0' };
	cout << "Here are ten names: \n";
	for (int i = 0; i < 10; i++)
	{
		tmpnam_s(pszName);//here generate
		cout << pszName << endl;
	}
	return 0;
}
  • 每次读取一个单词的实现
#include<iostream>
#include<sstream>
#include<string>
using namespace std;
int main() {
	string lit = "It is a good day, And I want to dance.";
	istringstream instr(lit);
	string word;
	while (instr >> word) {
		cout << word << endl;
	}
	system("pause");
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值