在c++中替换,添加和删除巨大文本文件中的行
Replacing, adding and deleting lines in huge text file in C++
我有一些大的文本文件(>1Gb),需要替换或删除一些行。我需要能够替换一个随机选择的行与另一个,删除它或插入一行又一行。
我尝试使用getline(file, line)
计算行数-这需要太多时间。这也会导致需要很长时间才能到达一行。
是否有更有效或更好的方法来做到这一点?
您必须考虑到,为了更改一行,您需要读取整个文件,搜索该行,更改它,然后写入整个文件。这确实很糟糕,但文件本质上是连续的,如果不访问所有之前的文件,您就无法到达一个地方。
根据您的实际问题,您基本上有两个选择:
1)如果您对文件重复执行此操作,则可以通过使用更高级的数据结构对其进行优化。基本上,您存储的不再是平面文本文件,而是行集合。这可以通过为每行添加一个带有偏移量的头文件,一个包含所有更改(当然,在读取时必须考虑)的附加增量文件来实现,这些更改仅在它开始变大或操作完成时应用,或者甚至将所有行保留在更传统的DBMS中。
2)如果这个操作很少在每个文件中执行,你可能希望优化一下你的读例程。你可能有最好的机会mmap
整个文件,并扫描它为EOL自己,因为你可以摆脱一大堆的内存分配/字符串副本这种方式。虽然mmap
显然会在后台造成内存压力,但我发现这种技术在实践中相当快,并且非常容易实现。
我认为您可以使用数据库来保存每一行。表的每一行可以有两列(ID和行)。在对数据库进行归档之后,您可以向数据库请求具有随机ID的行。
我认为,在您的情况下,最好的选择是使用内存映射文件。CreateFileMapping和MapViewOfFile将会帮助你。
下面是一个在Windows中使用内存映射文件的简单示例。我省略了错误检查代码,并将任务简化为将随机字符串的字符替换为'?'。这样做是为了只概述主要方面:
1)创建一个内存映射文件(CreateFile -> CreateFileMapping-> MapViewOfFile)
2)处理它,因为它只是一个内存块。是的,如果你需要在行模式下处理,你必须从一开始就扫描它,但我认为映射它将是最快的方法。
重要提示:现实生活中的任务可能需要对原始文件进行缩小或扩展。减少它非常容易——只需将相应的部分移回并在关闭时截断文件。扩展需要更复杂的技术。
3)不要忘记使用UnmapViewOfFile/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;
}
- 文本文件中的单词链表
- 从命令行c++发送文本文件名
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 2D数组来自文本输入,中间有空格
- 如何将内容数组写入文本文件?
- 无法通过空白将文本文件行分隔为矢量
- 我正在使用嵌套的while循环来解析具有多行的文本文件,但由于某种原因,它只通过第一行,我不知道为什么
- C++将文本文件中的数据读取到结构数组中
- 在指针的帮助下,文本文件中单词的频率
- 将字符指针十六进制转换为字符串并保存在文本文件C++中
- 将值从二维数组输出到文本文件
- 在linux上调试巨大的C++项目
- 如何在c++中从文本文件中逐行读取整数
- 如何在一个巨大的文本文件中对整数进行排序
- SFML文本在小视图中显得巨大
- 用带缓冲的c++逐行读取巨大的文本文件
- 巨大的.cpp文件比从文本文件读取更好
- 将巨大的2D矢量写入文本文件太慢,如何提高性能
- 在c++中将一个巨大的文本文件(2Gb以上)分成2个块
- 在c++中替换,添加和删除巨大文本文件中的行