1 二进制文件读写
-- 二进制读文件
ifstream和fstream的成员函数
函数:istream& read(char* s, long n);
作用:将文件读指针指向的地方的n个字节内容,读入到内存地址s,然后将文件读指针向后移动n个字节(以ios::in方式打开文件时,文件读指针开始指向文件开头,以ios::ate方式打开文件时,文件读指针开始指向文件结尾)
-- 二进制写文件
ofstream和fstream的成员函数
函数:istream& write(const char* s, long n);
作用:将内存地址s处的n个字节内容,写入到文件中写指针指向的位置,然后将文件写指针向后移动n个字节(以ios::out方式打开文件时,文件写指针开始指向文件开头,以ios::app方式打开文件时,文件写指针开始指向文件尾部)
2 二进制读写例子(见本工程erjinzhiduxie.cpp)
/**
* 二进制文件读写
* 在文件中写入和读取一个整数案例
*/
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
// 在构造方法中初始化 打开some.dat文件,以二进制方式写入,如果不写ios::binary 会有麻烦
ofstream fout("some.dat", ios::out | ios::binary);
int x = 120;
// istream& write(const char* s, long n);
// 将内存地址s处的n个字节内容,写入到文件中写指针指向的位置,然后将文件写指针向后移动n个字节
// 以ios::out方式打开文件时,文件写指针开始指向文件开头,以ios::app方式打开文件时,文件写指针开始指向文件尾部
// &x类型是int* 与const char*类型不匹配,因此需要强制转换
fout.write((const char*)(&x), sizeof(int)); // 内容地址 --> 写指针
fout.close();
ifstream fin("some.dat", ios::in | ios::binary);
int y;
// istream& read(char* s, long n);
// 将文件读指针指向的地方的n个字节内容,读入到内存地址s,然后将文件读指针向后移动n个字节
// 以ios::in方式打开文件时,文件读指针开始指向文件开头,以ios::ate方式打开文件时,文件读指针开始指向文件结尾
fin.read((char*)&y, sizeof(int)); // 读指针 --> 内容地址
fin.close();
cout << y << endl;
return 0;
}
3 二进制读写例子
从键盘输入几个学生的姓名的成绩,并以二进制文件形式保存
(见本工程erjinzhiduxie2.cpp)
/**
* 演示二进制文件读写
* 从键盘输入几个学生的姓名和成绩,并以二进制文件形式保存
*/
#include <iostream>
#include <fstream>
using namespace std;
struct Student
{
char name[20]; // 20个字节的数组来存放姓名 一个char占用一个字节
int score; // int占用4个字节
};
int main()
{
Student s;
// 写指针位于文件开头
ofstream OutFile("students.dat", ios::out | ios::binary);
while(cin >> s.name >> s.score)
// istream& write(const char* s, long n);
// 将内存地址s处的n个字节内容,写入到文件中写指针指向的位置,然后将文件写指针向后移动n个字节
// 以ios::out方式打开文件时,文件写指针开始指向文件开头,以ios::app方式打开文件时,文件写指针开始指向文件尾部
OutFile.write((char*)&s, sizeof(s));
OutFile.close();
return 0;
}
将students.dat文件的内容读出并显示
(见本工程erjinzhiduxie3.cpp)
/**
* 二进制文件读写
* 将students.dat文件的内容读出并显示
*/
#include <iostream>
#include <fstream>
using namespace std;
struct Student
{
char name[20];
int score;
};
int main()
{
Student s;
// 读指针位于文件开头
ifstream inFile("students.dat", ios::in | ios::binary);
if(!inFile) // 判断文件打开是否成功
{
cout << "error" << endl;
return 0;
}
// istream& read(char* s, long n);
// 将文件读指针指向的地方的n个字节内容,读入到内存地址s,然后将文件读指针向后移动n个字节
// 以ios::in方式打开文件时,文件读指针开始指向文件开头,以ios::ate方式打开文件时,文件读指针开始指向文件结尾
while(inFile.read((char*)&s, sizeof(s))) // 读到s对象里去 s的地址需要强制转换成char* 读到文件尾,read就会返回false
{
int readedBytes = inFile.gcount(); // 看刚才读了多少字节
cout << s.name << " " << s.score << endl;
}
inFile.close();
return 0;
}
将students.dat文件的Jane的名字改成Mike
(见本工程erjinzhiduxie4.cpp)
/**
* 二进制文件读写
* 将student.dat文件的Jane的名字改成Mike
*/
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
struct Student
{
char name[20];
int score;
};
int main()
{
Student s;
fstream ioFile("students.dat", ios::in | ios::out | ios::binary);
if(!ioFile)
{
cout << "error";
return 0;
}
ioFile.seekp(2 * sizeof(s), ios::beg); // 定位写指针到第三个记录
// istream& write(const char* s, long n);
// 将内存地址s处的n个字节内容,写入到文件中写指针指向的位置,然后将文件写指针向后移动n个字节
// 以ios::out方式打开文件时,文件写指针开始指向文件开头,以ios::app方式打开文件时,文件写指针开始指向文件尾部
ioFile.write("Mike", strlen("Mike") + 1);
ioFile.seekg(0, ios::beg); //定位读指针到开头
while(ioFile.read((char*) &s, sizeof(s)))
cout << s.name << " " << s.score << endl;
ioFile.close();
return 0;
}
文件拷贝程序mycopy实例
(见本工程wenjiankaobei.cpp)
/**
* 二进制文件读写
* 文件拷贝程序mycopy实例
* 用法实例
* 执行命令行命令 mycopy src.dat dest.dat
* 即将src.dat拷贝到dest.dat 如果dest.dat原来就有,则原来的文件就会被覆盖
*
* 内存缓冲区
* 读取文件中的一个字符c,也就是只读了一个字节,文件在硬盘上,如果为了读一个字节,就要去访问一个硬盘,会非常的浪费,效率很低。
* 所以操作系统在读写文件的时候都会使用内存缓冲区,哪怕读取的是一个字符,操作系统也会把这个字符所在的硬盘的扇区整个的读到内存,甚至不是只读
* 一个扇区, 而是把这个扇区相邻的好几个扇区一块都读到内存。也就是所执行的指令只是读一个字符到内存,实际上产生的效果是操作系统有可能把硬盘上
* 4k/8k的内容全部都读到内存中,这样下一次执行get(c)的时候就不需要访问硬盘了,就可以直接从刚才已经放在内存中的那部分数据中来取得下一个字符
*
*
*/
#include <iostream>
#include <fstream>
using namespace std;
// argc为命令行参数的个数,argv为命令行参数
int main(int argc, char* argv[])
{
if(argc != 3)
{
cout << "File name missing!" << endl;
return 0;
}
// 打开文件argv[1],以二进制的方式进行读,读指针起始位置位于文件开头
ifstream inFile(argv[1], ios::binary | ios::in);
if(!inFile)
{
cout << "Source file open error." << endl;
return 0;
}
// 打开文件argv[2],以二进制方式进行写入,写指针起始位置位于文件开头
ofstream outFile(argv[2], ios::out | ios::binary);
if(!outFile)
{
cout << "New file open error." << endl;
inFile.close(); // 打开的文件一定要关闭
return 0;
}
char c;
// get()成员函数是istream的一个成员函数,作用是从流或者文件中读取一个字节,读取到的字节放在c中。如果返回false代表文件读取结束
// put()成员函数是ostream的一个成员函数,接收一个char类型的参数,put(c),将刚刚读到的字符写入到文件中
while(inFile.get(c)) // 每次读取一个字符
outFile.put(c); // 每次写入一个字符
outFile.close(); // 关闭流
inFile.close();
return 0;
}
4 二进制文件和文本文件的区别
Linux, Unix下的换行符号:‘\n’ (ASCII码:0x0a)
Windows下的换行符:‘\r\n’ (ASCII码:0x0d0a) endl就是‘\n’
Mac OS下的换行符: ‘\r’ (ASCII码:0x0d)
导致Linux, Mac OS 文本文件在Windows记事本中打开时不换行
-- Unix/Linux下打开文件,用不用ios::binary没区别
-- Windows下打开文件,如果不用ios::binary,则:
读取文件时,所有的‘\r\n’会被当做一个字符‘\n’处理,即少读了一个字符‘\r’
写入文件时,写入单独的‘\n’时,系统自动在前面加了一个‘\r’,即多写了一个‘\r’