文件操作
对c++来说,很重要的一个内容。
知识点
基本概念和文件流类
根据数据编码的不同,可分为文本文件和二进制文件。
文本文件:文件中的每个字节都是一个ascii码
二进制文件:非文本文件统称二进制文件
读文件:文本中数据到内存,输入
写文件:内存到文件,输出
文件流类
三个文件流类,使用时需要包含fstream头文件
ifstream:从文件读取数据
ofstream:向文件写入数据
fstream:可读可写
打开和关闭文件
打开文件
目的:
- 建立关联,通过指定文件名,建立文件和文件流对象的关联。
- 指明文件的使用方式和文件格式。只读、只写,可读可写,在文件未尾追加等4种,考点,文件格式是文本还是二进制等
打开方式
两种:不含隐式打开
先建立对象,再调用open()函数连接外部文件
流类名 对象名;
对象名.open(文件名,模式)
使用例子
文件流类ifstream中的open成员函数为例
open原型为:void open(const char* szFileName, int mode);//第一个参数是指向文件名的指针,第二个参数是文件的打开模式标记。
使用时,可以这样
ifstream inFile;
inFile.open("c:\\tmp\\test.txt", ios::in);//也可以采用相对路径如:oFile.open("tmp\\test2.txt", ios::out | ios::in);tmp\\表示位于tmp这个文件夹中,而..\\表示位于上一层文件夹
if (inFile) //条件成立,则说明文件打开成功
inFile.close();
另一种:调用流类带参数的构造函数
流类名 对象名(文件名,模式)
使用例子
ifstream 类为例,它的构造函数ifstream::ifstream (const char* szFileName, int mode = ios::in, int);//第一个参数是指向文件名的指针;第二个参数是打开文件的模式标记,默认值为ios::in
; 第三个参数是整型的,也有默认值
#include <iostream>
#include <fstream>//头文件包含
using namespace std;
int main()
{
ifstream inFile("c:\\tmp\\test.txt", ios::in);//流类构造函数
if (inFile)//文件打开成功
inFile.close();
fstream oFile2("tmp\\test2.txt", ios::out | ios::in);
if (!oFile2)
cout << "error 2";
}
关闭文件
作用:
- 系统会将缓冲区中的数据完整地写入文件
- 添加文件结束标记
- 切断流对象与外部文件的连接
关闭方式
对象名.close()
文件打开模式标记
模式标记 | 适用对象 | 作用 |
---|---|---|
ios::in | ifstream fstream | 打开文件用于读取数据。如果文件不存在,则打开出错。 |
ios::out | ofstream fstream | 打开文件用于写入数据。如果文件不存在,则新建该文件;如果文件原来就存在,则打开时清除原来的内容。 |
ios::app | ofstream fstream | 打开文件,用于在其尾部添加数据。如果文件不存在,则新建该文件。 |
ios::ate | ifstream | 打开一个已有的文件,并将文件读指针指向文件末尾。如果文件不存在,则打开出错。 |
ios:: trunc | ofstream | 打开文件时会清空内部存储的所有数据,单独使用时与 ios::out 相同 |
ios::binary | ifstream ofstream fstream | 以二进制方式打开文件。若不指定此模式,则以文本模式打开。ios::in|ios::binary:表示以二进制模式,以读取的方式打开文件。ios::out|ios::binary:表示用二进制模式,以写入的方式打开文件。 |
文件读写操作
相关文件流类的读写操作,详见c++考点之文件读写操作.
读写文本文件
类ofstream, ifstream 和fstream 是分别从ostream, istream 和iostream 中引申而来的。这就是为什么 fstream 的对象可以使用其父类的成员来访问数据。也就是说操作文件使用与控制台一样的成员函数cin和cout .
写实例
#include <fstream>
using namespace std;
int main()
{
short x = 1297;
ofstream out("out.txt");
if (out.is_open()) {
out << "my test.\n";//向文件写入后面的内容
out << "source.\n";
out << x;//这里将数字自动格式化为'1' '2' '9' '7'
out.close();
}
return 0;
}
读实例
#include<iostream>
#include<fstream>
#include<stdlib.h>
using namespace std;
int main(int argc, char const *argv[])
{
char buffer[256];
ifstream in("out.txt");//流提取
if (! in.is_open()) {
cout << "Error opening file";
exit(1);
}
while (!in.eof()) {
in.getline(buffer, 100);
cout << buffer << endl;//提取文件的内容
}
return 0;
}
成员函数put()和get()读写文件
get
其定义在 istream 类中,借助 cin.get() 可以读取用户输入的字符。
- int get()
功能:从指定的输入流中提取一个字符(使用的是ascii码),当遇到文件结束符时,返回EOF - istream &get(char &rch);
功能:需要定义一个字符变量rch,get() 方法会自行将读取到的字符赋值给这个变量。 - istream &get(char *pch,int nCount,char delin="\n");
功能:从流的当前字符开始,读取nCount-1字符,或遇到指定的分隔符delim结束,函数把读取到的字符(不包括分隔符)写入数组中,并在字符串后添加结束符‘\0’
get 实例
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
char c;
//以二进制形式打开文件
ifstream inFile("out.txt", ios::out | ios::binary);
if (!inFile) {
cout << "error" << endl;
return 0;
}
while ((c = inFile.get()) && c != EOF) { //或者 while(inFile.get(c)),对应第二种语法格式
cout << c ;
}
inFile.close();
return 0;
}
put
ostream &put(char ch);
功能:向输出流中插入一个字节。1
put实例
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
char c;
ofstream outFile("out.txt", ios::out);//写入方式打开,默认为文本
// ofstream outFile("out.txt", ios::out | ios::binary);//二进制形式
if (!outFile) {
cout << "error" << endl;
return 0;
}
while (cin >> c) {
outFile.put(c);//将字符 c 写入 out.txt 文件
}
outFile.close();
return 0;
}
二进制文件
从字符串表示到数字的转换称为解析,而从数字到字符串的逆转换称为格式化。
二进制文件中数据存储格式与内存格式一致,存储长度仅与数据类型相关
不会对写入或读出的数据做格式转换,便与高速处理。
专用函数
- ostream &write(char *buffer,int nCount);
功能:将内存中buffer所指向的nCount个字节的内容写入文件,返回值是对函数所作用的对象的引用。
可用于将二进制数据写入文件,要调用该函数,需指定一个缓冲区的地址,该缓冲区包含一个要写入的字节数组和一个指示要写入多少字节的整数。 - istream &read(char *buffer,int nCount);
功能:从文件中读取nCount个字节的内容,存放到buffre所指向的内存缓冲区中,返回值是对函数所作用的对象的引用 - int gcount();
功能:返回值就是最近一次read()函数执行时成功读取的字节数。
实例
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
//File object used to access file
fstream file("nums.dat", ios::out | ios::binary);//文件以输出和二进制模式打开。而文件默认是以文本方式打开
if (!file) {
cout << "Error opening file.";
return 0;
}
//Integer data to write to binary file
int buffer[ ] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int size = sizeof(buffer) / sizeof(buffer[0]);
// Write the data and close the file
cout << "Now writing the data to the file.\n";
file.write(reinterpret_cast<char *>(buffer), sizeof(buffer));
file.close();
// Open the file and use a binary read to read contents of the file into an array
file.open("nums.dat", ios::in);
if (!file) {
cout << "Error opening file.";
return 0;
}
cout << "Now reading the data back into memory.\n";
file.read(reinterpret_cast<char *>(buffer), sizeof(buffer));
// Write out the array entries
for (int count = 0; count < size; count++)
cout << buffer[count] << " ";
// Close the file
file.close();
return 0;
}
注意:
reinterpret_cast(value);//将某个值转换为某些目标类型,强制编译器解释为另一种类型,就仿佛重新定义类型一样。
文本与二进制文件优缺点
文本
- 优点:具有较高的兼容性
- 缺点:
- 存储一批纯数值信息时,需要在数据之间人为地添加分隔符
- 输入输出过程中,系统要对内外存数据格式进行相应的转换
- 不便于对数据进行随机访问
二进制
- 优点:
- 相同数据类型占用空间大小是均等的,不必在数据之间人为地添加分隔符
- 输入输出过程中,系统不需要对数据进行任何转换
- 便于对数据进行随机访问
- 缺点:数据兼容性差
注:
通常纯文本信息(如字符串)以文本形式存储,而将数值信息以二进制文件形式存储
随机访问文件
- 顺序文件:只能进行顺序存取操作的文件。如键盘、显示器和保存在磁带上的文件
- 随机文件:可以在文件任意位置进行存取操作的文件。如磁盘文件,可以进行随机访问,也可以顺序访问
- 顺序访问:严格按照数据保存的次序从头到尾访问文件
- 随机访问:根据需要在文件的不同位置进行访问。
- 文件位置指针:文件打开后,系统自动生成一个流指针,决定读写开始的位置
打开文件时,位置指针指向文件的第1个字节(如果以ios:ate方式打开,则指向文件末尾),每完成一次读写操作,位置指针自动移动到下一个读写分量的起始位置。
istream中与位置指针相关函数
- istream &seekg(long ps);//移动读指针函数
功能:将读指针设置为pos,即将读指针移动到文件的pos字节处。
istream &seekg(long offset,ios::seek_dir dir);
功能:将读指针按照seek_dir指示方向移动offset 个字节,其中seek_dir是在类ios中定义的一个枚举类型。
seek_dir常量含义
- ios::beg//流的开始位置
- ios::cur//流的当前位置
- ios::end//流的结束位置
- long tellg();//返回读指针当前位置值的函数
ostream中与位置指针相关的函数
- ostream &seekp(long pos);
功能:将写指针设置为pos
ostream &seekp(long offset,ios::seek_dir dir);
功能:写指针按方向移动offset个字节
的函数 - ostream &seekp(long pos);
功能:将写指针设置为pos
ostream &seekp(long offset,ios::seek_dir dir);
功能:写指针按方向移动offset个字节 - long tellp();//函数返回值为流中写指针的当前位置。
get 与put可用于文本也可用于二进制,主要是文本文件。 ↩︎