如果我有一个大的二进制文件(比如它有100,000,000个浮点数),C(或C ++)中有没有办法打开文件并读取特定的浮点数,而不必将整个文件加载到内存中(即如何我可以快速找到第62,821,214号浮标是什么)?第二个问题,有没有办法在不必重写整个文件的情况下更改文件中的特定浮点数?
我正在设想以下功能:
float readFloatFromFile(const char* fileName, int idx) {
FILE* f = fopen(fileName,"rb");
// What goes here?
}
void writeFloatToFile(const char* fileName, int idx, float f) {
// How do I open the file? fopen can only append or start a new file, right?
// What goes here?
}
答案 0 :(得分:19)
你知道浮点数的大小是sizeof(float)
,所以乘法可以让你到达正确的位置:
FILE *f = fopen(fileName, "rb");
fseek(f, idx * sizeof(float), SEEK_SET);
float result;
fread(&result, sizeof(float), 1, f);
同样,您可以使用此方法写入特定位置。
答案 1 :(得分:4)
fopen允许使用rb+
上的wb+
或fopen
模式打开文件进行修改(而不仅仅是追加)。见这里:http://www.cplusplus.com/reference/clibrary/cstdio/fopen/
要将文件定位到特定的浮动广告,您可以使用fseek
作为偏移广告index*sizeof(float)
作为预设使用SEEK_SET
。见这里:http://www.cplusplus.com/reference/clibrary/cstdio/fseek/
答案 2 :(得分:3)
如果您想使用C ++流,可以使用以下示例:
#include <fstream>
using namespace std;
int main()
{
fstream file("floats.bin", ios::binary);
float number;
file.seekp(62821214*sizeof(float), ios::beg);
file.read(reinterpret_cast<char*>(&number), sizeof(float));
file.seekp(0, ios::beg); // move to the beginning of the file
number = 3.2;
// write number at the beginning of the file
file.write(reinterpret_cast<char*>(&number), sizeof(float));
}
答案 3 :(得分:0)
一种方法是在文件上调用mmap()。完成后,您可以读取/修改文件,就好像它是内存中的数组一样。
当然,只有当文件足够小以适应进程的地址空间时,该方法才有效...如果你在64位模式下运行,你会没事的;在32位模式下,一个包含100,000,000个浮点数的文件应该适合,但是高于该数量的另一个或两个数量级,您可能会遇到麻烦。
答案 4 :(得分:-1)
我知道这个问题已经得到解答,但Linux / Unix提供了在文件中间轻松读/写(pread / pwrite)的系统调用。如果你看一下系统调用'read'&amp ;;的内核源代码。 'pread',最终都调用vfs_read()。而vfs_read需要一个OFFSET,即它需要一个POSITION来从文件中读取。在pread中,这个偏移量由我们给出,在read()中,偏移量在内核中计算并为文件描述符维护。与read()和pread相比,pread()提供了出色的性能,您可以在文件的不同部分的多个线程中同时读取/写入相同的文件描述符。我的Humble opionion,从不使用read()或其他文件流,使用pread()。希望文件流库包装read()调用,通过减少系统调用,流表现良好。
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
char* buf; off_t offToStart = id * sizeof(float); size_t sizeToRead = sizeof(float);
int fd = open("fileName", O_RDONLY);
ret = pread(fd, buf, sizeToRead, offToStart);
//processs from the read 'buf'
close(fd);
}