正如其他答案中所建议的,构建文件映射可能是一个好主意。我这样做的方式(以伪代码)是:
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)
。然后,您只需通过计算存储行号偏移量的位置的偏移量来查找映射文件,并读取该偏移量以及下一行偏移量。从那里您可以得到数据应位于的数字范围(以字节为单位)。
Example:
Data:
hello\n
world\n
(\n newline at end of file)
创建地图。
Map:每个分组[数字]将代表文件中的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
现在假设我想要第 2 行:
line offset = 2-1 * 8 // offset is 8
因为我们使用的是基于 0 的系统,所以它是文件中的第 9 个字节。因此,数字由字节 9 - 17 组成,它们是:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000111
//or as decimal
7
现在我们知道 out 行应该从数据文件中的偏移量 7 开始(该偏移量以 1 为基数,如果我们从 0 开始计数,则为 6)。
然后我们执行相同的过程来获取下一行的起始偏移量,即 14。
最后我们查找字节范围 7-14(基数 1、6-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()) {
//use better error handling than this
throw std::runtime_error("Error opening files");
}
std::string inputData;
std::size_t offset = 0;
while(std::getline(inputFile, inputData)){
//write the offset as binary
outfile.write((const char*)&offset, sizeof(offset));
//increment the counter
offset+=inputData.length()+2;
//add one becuase getline strips the \n and add one to make the index represent the next line
}
outfile.close();
offset=0;
//from here on we are reading the map
std::ifstream inmap("/Users/alexanderzywicki/Documents/xcode/textsearch/textsearch/map",std::ios::binary);
std::size_t line = 2;//your chosen line number
std::size_t idx = (line-1) * sizeof(offset); //the calculated offset
//seek into the map
inmap.seekg(idx);
//read the binary at that location
inmap.read((char*)&offset, sizeof(offset));
std::cout<<offset<<std::endl;
//from here you just need to lookup from the data file in the same manor
return 0;
}