2010-08-22 18 views
9

He creado un paquete de recursos simple para empaquetar los recursos de mi juego en un solo archivo. Todo iba bien hasta que comencé a escribir el desempaquetador. Noté que el archivo .txt - 26 bytes - que había empaquetado, salió bien del archivo de recursos, sin problemas de todos modos, todos los datos conservados. Sin embargo, al leer el archivo .PNG que había empaquetado en el archivo de recursos, los primeros 5 bytes estaban intactos, mientras que el resto se anuló por completo.fread Sólo los primeros 5 bytes del archivo .PNG

Tracé esto hasta el proceso de empaquetado, y noté que fread solo está leyendo los primeros 5 bytes del archivo .PNG y no puedo entender por qué. Incluso desencadena 'EOF' que indica que el archivo tiene solo 5 bytes de largo, cuando de hecho es un PNG de 787 bytes de un pequeño polígono, 100px por 100px.

Incluso probé este problema al hacer una aplicación por separado para simplemente leer este archivo PNG en un búfer, obtengo los mismos resultados y solo se leen 5 bytes.

Aquí está el código de esa pequeña aplicación separada:

#include <cstdio> 

int main(int argc, char** argv) 
{ 
    char buffer[1024] = { 0 }; 
    FILE* f = fopen("test.png", "r"); 
    fread(buffer, 1, sizeof(buffer), f); 
    fclose(f);  //<- I use a breakpoint here to verify the buffer contents 
    return 0; 
} 

Puede alguien señalar mi error estúpido?

+1

¿Por qué no utilizar las transmisiones en C++? – GManNickG

+0

¿Por qué hay un cero entre los corchetes para "buffer"? –

+0

@Billy: para anular el búfer, sé que no es una forma estándar. –

Respuesta

21

¿Alguien puede señalar mi estúpido error?

plataforma de Windows, supongo?

Utilice esta:

FILE* f = fopen("test.png", "rb"); 

en lugar de esto:

FILE* f = fopen("test.png", "r"); 

Ver msdn para la explicación.

+0

Wow. Muchas gracias. –

+0

Tenga en cuenta que el "rb" está en el estándar C y es portátil. Refleja "rt" que solicita el tratamiento de "texto" de la transmisión, que es el valor predeterminado. El tratamiento de texto en cualquier * nix es igual que el tratamiento binario. En Windows y algunas otras plataformas más oscuras difieren. En resumen, si se trata de datos binarios, siempre especifique "rb" a 'fopen()'. – RBerteig

8

La extensión de la correct answer from SigTerm, aquí es un poco de fondo de qué que tienes el efecto que hizo para la apertura de un archivo PNG en modo texto:

El formato PNG explica su 8-byte file header de la siguiente manera:

Los primeros ocho bytes de un archivo PNG siempre contienen los siguientes valores:

 (decimal)    137 80 78 71 13 10 26 10 
    (hexadecimal)   89 50 4e 47 0d 0a 1a 0a 
    (ASCII C notation) \211 P N G \r \n \032 \n 

Esta firma identifica el archivo como un archivo PNG y proporciona la detección inmediata de problemas comunes de transferencia de archivos. Los primeros dos bytes distinguen los archivos PNG en sistemas que esperan que los primeros dos bytes identifiquen el tipo de archivo de manera única. El primer byte se elige como un valor no ASCII para reducir la probabilidad de que un archivo de texto se reconozca erróneamente como un archivo PNG; también, atrapa las transferencias de archivos defectuosas que borran el bit 7. Bytes de dos a cuatro nombran el formato. La secuencia CR-LF detecta malas transferencias de archivos que alteran las secuencias de nueva línea. El carácter de control-Z detiene la visualización del archivo en MS-DOS. La alimentación de línea final comprueba el inverso del problema de traducción CR-LF.

Creo que en el modo de texto, la llamada a fread() se dio por terminado cuando se leyó el sexto byte que contiene un carácter Ctrl + Z.Ctrl + Z se usó históricamente en MSDOS (y en CPM antes) para indicar el final de un archivo, que era necesario porque el sistema de archivos almacenaba el tamaño de un archivo como un recuento de bloques, no un recuento de bytes.

Al leer el archivo en modo texto en lugar de modo binario, activó la protección contra el uso accidental del comando TYPE para mostrar un archivo PNG.

Una cosa que podría hacer que hubiera ayudado a diagnosticar este error es usar fread() de forma ligeramente diferente. No ha probado el valor de retorno desde fread(). Debieras. Además, debe llamar de esta manera:

... 
size_t nread; 
... 
nread = fread(buffer, sizeof(buffer), 1, f); 

modo que nread es un recuento de los bytes actualmente escritos en el búfer. Para el archivo PNG en modo texto, le habría dicho en la primera lectura que solo leyó 5 bytes. Dado que el archivo no puede ser tan pequeño, habría tenido una pista de que algo más estaba sucediendo. Los bytes restantes del búfer nunca fueron modificados por fread(), lo que se habría visto si inicializó el búfer a algún otro valor de relleno.

Cuestiones relacionadas