C++ 在文件中存储大量由分隔符分隔的整数键值对的最有效方法
我有一个系统,其中两个程序同时读写一个包含大量无符号整数对的文件。该键可以有一个值[0,2^16],该值可以有一个值[0,2^32]。我目前正在将这些整数作为字符存储在文件中,其中每对都在自己的行上,键和值由一个空格分隔,所有值都有10个字符 这10个字符的原因有两个:1.最大的无符号整数(解释为字符)长度为10个字符;2.我正在使用mmap将文件映射到两个程序的内存中,使用map_SHARED标志。当写入文件的程序第一次运行时,它将线性扫描文件并构造一个哈希映射映射指向值的指针的键。当编写器希望将新的键-值对放入文件时,它将在哈希映射中搜索该键,如果该键存在,它将覆盖存储在与该键关联的地址中的值。我确保所有值在文件中存储为10个字符,较小的值将填充到该文件中ht使用空格,这样编写器就可以始终简单地覆盖该地址的值,而不必再次对内存、munmap和mmap进行疯狂的洗牌 但是,将整数作为字符串存储在文件中效率极低,我想知道如何更有效地完成三件事:C++ 在文件中存储大量由分隔符分隔的整数键值对的最有效方法,c++,file,file-io,integer,mmap,C++,File,File Io,Integer,Mmap,我有一个系统,其中两个程序同时读写一个包含大量无符号整数对的文件。该键可以有一个值[0,2^16],该值可以有一个值[0,2^32]。我目前正在将这些整数作为字符存储在文件中,其中每对都在自己的行上,键和值由一个空格分隔,所有值都有10个字符 这10个字符的原因有两个:1.最大的无符号整数(解释为字符)长度为10个字符;2.我正在使用mmap将文件映射到两个程序的内存中,使用map_SHARED标志。当写入文件的程序第一次运行时,它将线性扫描文件并构造一个哈希映射映射指向值的指针的键。当编写器希
一般来说,文件的结构是否可以像数据结构一样,可以通过二进制搜索之类的方式进行排序?如果可以,我将如何进行排序?数据存储: 我建议您以二进制形式存储数据,这将在一定程度上减少文件大小 数据访问:我认为
mmap()
是一个好主意(特别是如果您使用像这样的跨平台解决方案)
搜索:由于
mmap()
ing将提供一些指针来处理数据,因此您应该能够将其作为原始C样式数组使用,或者将其包装在中并与标题功能一起使用。我最终实现了一个我正在寻找的解决方案,该解决方案具有以下功能:
struct Pair { uint32_t index[]; };
struct PairArray { uint64_t index[]; };
size_t getFilesize(const char* filename) {
struct stat st;
stat(filename, &st);
return st.st_size;
}
void binarySearch(const PairArray* const pairArray,
uint16_t numElements, uint32_t key, uint32_t*& value) {
int mid = numElements/2;
if (numElements == 0) return;
// interpret the pair as an array of 4 byte key and value
const Pair* pair = reinterpret_cast<const Pair*>(&(pairArray->index[mid]));
// new pointer to pass into recursive call
const PairArray* const newPairArray = reinterpret_cast<const PairArray* const>(
&(pairArray->index[mid + 1]));
// if key is found, point pointer passed by reference to value
if (key == pair->index[0]) {
value = const_cast<uint32_t*>(&pair->index[1]);
return;
}
// if search key is less than current key, binary search on left subarray
else if (key < pair->index[0]) {
binarySearch(pairArray, mid, key, value);
}
// otherwise, binary search on right subarray
else (numElements%2 == 0)
? binarySearch(newPairArray, mid - 1, key, value)
: binarySearch(newPairArray, mid, key, value);
}
int main(int argc, char** argv) {
...
// get size of the file
size_t filesize = getFilesize(argv[1]);
// open file
int fd = open(argv[1], O_RDWR, 0);
if (fd < 0) {
std::cerr << "error: file could not be opened" << std::endl;
exit(EXIT_FAILURE);
}
// execute mmap:
char* mmappedData = static_cast<char*>(
mmap(NULL, filesize, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0));
if (mmappedData == NULL) {
std::cerr << "error: could not memory map file" << std::endl;
exit(EXIT_FAILURE);
}
// interpret the memory mapped file as an array of 8 byte pairs
const PairArray* const pairArray = reinterpret_cast<PairArray*>(mmappedData);
// spin until file is unlocked, and take lock for yourself
while(true) {
int gotLock = flock(fd, LOCK_SH);
if (gotLock == 0) break;
}
// binary search for key value pair
uint32_t* value = nullptr;
binarySearch(pairArray, filesize/8, key, value);
(value == nullptr)
? std::cout << "null" << std::endl
: std::cout << *value << std::endl;
// release lock
flock(fd, LOCK_UN);
...
}
struct Pair{uint32_t index[];};
结构PairArray{uint64_t index[];};
大小\u t getFilesize(常量字符*文件名){
结构统计;
stat(文件名,&st);
返回st.st_大小;
}
无效二进制搜索(常量PairArray*常量PairArray,
uint16元素、uint32键、uint32键*&值){
int mid=numElements/2;
如果(numElements==0)返回;
//将该对解释为4字节密钥和值的数组
const Pair*Pair=reinterpret_cast(&(pairArray->index[mid]);
//传递到递归调用的新指针
const PairArray*const newPairArray=重新解释(
&(pairArray->index[mid+1]);
//若找到键,则通过引用传递给值的点指针
如果(键==对->索引[0]){
value=const_cast(&pair->index[1]);
返回;
}
//若搜索键小于当前键,则在左侧子数组上进行二进制搜索
else if(键index[0]){
二进制搜索(pairArray、mid、key、value);
}
//否则,在右侧子阵列上进行二进制搜索
其他(数值%2==0)
?二进制搜索(newPairArray,mid-1,键,值)
:binarySearch(newPairArray、mid、键、值);
}
int main(int argc,字符**argv){
...
//获取文件的大小
size_t filesize=getFilesize(argv[1]);
//打开文件
int fd=打开(argv[1],O_RDWR,0);
如果(fd<0){
std::cerr您能将当前的实现与需求分开一点吗?例如,列出您希望支持的操作类型?@KarolyHorvath现在,编写程序只需要设置一个键值对,而读取程序只需要获得一个与键值关联的值。但我认为允许wr是很好的正在使用程序删除一对。为什么文件的大小很重要?您是在磁盘空间严重受限的系统上,还是在内存非常有限的系统上?您是否在2^32个可能的值中有一个值,可以指定为NULL
?如果内存足够,2^16个密钥可以存储在一个数组中。谢谢您的建议。我有实现了一个解决方案,并回答了这个问题!