正如其他答案所建议的那样,构建文件映射可能是一个好主意。我会用伪代码实现这个过程:
let offset be a unsigned 64 bit int =0;
for each line in the file
read the line
write offset to a binary file (as 8 bytes rather as chars)
offset += length of line in bytes
现在您有一个“Map”文件,其中包含64位整数列表(每行一个)。要读取地图,只需计算所需行的条目在地图中的位置:
offset = desired_line_number * 8 // where line number starts at 0
offset2 = (desired_line_number+1) * 8
data_position1 = load bytes [offset through offset + 8] as a 64bit int from map
data_position2 = load bytes [offset2 through offset2 + 8] as a 64bit int from map
data = load bytes[data_position1 through data_position2-1] as a string from data.
这个想法是你只需一次读取数据文件并记录每行开始的字节偏移量,然后使用固定大小的整数类型将偏移量按顺序存储在二进制文件中。映射文件的大小应为
number_of_lines * sizeof(integer_type_used)
。然后,您只需通过计算存储行号偏移的位置的偏移量来查找映射文件,并读取该偏移量以及下一行的偏移量。从那里,您就有了数据所在的字节数值范围。
例子:
数据:
hello\n
world\n
(\n newline at end of file)
创建地图。
地图:每个分组[number]将表示文件中的8个字节长度。
[0][7][14]
//or in binary
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000111
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00001110
现在假设我想要第二行:
line offset = 2-1 * 8 // offset is 8
因为我们使用的是基于0的系统,所以这将会是文件中的第9个字节。所以我们的数字由第9到17个字节组成,它们分别是:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000111
//or as decimal
7
现在我们知道了,我们的数据文件中的行应该从偏移量7开始(此偏移量为基数1,如果我们从0开始计数,则该偏移量将为6)。
然后我们执行相同的过程来获取下一行的起始偏移量,即14。
最后,我们查找字节范围7-14(基础1,0-13基础0),将其存储为字符串并获得world\n
。
C++实现:
#include <iostream>
#include <fstream>
int main(int argc, const char * argv[]) {
std::string filename = "path/to/input.txt";
std::ifstream inputFile(filename.c_str(),std::ios::binary);
std::ofstream outfile("path/to/map/file.bin",std::ios::binary|std::ios::ate);
if (!inputFile.is_open() || !outfile.is_open()) {
throw std::runtime_error("Error opening files");
}
std::string inputData;
std::size_t offset = 0;
while(std::getline(inputFile, inputData)){
outfile.write((const char*)&offset, sizeof(offset));
offset+=inputData.length()+2;
}
outfile.close();
offset=0;
std::ifstream inmap("/Users/alexanderzywicki/Documents/xcode/textsearch/textsearch/map",std::ios::binary);
std::size_t line = 2;
std::size_t idx = (line-1) * sizeof(offset);
inmap.seekg(idx);
inmap.read((char*)&offset, sizeof(offset));
std::cout<<offset<<std::endl;
return 0;
}
bash
,但如果您认为它不合理,我可以删除该标签。 - Remi.b