C++ 在C+中替换、添加和删除大型文本文件中的行+;

C++ 在C+中替换、添加和删除大型文本文件中的行+;,c++,windows,C++,Windows,我有一些大的文本文件(>1Gb),需要替换或删除一些行。我需要能够替换一个随机选择的行与另一个,删除它或插入一行接一行 我曾尝试使用getline(file,line)计算行数,这花费了太多时间。这也会导致很长的时间来达到一行的数字 有没有更有效或更好的方法来做到这一点?我认为您可以使用一个数据库来保存每一行。表的每一行可以有两列(ID和line)。归档数据库后,您可以要求数据库提供一行随机ID。您必须考虑到,为了更改一行,您需要读取整个文件,搜索该行,更改它,然后写入整个文件。是的,这很糟糕,

我有一些大的文本文件(>1Gb),需要替换或删除一些行。我需要能够替换一个随机选择的行与另一个,删除它或插入一行接一行

我曾尝试使用
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”到达最后一行并计算总行数