2008-11-17 22 views
74

Tuvimos una discusión aquí en el trabajo con respecto a por qué fread y fwrite toman un tamaño por miembro y cuentan y devuelven el número de miembros leídos/escritos en lugar de simplemente tomar un buffer y tamaño. El único uso que podríamos hacer es si se quiere leer/escribir una matriz de estructuras que no son divisibles por la alineación de la plataforma y, por lo tanto, se han rellenado, pero eso no puede ser tan común como para justificar esta elección. en diseño.¿Cuál es el fundamento para tomar el tamaño de fread/fwrite y contar como argumentos?

De FREAD (3):

La función fread() lee nmemb elementos de datos, cada tamaño de bytes de longitud, de la corriente de datos apuntado por flujo, almacenándolos a la ubicación dada por ptr.

La función fwrite() escribe nmemb elementos de datos, cada tamaño bytes largo, en la secuencia a la que apunta el flujo, obteniéndolos de la ubicación dada por ptr.

fread() y fwrite() devuelven el número de elementos leídos o escritos con éxito (es decir, no el número de caracteres). Si se produce un error o se alcanza el final de archivo , el valor de retorno es un recuento breve de elementos (o cero).

+9

hey esta es una buena pregunta. siempre me lo pregunté –

+1

Por favor revisa este hilo: http://stackoverflow.com/questions/8589425/how-does-fread-really-work – Franken

Respuesta

18

Se basa en cómo se implementa fread.

the Single Unix Specification dice

Para cada objeto, llamadas del calibre se hacen a la función fgetc() y los resultados almacenados, en el orden de lectura, en una matriz de char sin signo exactamente superponiendo el objeto.

fgetc también tiene esta nota:

Desde fgetc() opera en bytes, lectura de un personaje que consiste en múltiples bytes (o "un multi-byte carácter") pueden requerir varias llamadas a fgetc().

Por supuesto, esto es anterior a la fantasía de codificaciones de caracteres de bytes variables como UTF-8.

El SUS advierte que esto realmente se toma de los documentos ISO C.

50

La diferencia en fread (buf, 1000, 1, stream) y fread (buf, 1, 1000, stream) es que en el primer caso se obtiene solo un fragmento de 1000 bytes o nuthin, si el el archivo es más pequeño y en el segundo caso obtiene todo en el archivo a menos de y hasta 1000 bytes.

+3

Aunque es cierto, eso solo cuenta una pequeña parte de la historia. Sería mejor contrastar algo leyendo, por ejemplo, una matriz de valores int o una matriz de estructuras. –

+2

Esto sería una gran respuesta si se completa la justificación. –

+0

respuesta práctica. gracias – austin

3

Es probable que regrese a la forma en que se implementó la E/S de archivos. (De vuelta en el día) Podría haber sido más rápido escribir/leer archivos en bloques y luego escribir todo a la vez.

+0

No realmente. La especificación C para fwrite indica que realiza llamadas repetidas a fputc: http://www.opengroup.org/onlinepubs/009695399/functions/fwrite.html – Powerlord

9

Aquí, Voy a corregir esas funciones:

size_t fread_buf(void* ptr, size_t size, FILE* stream) 
{ 
    return fread(ptr, 1, size, stream); 
} 


size_t fwrite_buf(void const* ptr, size_t size, FILE* stream) 
{ 
    return fwrite(ptr, 1, size, stream); 
} 

En cuanto a la justificación de los parámetros a fread()/fwrite(), he perdido mi copia de K & R hace mucho tiempo, así que sólo puedo adivinar. Creo que una posible respuesta es que Kernighan y Ritchie simplemente pensaron que la realización de E/S binarias se haría de forma más natural en arreglos de objetos. Además, pueden haber pensado que la E/S de bloques sería más rápida/más fácil de implementar o lo que sea en algunas arquitecturas.

A pesar de que el estándar C especifica que fread() y fwrite() implementarse en términos de fgetc() y fputc(), recuerda que la norma entró en existencia mucho después de C se define por K & R y que las cosas que se especifican en la norma no podrían haber sido en las ideas originales de los diseñadores. Incluso es posible que las cosas que se dicen en K & R "The C Programming Language" no sean las mismas que cuando se estaba diseñando el idioma por primera vez.

Finalmente, esto es lo PJ Plauger tiene que decir sobre fread() en "La biblioteca estándar de C":

Si el (segundo) argumento size es mayor que uno, no se puede determinar si la función también leyó hasta size - 1 caracteres adicionales más allá de lo que informa. Como regla general, usted es mejor llamar a la función como fread(buf, 1, size * n, stream); en lugar de fread(buf, size, n, stream);

Bascially, él está diciendo que la interfaz fread() 's se ha roto. Para fwrite(), señala que "los errores de escritura son generalmente poco frecuentes, por lo que esta no es una falla importante", una declaración con la que no estoy de acuerdo.

+16

En realidad, a menudo me gusta hacerlo de otra manera: 'fread (buf, size) * n, 1, secuencia); 'Si las lecturas incompletas son una condición de error, es más sencillo hacer que' fread' simplemente devuelva 0 o 1 en lugar de la cantidad de bytes leídos. Luego puede hacer cosas como 'if (! Fread (...))' en lugar de tener que comparar el resultado con el número solicitado de bytes (que requiere código C extra y código de máquina adicional). –

12

Esto es pura especulación, sin embargo, en los últimos tiempos (algunos aún existen), muchos sistemas de archivos no eran flujos de bytes simples en un disco duro.

Muchos sistemas de archivos se basaron en registros, para satisfacer dichos sistemas de archivos de manera eficiente, deberá especificar el número de elementos ("registros"), permitiendo que fwrite/fread funcione en el almacenamiento como registros, no solo flujos de bytes.

+1

Me alegra que alguien haya mencionado esto. Trabajé mucho con las especificaciones del sistema de archivos y el FTP y los registros/páginas y otros conceptos de bloqueo están firmemente respaldados, aunque nadie usa esas partes de las especificaciones nunca más. –

1

Creo que es porque C carece de sobrecarga de funciones. Si hubiera alguno, el tamaño sería redundante. Pero en C no puede determinar el tamaño de un elemento de matriz, debe especificar uno.

Considera:

int intArray[10]; 
fwrite(intArray, sizeof(int), 10, fd); 

Si se acepta fwrite número de bytes, se podría escribir lo siguiente:

int intArray[10]; 
fwrite(intArray, sizeof(int)*10, fd); 

pero es sólo ineficiente. Tendrá sizeof (int) veces más llamadas al sistema.

Otro punto que debe tenerse en cuenta es que normalmente no desea que se escriba una parte de un elemento de matriz en un archivo. Quieres el entero entero o nada. fwrite devuelve una cantidad de elementos escritos con éxito. Entonces, si descubres que solo se escriben 2 bytes bajos de un elemento, ¿qué harías?

En algunos sistemas (debido a la alineación) no puede acceder a un byte de un entero sin crear una copia y desplazamiento.

Cuestiones relacionadas