2009-11-08 20 views
6

Si tengo un archivo binario grande (digamos que tiene 100,000,000 flotantes), ¿hay alguna manera en C (o C++) para abrir el archivo y leer un flotación específica, sin tener que cargar todo el archivo en la memoria (es decir, ¿cómo puedo encontrar rápidamente lo que es el flotador 62,821,214º)? Una segunda pregunta, ¿hay alguna manera de cambiar esa flotación específica en el archivo sin tener que reescribir todo el archivo?Leyendo y escribiendo en el medio de un archivo binario en C/C++

estoy imaginando funciones como:

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

Para escribir, asegúrese de abrir en modo "r +" y no "a +". En modo de adición, independientemente de dónde busque, las escrituras siempre van al final del archivo. –

Respuesta

19

se conoce el tamaño de un flotador es sizeof(float), por lo que la multiplicación se puede llegar a la posición correcta:

FILE *f = fopen(fileName, "rb"); 
fseek(f, idx * sizeof(float), SEEK_SET); 
float result; 
fread(&result, sizeof(float), 1, f); 

Del mismo modo, puede escribir a una posición específica usando este método.

+0

Bien, genial. Debe ser fread (y resultado, sizeof (resultado), 1, f); aunque correcto? – Switch

+0

Oh, tienes toda la razón. Lo arreglaré. –

4

fopen permite abrir un archivo para su modificación (no solo para anexar) utilizando el modo rb+ o wb+ en fopen. Ver aquí: http://www.cplusplus.com/reference/clibrary/cstdio/fopen/

para colocar el archivo a un flotador específico, puede utilizar el fseek utilizando index*sizeof(float) como el anuncio de compensación SEEK_SET como el orign. Ver aquí: http://www.cplusplus.com/reference/clibrary/cstdio/fseek/

+0

"rb +" funcionará, pero "wb +" trunca el archivo si existe – marcin

3

Aquí es un ejemplo si desea utilizar flujos de 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)); 
} 
0

Una forma sería llamar mmap() en el archivo. Una vez que haya hecho eso, puede leer/modificar el archivo como si fuera una matriz en memoria.

Por supuesto, ese método solo funciona si el archivo es lo suficientemente pequeño como para caber en el espacio de direcciones de su proceso ... si está ejecutando en modo de 64 bits, estará bien; en el modo de 32 bits, un archivo con 100.000,000 flotantes debería caber, pero otro orden o dos de magnitud por encima de eso y podría tener problemas.

-1

Sé que ya se ha respondido esta pregunta, pero Linux/Unix proporciona llamadas fáciles al sistema para leer/escribir (pread/pwrite) en el medio de un archivo. Si observa el código fuente del kernel para las llamadas al sistema 'leer' & 'pread', ambas eventualmente llaman al vfs_read(). Y vfs_read requiere un DESPLAZAMIENTO, es decir, requiere una POSICIÓN para leer del archivo. En pread, este desplazamiento lo damos nosotros y en read() el desplazamiento se calcula internamente en el kernel y se mantiene para el descriptor del archivo. pread() ofrece un rendimiento excepcional en comparación con read() y el uso de pread, puede leer/escribir en el mismo descriptor de archivo simultáneamente en varios subprocesos en diferentes partes del archivo. Opción My Humble, nunca use read() u otras secuencias de archivos, use pread(). Espero que las bibliotecas de filestream hayan envuelto las llamadas de lectura(), las secuencias funcionan bien haciendo menos llamadas al sistema.

#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); 
} 
+0

no se puede leer el archivo binario con esta solución. – LOLKFC