最近几天在做一个简易的社交系统’/*其实是数据结构大作业*/’,频繁地用到文件操作。其中比较捉急的是对于文件内容的改写。
文件修改
我觉得修改可以分为两种,一种是定长修改,一种是长度发生变化的修改。两种修改都有一种通用的修改方法,不过这个方法非常没有效率,那就是建立一个tmp文件,把修改过后的内容放到里面,然后删掉原文件把tmp文件改成原文件的名字。这个方法显然不是很科学,而且如果文件内容很大,那么时间可能会挺长的。
探索定长修改
抛去上面的方法不说,定长修改的方法很简单,就是同时以ios::in
与ios::out
打开文件,不过其中还是有些需要注意的。
在进行文件写的时候(非二进制),文件指针很成问题。举个例子:比如文件的内容是”100100100”,写入了三个int
类型的变量,值为100。接下来我如果想改变第二个100,使其变成200,文件指针需要移动3位,因为前面有三个字符。这时候指针是一个字符一个字符的移动的
#include < iostream >
#include < fstream >
using namespace std;
int main() {
ofstream ofs("cece.txt", ios::out);
int x = 100;
ofs << x << x << x;
ofs.close();
ofs.open("cece.txt", ios::out | ios:: in );
x = 200;
ofs.seekp(3);
ofs << x;
}
而如果把文件换成二进制的写,那么情况就会有些变化,如果还是想改写第二个100的内容,那么文件指针就需要指向sizeof(int)。指针是一个byte一个byte地移动。 int存入的方式就是以int类型,将其原封写入文件,所以二进制的读写比较简单。
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ofstream ofs("cece.txt", ios::out | ios::binary);
int x = 100;
ofs.write((char *)&x, sizeof(x));
ofs.write((char *)&x, sizeof(x));
ofs.write((char *)&x, sizeof(x));
ofs.close();
ofs.open("cece.txt", ios::out | ios::in | ios::binary);
x = 200;
ofs.seekp(sizeof(int));
ofs.write((char *)&x, sizeof(x));
}
经实验表明,ios::app Mode下是不能移动文件指针的,而且这个时候tellp()是0。此模式下只能在后面追加着写。
另外,如果想要获得指向末尾的位置指针,需要以下写法,这个时候如果文件内没有内容,那么pointer的值会是-1。
ofs.seekp(0, ios::end);
pointer = ofs.tellp();
不等长修改
等长修改就是这样,不等长修改的话,如果长度小于原来,可以写进去,然后添0,或者别的,大于原来的,目前只会tmp覆盖原文件的方法。
就是这样,嗯。本来是一定要用不等长修改的,但是后来删除没有实现,也就没有做。