2010-04-19 14 views
7

De modo que una secuencia FILE puede tener búferes de entrada y salida. Puede ajustar la secuencia de salida utilizando setvbuf (no conozco ningún método para jugar con el tamaño y el comportamiento del búfer de entrada).¿Buffer de entrada y salida predeterminado para archivos fopen'd?

Además, de forma predeterminada, el almacenamiento intermedio es BUFSIZ (no estoy seguro de si esto es una cosa de POSIX o C). Está muy claro lo que esto significa para stdin/stdout/stderr, pero ¿cuáles son los valores predeterminados para los archivos recién abiertos? ¿Están almacenados en búfer tanto para entrada como para salida? ¿O tal vez solo uno?

Si se almacena en el búfer, ¿la salida predeterminada es bloquear o modo de línea?

EDIT: He hecho algunas pruebas para ver cómo la respuesta de Jonathan Leffler afectó a los programas del mundo real. Parece que si haces una lectura, entonces escribes. La escritura hará que la porción no utilizada del búfer de entrada caiga por completo. De hecho, habrá algunas búsquedas que se realizan para mantener las cosas en las compensaciones de archivos correctas. He utilizado este sencillo programa de pruebas:

/* input file contains "ABCDEFGHIJKLMNOPQRSTUVWXYZ" */ 
#include <stdio.h> 
#include <stdlib.h> 

int main() { 

    FILE *f = fopen("test.txt", "r+b"); 
    char ch; 
    fread(&ch, 1, 1, f); 
    fwrite("test", 4, 1, f); 
    fclose(f); 
    return 0; 
} 

resultó en el sistema siguiente llama:

read(3, "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n", 4096) = 27 // attempt to read 4096 chars, got 27 
lseek(3, -26, SEEK_CUR)     = 1  // at this point, I've done my write already, so forget the 26 chars I never asked for and seek to where I should be if we really just read one character... 
write(3, "test", 4)      = 4  // and write my test 
close(3)        = 0 

Si bien estos son claramente los detalles de implementación que nos parecieron ser muy interesante en cuanto a cómo podría ser la biblioteca estándar implementado. Gracias a Jonathan por tu perspicaz respuesta.

+0

BUFSIZ está en el estándar C - también está en POSIX, por lo tanto. –

+1

Comportamiento no definido: debe 'fseek()' entre 'fread()' y 'fwrite()' - y cuando no lo haga, la implementación puede hacer lo que quiera (que puede o no ser lo que desea). –

Respuesta

6

Un solo flujo de archivos tiene un solo búfer. Si el archivo se usa tanto para la entrada como para la salida, debe asegurarse de realizar las operaciones apropiadas (fseek() o equivalentes) entre las operaciones de lectura y escritura (o escritura y lectura).

El comportamiento de almacenamiento en búfer de los canales estándar depende de la plataforma.

Normalmente, la salida estándar se almacena en la línea cuando la salida va al terminal. Sin embargo, si stdout va a un archivo o conducto en lugar de a un terminal, por lo general cambia al almacenamiento en búfer completo.

Normalmente, stderr está en línea con búfer o sin búfer, para garantizar que se vean los mensajes de error (por ejemplo, incluso si el programa está a punto de bloquearse).

Por lo general, stdin tiene línea de buffer; esto significa que tiene la oportunidad de editar su entrada (retroceso de errores, etc.). Rara vez ajustas esto. Nuevamente, si la entrada proviene de un archivo (o tubería), el comportamiento puede ser diferente.

Los archivos recién abiertos por lo general se almacenarán completamente en el búfer. Una implementación particular puede cambiar eso al almacenamiento en línea de la línea si el dispositivo es una terminal.

Su premisa - que hay dos almacenamientos intermedios - es incorrecta.


Sección 7.19.3 de C99, que dice:

al inicio del programa, tres flujos de texto están predefinidos y no es necesario abre explícitamente - entrada estándar (para la lectura de la entrada convencional), norma salida (para escribir salida convencional) y error estándar (para escribir salida de diagnóstico).Como inicialmente se abrió , la secuencia de error estándar no está totalmente almacenada en el búfer; la entrada estándar y las corrientes de salida estándar están completamente almacenadas en el búfer si y solo si se puede determinar que la secuencia no se refiere al en un dispositivo interactivo.

Así que, como se dijo inicialmente, stderres ya sea sin búfer o búfer de línea (no es amortiguada por completo).

+0

¿No se permiten dos almacenamientos intermedios? Me resultaría mucho más fácil de implementar si solo fueran dos buffers después de que todo el estándar diga que los buffers predeterminados se asignan en el primer uso. Digo esto porque si bien sería claro que una operación de entrada podría borrar el búfer de cualquier carácter de salida (el búfer ahora está libre, podría usarse para la entrada ...), lo contrario es más complejo de manejar. –

+0

También encontré que el estándar dice que 'stderr' está por defecto sin búfer. –

+0

Dos búferes serían significativamente más complejos (aparte de requerir el doble de memoria). Por ejemplo, si lee desde el búfer de entrada, vuelva a fseek() hasta donde acaba de empezar a leer y luego escriba(), debe asegurarse de copiar los datos del búfer de salida (hipotético) sobre (buffer hipotético de entrada. –

Cuestiones relacionadas