用c++同时读写同一个文件
Reading and writing the same file simultaneosly with c++
我在遍历行时尝试读写文件。在每一行,我都会进行评估以确定是否要将其写入文件或跳过它并移至下一行。这基本上是我目前所拥有的框架。
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
and/or 一些其他较低级别的 C 库函数。
由于您使用的是 C++,因此最好的方法是创建您自己的 class 来处理读取并包括行分隔符 [3][=35= [你想要高速和低资源利用率)。在后一种情况下,大小至少需要与最长的行一样大。 [4]
无论哪种方式,您都希望添加到 class 以在二进制模式下打开文件并公开所需的方法以对任意行进行行级操作。有人说(我个人同意)利用 Bjarne Stroustrup 在 C++ 中的 class 封装是 classes 更容易仔细测试。这样的行操作 class 将封装随机访问 C 函数和无缓冲 i/o 并留出最大化速度的机会,同时允许在系统和应用程序中使用即插即用。
备注
[1]当前位置的查找只是测试功能,还没有在当前代码状态下重新定位当前文件指针。
[2] 请注意,在当今的计算环境中,字符级和字节级操作之间存在差异,在当今的计算环境中,utf-8 或其他一些 unicode 标准现在在许多领域(尤其是网络领域)比 ASCII 更为普遍。
[3] 请注意,行分隔符取决于操作系统、版本,有时还取决于设置。
[4] 循环缓冲区在速度方面的优势在于使用 fread 一次可以读取多行并使用快速迭代找到下一行的结尾。
您正在读取和写入同一个文件,您最终可能会在文件中出现重复行。
您会发现 this 非常有用。想象一下您第一次到达 while 循环并从您执行的文件开头开始 file.getline(line, MAX_BUFFER)
。现在 get 指针(用于读取)从文件开头(您的起点)移动 MAX_BUFFER
个位置。
在您决定写回文件后 seekp()
有助于相对于参考点指定您要写入的位置,语法:file.seekp(num_bytes,"ref");
where ref
将是 ios::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");
}
从 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");
}
我在遍历行时尝试读写文件。在每一行,我都会进行评估以确定是否要将其写入文件或跳过它并移至下一行。这基本上是我目前所拥有的框架。
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
and/or 一些其他较低级别的 C 库函数。
由于您使用的是 C++,因此最好的方法是创建您自己的 class 来处理读取并包括行分隔符 [3][=35= [你想要高速和低资源利用率)。在后一种情况下,大小至少需要与最长的行一样大。 [4]
无论哪种方式,您都希望添加到 class 以在二进制模式下打开文件并公开所需的方法以对任意行进行行级操作。有人说(我个人同意)利用 Bjarne Stroustrup 在 C++ 中的 class 封装是 classes 更容易仔细测试。这样的行操作 class 将封装随机访问 C 函数和无缓冲 i/o 并留出最大化速度的机会,同时允许在系统和应用程序中使用即插即用。
备注
[1]当前位置的查找只是测试功能,还没有在当前代码状态下重新定位当前文件指针。
[2] 请注意,在当今的计算环境中,字符级和字节级操作之间存在差异,在当今的计算环境中,utf-8 或其他一些 unicode 标准现在在许多领域(尤其是网络领域)比 ASCII 更为普遍。
[3] 请注意,行分隔符取决于操作系统、版本,有时还取决于设置。
[4] 循环缓冲区在速度方面的优势在于使用 fread 一次可以读取多行并使用快速迭代找到下一行的结尾。
您正在读取和写入同一个文件,您最终可能会在文件中出现重复行。
您会发现 this 非常有用。想象一下您第一次到达 while 循环并从您执行的文件开头开始 file.getline(line, MAX_BUFFER)
。现在 get 指针(用于读取)从文件开头(您的起点)移动 MAX_BUFFER
个位置。
在您决定写回文件后 seekp()
有助于相对于参考点指定您要写入的位置,语法:file.seekp(num_bytes,"ref");
where ref
将是 ios::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");
}
从 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");
}