c linux unix io

c - leer() de stdin



linux unix (5)

Considere la siguiente línea de código:

while((n = read(STDIN_FILENO, buff, BUFSIZ)) > 0)

Según mi entendimiento, las funciones de read/write son parte de una E / S no almacenada en búfer. Entonces, ¿significa que la función de read() leerá solo un carácter por llamada desde stdio? O en otras palabras, el valor de n será

-1 in case of error n = 0 in case of EOF 1 otherwise

Si no es así, ¿cuándo volverá la función read() anterior y por qué?

Nota: También estaba pensando que read() esperará hasta que lea con BUFSIZ número de caracteres BUFSIZ de la entrada estándar. Pero, ¿qué sucede en un caso la cantidad de caracteres disponibles para leer es menor que BUFSIZ ? ¿Se leerá esperar para siempre o hasta que llegue EOF ( Ctrl + D en Unix o Ctrl + Z en Windows)?

Además, digamos BUFSIZ = 100 y stdin = ACtrl+D (es decir, EOF inmediatamente después de un solo carácter). Ahora, ¿cuántas veces se repetirá el while loop ?


  1. Leer intentos de obtener todos los caracteres solicitados.
  2. Si EOF ocurre antes de que todos los caracteres solicitados puedan ser devueltos, devuelve lo que obtuvo después de hacer esto, la siguiente lectura devuelve -1, para hacerle saber el final del archivo.

Lo que sucede cuando intenta leer y no hay nada allí implica algo que se llama bloqueo. Puede llamar abierto para leer un archivo bloqueando o no bloqueando. "Bloquear" significa esperar hasta que haya algo que devolver.

Esto es lo que ves en un shell esperando una entrada. Se sienta allí. Hasta que pulses volver.

Sin bloqueo significa que la lectura no devolverá bytes de datos si no hay ninguno. Dependiendo de muchos otros factores que harían inutilizable para usted una respuesta completamente correcta, la lectura establecerá errno en algo como EWOULDBLOCK, que le permite saber por qué su lectura devolvió cero bytes. No es necesariamente un error fatal.

Su código podría probar un signo negativo para encontrar EOF o errores


Como read() manual de read() :

Valor de retorno

En caso de éxito, se devuelve el número de bytes leídos (cero indica el final del archivo), y la posición del archivo avanza en este número. No es un error si este número es menor que el número de bytes solicitados; esto puede suceder, por ejemplo, porque hay menos bytes disponibles en este momento (tal vez porque estábamos cerca del final del archivo, o porque estamos leyendo desde una tubería o desde un terminal), o porque read () fue interrumpido por un señal. En caso de error, se devuelve -1, y errno se establece adecuadamente. En este caso, no se especifica si la posición del archivo (si existe) cambia.

Por lo tanto, cada read() leerá hasta el número de bytes especificados; pero puede leer menos. "No almacenado en búfer" significa que si especifica read(fd, bar, 1) , la lectura solo leerá un byte. IO en BUFSIZ intenta leer en cantidad de BUFSIZ , incluso si solo desea un carácter. Esto puede parecer un desperdicio, pero evita la sobrecarga de hacer llamadas al sistema, lo que lo hace rápido.


Cuando decimos que la read tiene búfer, significa que no se realiza el almacenamiento en búfer en el nivel de su proceso después de que los datos se extraen de la descripción del archivo abierto subyacente, que es un recurso potencialmente compartido. Sin embargo, si stdin es un terminal, es probable que haya al menos 2 buffers adicionales en juego:

  1. El búfer del terminal, que probablemente puede contener 1-4k de datos de la línea hasta.
  2. El búfer de modo canónico / cocinado del kernel para la entrada / edición de línea en un terminal, lo que permite al usuario realizar la edición primitiva (retroceso, backword, borrar línea, etc.) en la línea hasta que se envía (al búfer descrito anteriormente) presionando Intro .

read extraerá todo lo que ya se haya enviado, hasta la longitud máxima de lectura que le pasaste, pero no puede extraer nada del búfer de edición de línea. Si desea deshabilitar esta capa adicional de almacenamiento en búfer, debe buscar cómo deshabilitar el modo cocinado / canónico para una terminal usando tcsetattr , etc.


La forma en que se comporta la lectura () depende de lo que se está leyendo. Para los archivos normales, si solicita N caracteres, obtendrá N caracteres si están disponibles, menos que N si interviene el final del archivo.

Si read () está leyendo desde un terminal en modo canónico / cocinado, el controlador tty proporciona datos una línea a la vez. Por lo tanto, si le dice a read () que obtenga 3 caracteres o 300, read se bloqueará hasta que el controlador tty haya visto una nueva línea o la tecla EOF definida del terminal, y luego read () regresará con el número de caracteres en la línea o número de caracteres que ha solicitado, el que sea menor.

Si read () está leyendo desde un terminal en modo no canónico / en bruto, read tendrá acceso a las pulsaciones de teclas inmediatamente. Si solicita a read () que obtenga 3 caracteres, puede regresar con entre 0 y 3 caracteres, dependiendo de la temporización de entrada y cómo se configuró el terminal.

read () se comportará de manera diferente ante las señales, regresando con menos del número de caracteres que solicita, o -1 con errno establecido en EINTR si una señal interrumpió la lectura antes de que llegara algún carácter.

read () se comportará de manera diferente si el descriptor se ha configurado para la E / S sin bloqueo. read () devolverá -1 con errno establecido en EAGAIN o EWOULDBLOCK si no hay entrada disponible de inmediato. Esto se aplica a los enchufes.

Entonces, como puede ver, debe estar preparado para las sorpresas cuando llame a read (). No siempre obtendrá la cantidad de caracteres que solicitó, y es posible que reciba errores no fatales como EINTR, lo que significa que debe volver a intentar leer ().


Su código lee:

while((n = read(0, buff, BUFSIZ) != 0))

Esto es defectuoso, los paréntesis significan que se interpreta como:

while ((n = (read(0, buff, BUFSIZ) != 0)) != 0)

donde la condición booleana se evalúa antes de la asignación, por lo que n solo obtendrá los valores 0 (la condición no es verdadera) y 1 (la condición es verdadera).

Deberías escribir:

while ((n = read(0, buff, BUFSIZ)) > 0)

Esto se detiene en EOF o en un error de lectura, y n permite saber qué condición encontró.

Al parecer, el código anterior era un error tipográfico en la pregunta.

La E / S no almacenada leerá hasta la cantidad de caracteres que lea (pero no más). Puede leer menos a causa de EOF o un error. También puede leer menos porque hay menos disponible en el momento de la llamada. Considera una terminal; por lo general, eso solo se leerá hasta el final de la línea porque no hay más disponible que eso. Considera una pipa; Si el proceso de alimentación ha generado 128 bytes no leídos, entonces si BUFSIZ es 4096, solo obtendrá 128 bytes de la lectura. Un descriptor de archivo no bloqueante puede regresar porque no hay nada disponible; un socket puede devolver menos bytes porque aún no hay más información disponible; una lectura de disco puede devolver menos bytes porque quedan menos del número solicitado de bytes en el archivo cuando se realiza la lectura.

En general, sin embargo, read() no devolverá solo un byte si solicita muchos bytes.