一、文件的读写
如前面所提,流的读写主要有<<, >>, get, put, read, write 等操作,ofstream 继承自ostream, ifstream 继承自 istream,故操作函数都是一致的。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
#include <iostream>
#include <fstream> #include <string> #include <cassert> using namespace std; int main( void) { ofstream fout( "test.txt"); fout << "abc" << " " << 200; fout.close(); ifstream fin( "test.txt"); string s; int n; //fin>>n>>s; fin >> s >> n; cout << s << " " << n << endl; ofstream fout1( "test2.txt"); assert(fout1); char ch; for ( int i = 0; i < 26; i++) { ch = 'A' + i; fout1.put(ch); } fout1.close(); ifstream fin1( "test2.txt"); while (fin1.get(ch)) { cout << ch; } cout << endl; return 0; } |
二、二进制文件的读写
二进制文件不同于文本文件,它可用于任何类型的文件(包括文本文件)
对二进制文件的读写可采用从istream类继承下来的成员函数read()和从ostream类继承下来的成员函数write()
文件打开操作时使用枚举常量ios::binary,例如:ofstream fout(“binary.dat”,ios::out | ios::binary);
(一)、write成员 函数
函数功能:以字节位单位向文件流中写入整块数据,最有价值的应用可以处理结构体变量和类对象
函数原型:
ostream& write( const char* pch, int nCount );
函数参数:
pch 写入的数据的指针
nCount 写入数据的字节大小
(二)、read 成员 函数
函数功能:从文件流中读出整块数据
函数原型:
istream& read( char* pch, int nCount );
函数参数:
pch 用来接收数据的指针
nCount 读取的字节数的大小
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#include <cassert>
#include <iostream> #include <fstream> #include <string> using namespace std; struct Test { int a; int b; }; int main( void) { ofstream fout( "test3.txt", ios::out | ios::binary); // 二进制方式打开,' '不做转换 fout << "ABC "; // << 是以文本方式写入 fout.close(); Test test = { 100, 200 }; ofstream fout1( "test4.txt", ios::out | ios::binary); fout1.write( reinterpret_cast< char *>(&test), sizeof(Test)); // 二进制方式写入后用文本编辑器打开test4.txt 乱码 fout1.close(); Test test2; ifstream fin( "test4.txt", ios::in | ios::binary); fin.read( reinterpret_cast< char *>(&test2), sizeof(Test)); cout << test2.a << " " << test2.b << endl; ofstream fout2( "test5.txt", ios::out | ios::binary); fout2 << "abc" << 200; // << 是以文本方式写入 fcout2.close(); return 0; } |
在window下以文本方式打开文件,则写入时遇到' ' , 转换为' ',以二进制方式打开则不做转换,故test3.txt 文件大小为4个字节。
而写入100(write 是以二进制方式写入)就不再是写入'1', '0' ,' 0' 的ascii 码,而是按照内存本来二进制形式写入,故用文本编辑器打开test4.txt 时会出现乱码。文件大小为8个字节(两个int)
同理,test5.txt 虽然以二进制打开,但是以文本方式(<< 是以文本方式写入)写入的,故写入200后用文本编辑器打开不会出现乱码,文件大小为6个字节。
有关文本文件与二进制文件的区别,请参考这里。
使用read, write 读取string 的时候需要注意,string 实际上内部是一些指针成员,sizeof(string)=32 (跟编译器实现有关),即string 大小是一定的,而它的指针成员保存的字符串长度不一定是32,故我们应该这些读写:
1
2 3 4 5 6 7 8 9 |
string str1 =
"fdsfafsdsf";
int len = str1.length(); ofstream fout( "test6.txt", ios::out | ios::binary); fout.write(str1.data(), str1.length()); string str2; str2.resize(len); ifstream fin( "test6.txt", ios::in | ios::binary); fin.read(&str2[ 0], len); |
如果像这样写入 fout.write((char*)&str1, sizeof(str1)); 一定是错误的,因为写入的是str1 的指针成员,而不是指针成员指向的字符串,而且str1 的大小恒等于32。
三、文件随机读写
(一)、当前文件流活动指针
文件流指针用以跟踪发生 I/O 操作的位置
每当从流中读取或写入一个字符,当前活动指针就会向前移动
当打开方式中不含有ios::ate或ios::app选项时,则文件指针被自动移到文件的开始位置,即字节地址为0的位置。
(二)、文件的随机读写 seekp和seekg
seekp 和 seekg 类似与C库的fseek, linux系统调用的lseek。
函数功能
seekp:设置输出文件流的文件流指针位置
seekg:设置输入文件流的文件流指针位置
函数原型:
ostream& seekp( streampos pos );
ostream& seekp( streamoff off, ios::seek_dir dir );
istream& seekg( streampos pos );
istream& seekg( streamoff off, ios::seek_dir dir );
函数参数
pos:新的文件流指针位置值
off:需要偏移的值
dir:搜索的起始位置
dir参数用于对文件流指针的定位操作上,代表搜索的起始位置
在ios中定义的枚举类型:
enum seek_dir {beg, cur, end};
每个枚举常量的含义:
ios::beg:文件流的起始位置
ios::cur:文件流的当前位置
ios::end:文件流的结束位置
tellp 和 tellg 类似C库的ftell,,linux 系统调用的lseek(fd, 0, SEEK_CUR);
函数功能
tellp:获得输出的文件流指针的当前位置,以字节为单位
tellg:获得输入的文件流指针的当前位置,以字节为单位
函数原型:
streampos tellp();
streampos tellg();
函数返回值:实际上是一个long类型
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#include <cassert>
#include <iostream> #include <fstream> #include <string> using namespace std; int main( void) { ifstream fin( "test7.txt"); assert(fin); fin.seekg( 2); //位置从0开始计数 char ch; fin.get(ch); cout << ch << endl; fin.seekg(- 1, ios::end); //end 实际上是EOF位置 fin.get(ch); cout << ch << endl; fin.seekg( 0, ios::end); streampos pos = fin.tellg(); cout << pos << endl; return 0; } |
假设test7.txt 现在存放abcdefg 7个字符,则输出为c g 7 .
参考:
C++ primer 第四版
Effective C++ 3rd
C++编程规范