简单的文件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;
}
较新的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;
}
#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;
}