使用 c++ 同时读取和写入同一文件

Reading and writing the same file simultaneosly with c++

本文关键字:文件 读取 c++ 使用      更新时间:2023-10-16

我正在尝试在循环浏览文件行时读取和写入文件。在每一行,我将进行评估,以确定是要将其写入文件还是跳过它并移至下一行。这基本上是我目前所拥有的骨架。

void readFile(char* fileName)
{
char line[1024];
fstream file("test.file", ios::in | ios::out);
if(file.is_open())
{
while(file.getline(line,MAX_BUFFER))
{
//evaluation
file.seekg(file.tellp());
file << line;
file.seekp(file.tellg());
}
}
}

当我阅读这些行时,我似乎对复制到行变量中的字符串的起始索引有问题。例如,我可能期望行变量中的字符串是"000/123/FH/",但它实际上是"123/FH/"。我怀疑我对file.seekg(file.tellp())和file.seekp(file.tellg())有问题,但我不确定它是什么。

从您的代码[1]和问题描述中不清楚文件中的内容以及为什么您希望"000/123/FH/",但我可以声明getline函数是缓冲输入,您没有代码来访问缓冲区。 通常,不建议同时使用缓冲和非缓冲 I/O,因为它需要深入了解缓冲机制,然后依赖于该机制,以免在库升级时更改。

您似乎想要进行字节或字符[2]级别的操作。 对于小文件,应将整个文件读入内存,对其进行操作,然后覆盖原始文件,需要打开、读取、关闭、打开、写入、关闭顺序。 对于大文件,您将需要使用fread和/或其他一些较低级别的 C 库函数。

由于您使用的是C++,因此最好的方法是创建自己的类,该类处理读取并将行分隔符[3]包含在现成的循环缓冲区之一(使用 malloc 或插件分配器,如类似 STL 的容器的情况下)或作为模板开发的循环缓冲区,而不是静态分配的字节数组(如果您希望高速低资源利用率)。 在后一种情况下,大小至少需要与最长线一样大。[4]

无论哪种方式,您都希望添加到类中以二进制模式打开文件,并向任意行公开所需的方法来执行行级操作。 有人说(我个人也同意)利用Bjarne Stroustrup在C++中的类封装是类更容易仔细测试。 这样的线路操作类将封装随机存取 C 函数和无缓冲 I/O,并留下最大化速度的机会,同时允许在系统和应用程序中即插即用。

笔记

[1] 查找当前位置只是测试函数,在代码的当前状态下,还没有重新定位当前文件指针。

[2] 请注意,在当今的计算环境中,字符级和字节级操作之间存在差异,其中 utf-8 或其他一些 unicode 标准现在在许多领域比 ASCII 更常见,尤其是在 Web 领域。

[3] 请注意,行分隔符取决于操作系统、版本,有时还取决于设置。

[4] 循环缓冲区在速度方面的优势在于,您可以一次使用 fread 读取多行,并使用快速迭代来查找下一行。

从 Douglas Daseeco 的回应中汲取灵感,我通过简单地读取现有文件,将其行写入新文件,然后重命名新文件以覆盖原始文件来解决我的问题。下面是我的解决方案的骨架。

char line[1024];
ifstream inFile("test.file");
ofstream outFile("testOut.file");
if(inFile.is_open() && outFile.is_open())
{               
while(inFile.getline(line,1024))
{
// do some evaluation
if(keep)
{
outFile << line;
outFile << "n";
}
}
inFile.close();
outFile.close();
rename("testOut.file","test.file");
}

您正在读取和写入同一个文件,最终可能会在文件中出现重复的行。

你会发现这非常有用。想象一下你第一次到达while循环并从你file.getline(line, MAX_BUFFER)的文件的开头开始。现在,get 指针(用于读取)从文件开头(您的起点)移动到MAX_BUFFER位置。

确定写回文件后seekp()有助于指定相对于参考点要写入的位置,语法:file.seekp(num_bytes,"ref");refios::beg(beginning), ios::end, ios::cur的位置(文件中的当前位置)。

就像在阅读后的代码中一样,找到一种方法来使用MAX_BUFFER来引用相对于引用的位置。

while(file.good())
{
file.getline(line,MAX_BUFFER);
...
if(//for some reasone you want to write back)
{
// set put-pointer to location for writing
file.seekp(num_bytes, "ref");
file << line;

}
//set get-pointer to desired location for the next read
file.seekg(num_bytes, "ref");

}