C++ 在C+中替换、添加和删除大型文本文件中的行+;
我有一些大的文本文件(>1Gb),需要替换或删除一些行。我需要能够替换一个随机选择的行与另一个,删除它或插入一行接一行 我曾尝试使用C++ 在C+中替换、添加和删除大型文本文件中的行+;,c++,windows,C++,Windows,我有一些大的文本文件(>1Gb),需要替换或删除一些行。我需要能够替换一个随机选择的行与另一个,删除它或插入一行接一行 我曾尝试使用getline(file,line)计算行数,这花费了太多时间。这也会导致很长的时间来达到一行的数字 有没有更有效或更好的方法来做到这一点?我认为您可以使用一个数据库来保存每一行。表的每一行可以有两列(ID和line)。归档数据库后,您可以要求数据库提供一行随机ID。您必须考虑到,为了更改一行,您需要读取整个文件,搜索该行,更改它,然后写入整个文件。是的,这很糟糕,
getline(file,line)
计算行数,这花费了太多时间。这也会导致很长的时间来达到一行的数字
有没有更有效或更好的方法来做到这一点?我认为您可以使用一个数据库来保存每一行。表的每一行可以有两列(ID和line)。归档数据库后,您可以要求数据库提供一行随机ID。您必须考虑到,为了更改一行,您需要读取整个文件,搜索该行,更改它,然后写入整个文件。是的,这很糟糕,但文件本质上是连续的,如果不访问之前的所有文件,您就无法到达某个位置。根据实际问题,您基本上有两种选择: 1) 如果对文件重复执行此操作,则可以使用更高级的数据结构对其进行优化。基本上,您不再存储平面文本文件,而是存储行集合。这可以通过为每行添加一个带有偏移量的头文件来实现,这是一个额外的增量文件,包含所有更改(当然,在读取时必须考虑这些更改),仅在开始变大或操作完成时应用,甚至可以将所有行保留在更传统的DBMS中
2) 如果每个文件很少执行此操作,则可能希望稍微优化一下读取例程。你可能有最好的机会,通过扫描整个文件,并自己扫描它的下线,因为你可以通过这种方式摆脱一大堆内存分配/字符串拷贝。虽然
mmap
显然会在后台造成内存压力,但我发现这种技术在实践中速度相当快,而且非常容易实现。我相信,在您的情况下,最好的选择是使用内存映射文件。我会帮你的
下面是一个在Windows中使用内存映射文件的简单示例。我省略了错误检查代码,并将任务简化为将随机字符串的字符替换为“?”。这样做只是为了概述主要方面:
1) 创建内存映射文件(CreateFile->CreateFileMapping->MapViewOfFile)
2) 处理它,因为它只是一个内存块。是的,如果你需要在线模式下处理,你必须从一开始就扫描,但我相信这是最快的方法
重要提示:实际任务可能需要减少或扩展原始文件。减少它很容易——只需将相应的部分向后移动,并在关闭时截断文件。扩张需要更复杂的技术
3) 不要忘记使用unmpviewoffile/CloseHandle释放资源
#include "stdafx.h"
#include <Windows.h>
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR fileName[] = _T("SomeHugeFile.dat");
HANDLE hFile = CreateFile(
fileName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (!hFile) {
// Process the error
}
DWORD fileSize = GetFileSize(hFile, NULL);
if (!fileSize) {
// Check if it's an actual errro with GetLastError
// and process accordingly if so
}
HANDLE hMemMappedFile = CreateFileMapping(
hFile,
NULL,
PAGE_READWRITE,
0,
0,
NULL
);
if (!hMemMappedFile) {
// Process the error
}
LPVOID mappedMemory = MapViewOfFile(
hMemMappedFile,
FILE_MAP_ALL_ACCESS,
0,
0,
0 // To the end of the file
);
DWORD lineToDelete = 3; // Some random line number
// Assuming the file is ASCII and with Unix line endings
char *mappedMemoryStart = (char *)mappedMemory;
char *mappedMemoryEnd = mappedMemoryStart + fileSize;
char *lineStart = NULL;
char *lineEnd = NULL;
// Find the line start:
DWORD lineNumber = 0;
for (lineStart = (char *)mappedMemory; lineStart < mappedMemoryEnd; lineStart++) {
if (*lineStart == '\n') {
lineNumber++;
if (lineNumber == lineToDelete) {
lineStart++;
break;
}
}
}
if (lineStart >= mappedMemoryEnd) {
// Error: has gone beyond file end
}
for (lineEnd = lineStart; lineEnd < mappedMemoryEnd; lineEnd++) {
if (*lineEnd == '\n') {
break;
}
}
// Now mangle the found line:
while (lineStart < lineEnd) {
*lineStart = '?';
lineStart++;
}
UnmapViewOfFile(mappedMemory);
CloseHandle(hMemMappedFile);
CloseHandle(hFile);
return 0;
}
#包括“stdafx.h”
#包括
int _tmain(int argc,_TCHAR*argv[]
{
TCHAR fileName[]=“SomeHugeFile.dat”);
HANDLE hFile=CreateFile(
文件名,
一般的读,一般的写,
0,
无效的
开放式,
文件\u属性\u正常,
无效的
);
如果(!hFile){
//处理错误
}
DWORD fileSize=GetFileSize(hFile,NULL);
如果(!fileSize){
//使用GetLastError检查它是否是实际的erro
//若有,则进行相应处理
}
HANDLE hMemMappedFile=CreateFileMapping(
hFile,
无效的
第页读写,
0,
0,
无效的
);
如果(!hMemMappedFile){
//处理错误
}
LPVOID mappedMemory=MapViewOfFile(
hMemMappedFile,
文件\u映射\u所有\u访问,
0,
0,
0//到文件末尾
);
DWORD lineToDelete=3;//一些随机行号
//假设文件为ASCII且具有Unix行结尾
char*mappedMemoryStart=(char*)mappedMemory;
char*mappedMemoryEnd=mappedMemoryStart+文件大小;
char*lineStart=NULL;
char*lineEnd=NULL;
//查找行开始:
DWORD lineNumber=0;
对于(lineStart=(char*)mappedMemory;lineStart=mappedMemoryEnd){
//错误:已超出文件结尾
}
用于(lineEnd=lineStart;lineEnd
在这种特殊情况下,我不会信任库函数。一个字符接一个字符,并根据需要利用内存。当然,您不能在内存中获得整行数据(多GB),您需要一些技巧,这取决于您的问题规范。请告诉我们更多关于您的目标以及您迄今为止所做的工作。是否保证每行的字符数相同?如果是这样,那么在不使用getline
的情况下,搜索特定行的任务就变得容易多了。问题是当需要将文件与丢失的行放回一起时。我不认为你能很快做到这一点。字符的数量是不一样的,只是一个随机文件可以。而且行数也不得而知。因此,主要的问题是交换两个随机行或从文件中删除一行。到目前为止,我还没有做太多的工作,只是尝试使用“getline”到达最后一行并计算总行数