2011-06-23 8 views
6

Estoy intentando leer bloques de un archivo y tengo un problema.Uso de búferes para leer desde el archivo de tamaño desconocido

char* inputBuffer = new char[blockSize] 
while (inputFile.read(inputBuffer, blockSize)) { 
    int i = inputFile.gcount(); 
//Do stuff 
} 

Supongamos que nuestro tamaño del bloque es 1024 bytes, y el archivo es 24,3 KiB. Después de leer el bloque 23, quedará 0,3 KiB para leer. También quiero leer que 0,3 KiB, de hecho, uso gcount() más tarde para que pueda saber cuánto de la memoria intermedia modificó read(...) (en caso de que sea menor).
Pero cuando accede al bloque 24, read(...) devuelve un valor tal que el programa no ingresa al bucle, obviamente porque el tamaño de los bytes restantes no leídos en el archivo es menor que el tamaño del búfer. ¿Que debería hacer?

Respuesta

3

Creo que Konrad Rudolf de quien hablas en el comentario a otra respuesta hace una buena observación sobre el problema con la lectura hasta eof. Si nunca llega a eof debido a algún otro error, se encuentra en un ciclo infinito. Así que tome su consejo, pero modifíquelo para abordar el problema que ha identificado. Una forma de hacerlo es la siguiente;

bool okay=true; 
while (okay) { 
    okay = inputFile.read(inputBuffer, blockSize); 
    int i = inputFile.gcount(); 
    if(i) { 
     //Do stuff 
    } 
} 

Editar: Desde que se acepta mi respuesta, la estoy editando para que sea lo más útil posible. Resulta que mi bool está bien no es necesario (ver la respuesta de ferosekhanj). Es mejor probar el valor de inputFile directamente, que también tiene la ventaja de que puede evitar elegantemente ingresar al bucle si el archivo no se abrió correctamente. Entonces creo que esta es la solución canónica a este problema;

inputFile.open("test.txt", ios::binary); 
while (inputFile) { 
    inputFile.read(inputBuffer, blockSize); 
    int i = inputFile.gcount(); 
    if(i) { 
     //Do stuff 
    } 
} 

Ahora la última vez que // hacer cosas, voy a ser menos de blockSize, excepto en el caso de que el archivo pasa a ser un múltiplo de blockSize bytes de longitud.

La respuesta de Konrad Rudolf here también es buena, tiene la ventaja de que .gcount() solo se llama una vez, fuera del bucle, pero tiene la desventaja de que realmente necesita el procesamiento de datos para una función separada, para evitar duplicaciones .

+0

Debe incluir un if (correcto) después de "okay = inputFile.read (...)", por lo que se asegura que el programa nunca funcionará con datos no válidos. Hazlo, así que lo marco como una respuesta aceptada. – Erandros

+0

@Erandos, no, eso no funcionará porque entonces has vuelto al cuadro 1 - ¡no procesarás el último bloque subscrito! En su lugar, quizás agregue if (i), de modo que solo haga cosas si hay datos. –

+0

Tienes razón. Sigo pensando que debería haber un "if (lessThanBufferSizeFlag)". Sin embargo, no sé cómo obtener ese valor de bandera. – Erandros

1

Pero cuando se accede al bloque 24, leer (...) devuelve un valor tal que el programa no entra en el bucle, obviamente, porque el tamaño de los bytes leídos que quedan en el archivo es menor que el buffer tamaño.

Eso es porque el bucle está mal. Que debería estar haciendo:

while(!inputFile) { 
    std::streamsize numBytes = inputFile.readsome(inputBuffer, blockSize); 
//Do stuff 
} 

Aviso el uso de readsome en lugar de read.

+0

Ese bucle está mal?Este hombre representante de 100K dice lo contrario: http://stackoverflow.com/questions/6444876/c-reading-buffer-size/6444962#6444962 Aunque intentaré leerlo. – Erandros

+1

@Erandros: También dice que poner la lectura dentro de la condición de tiempo es "más legible", que es algo que yo cuestionaría. Las declaraciones de condición que realizan el trabajo real pueden ser un modismo establecido en C/C++, pero no necesariamente son buenas o legibles. –

+0

Acepto el problema "más legible". Pero, ¿qué pasa si lo hago y no? Seguiré haciendo cosas con datos corruptos. Asegurar que nunca ocurra fue la ventaja de ese tiempo. – Erandros

3

La solución @Konrad Rudolph mencionada es para verificar el objeto de transmisión en sí, ya que eso incluye verificar eof y la condición de error. El inputFile.read() devuelve la corriente que es ArchivoDeEntrada sí para que pueda escribir como

while(inputFile.read()) 

Pero esto no va a funcionar siempre. El caso donde falla es tu caso. Una solución adecuada sería escribir, como a continuación

char* inputBuffer = new char[blockSize] 
while (inputFile) 
{ 
    inputFile.read(inputBuffer, blockSize); 
    int count = inputFile.gcount(); 
    //Access the buffer until count bytes 
    //Do stuff 
} 

Creo que esta fue la solución de lo que significaba @Konrad Rudolph en su puesto. De mi experiencia anterior de CPP también haría algo como arriba.

+0

Esto también funciona. – Erandros

+0

Estoy de acuerdo, esta es una mejora con respecto a mi solución, así que +1 está bien hecho. –

+0

La única ventaja (muy leve) que mi solución tiene sobre la suya es que solo necesito comprobar 'gcount' una vez, después del ciclo (dentro del ciclo siempre será igual a' blockSize'). Y realmente no me gusta realizar operaciones innecesarias, incluso si son baratas. Dicho esto, su solución es superior tan pronto como el procesamiento del búfer se convierta en algo no trivial (= más que un solo enunciado). –

Cuestiones relacionadas