Entrada y salida de archivos en C

Aprende cómo los programas en C leen y escriben archivos con la biblioteca estándar de entrada y salida. Abre archivos como flujos en el modo adecuado y conecta los programas con la entrada, la salida y la salida de error estándar. Procesa texto carácter a carácter, mediante lecturas y escrituras con formato y línea a línea con fgets. Guarda arrays y registros en archivos binarios con fread y fwrite, diseña formatos de archivo que se lean correctamente en otras máquinas y accede directamente a cualquier registro con fseek. En todo momento, comprueba cada resultado, explica los fallos con errno y libera los recursos para que tus programas fallen de forma segura e informen fielmente del resultado.

PrincipianteUnidad 7 de 8 del curso Curso de Programación en C

Lo que aprenderás

  1. Explicar cómo los programas en C acceden a los archivos mediante flujos con almacenamiento en búfer, abrir y cerrar archivos en el modo adecuado y utilizar los tres flujos estándar con redirección en la línea de comandos.
    • Explicar los flujos, el almacenamiento en búfer y las diferencias entre el modo texto y el modo binario
      Describir qué son un flujo y un FILE *, cómo funcionan el almacenamiento en búfer y la posición en el archivo, y en qué se diferencia el modo texto del modo binario en Windows y en sistemas similares a Unix.
    • Abrir y cerrar archivos con fopen y fclose
      Abrir un archivo en el modo adecuado para la tarea, comprobar que se abrió, localizar archivos mediante rutas y cerrar cada flujo al terminar.
    • Utilizar stdin, stdout y stderr con redirecciones y tuberías
      Utilizar los tres flujos con los que comienza todo programa en C, enviar los resultados y mensajes de error al lugar adecuado y permitir que los usuarios los redirijan desde la línea de comandos.
  2. Procesar archivos de texto carácter a carácter, mediante lecturas y escrituras con formato y línea a línea, eligiendo el patrón seguro para cada caso y comprobando cada resultado.
    • Leer y escribir carácter a carácter
      Utilizar fgetc y fputc con una variable int, detenerse correctamente al llegar al fin de archivo y contar, copiar y transformar texto carácter a carácter.
    • Escribir y leer texto con formato mediante fprintf y fscanf
      Escribir números y cadenas en archivos con una disposición elegida, construir nombres de archivo con sprintf y leer datos con formato mediante fscanf comprobando cuántos elementos convirtió.
    • Leer líneas de forma segura con fgets
      Leer texto una línea a la vez con fgets, gestionar saltos de línea, líneas largas y finales de línea de Windows, y analizar cada línea después de leerla.
  3. Escribir y leer bytes en bruto, arrays y estructuras con fwrite y fread, y diseñar formatos de archivo binarios que se lean correctamente en otras máquinas.
    • Leer y escribir datos binarios con fread y fwrite
      Utilizar fread y fwrite con el tamaño y el número de elementos adecuados, copiar archivos por bloques, reconocer tipos de archivo por sus primeros bytes y almacenar arrays y estructuras.
    • Diseñar formatos binarios que funcionen en distintas máquinas
      Explicar cómo los tamaños de los tipos, el orden de los bytes y el relleno de las estructuras hacen que los archivos binarios en bruto dependan de la máquina, y leer y escribir campos de varios bytes en un formato definido.
  4. Obtener y establecer la posición en el archivo para acceder directamente a los datos que necesitas y actualizar registros de tamaño fijo en su misma posición sin reescribir todo el archivo.
    • Obtener y establecer la posición en el archivo con ftell, fseek y rewind
      Obtener la posición actual, desplazarse a posiciones relativas al principio, al lugar actual o al final, calcular desplazamientos de registros y tamaños de archivos, y conocer las limitaciones de los flujos de texto.
    • Actualizar registros de tamaño fijo en su misma posición
      Abrir un archivo tanto para lectura como para escritura, seguir la regla para alternar entre ambas y modificar, añadir o eliminar registros sin corromper el archivo.
  5. Comprobar el resultado de cada operación con archivos, explicar los fallos al usuario con errno y liberar todos los recursos para que los programas fallen de forma segura e informen fielmente del éxito.
    • Comprobar cada resultado y distinguir el fin de archivo de los errores
      Conocer cómo señala un fallo cada función de stdio, usar feof y ferror cuando termina un bucle de lectura y detectar errores de escritura que solo aparecen al escribir el contenido del búfer.
    • Explicar los fallos con errno, perror y strerror
      Utilizar errno para averiguar por qué falló una llamada a la biblioteca e imprimir mensajes de error claros que indiquen el programa, el archivo y el motivo.
    • Liberar los recursos e informar del resultado
      Cerrar todos los flujos en todas las rutas, no dejar archivos de salida escritos a medias y devolver un estado de salida que refleje fielmente el resultado.

Guía de estudio de Entrada y salida de archivos en C

5 capítulos

1

Abrir archivos como flujos y conectar los programas con su entrada y su salida

Los archivos llegan a un programa a través de flujos, que controlan el acceso, el almacenamiento en búfer y la posición. La elección de un modo puede conservar los datos antiguos, borrarlos o forzar cada escritura al final, por lo que la apertura forma parte del diseño del programa. Los tres flujos estándar extienden la misma interfaz a terminales, archivos redirigidos y tuberías. Comprender sus conexiones te permite escribir una rutina de procesamiento que funcione en varios entornos y mantenga los mensajes de diagnóstico separados de los resultados útiles.

1.1 Explicar los flujos, el almacenamiento en búfer y las diferencias entre el modo texto y el modo binario

Un archivo contiene datos almacenados; un flujo es el canal que utiliza un programa en ejecución para acceder a ellos. Las mismas funciones de flujo también pueden trabajar con un terminal o una tubería. Incluye <stdio.h> y guarda el puntero al flujo en una variable de tipo FILE *.

Qué información conserva el flujo

El objeto FILE de la biblioteca lleva el control de un búfer, la posición actual en el archivo y los indicadores de fin de archivo y de error. Pasa su puntero a funciones como fgetc y fprintf; no inspecciones ni modifiques sus campos. Una lectura o escritura adelanta la posición hasta después de los datos procesados. En un archivo binario que comienza con "hello\nworld\n", leer los primeros seis bytes sitúa la siguiente lectura en la w.

El almacenamiento en búfer agrupa pequeñas operaciones en transferencias más grandes. Una escritura que tiene éxito puede significar que los datos llegaron a un búfer de memoria y que la transferencia al sistema operativo sigue pendiente. fflush(fp) envía la salida pendiente al sistema operativo. fclose(fp) hace eso antes de liberar el flujo. Ninguna de las dos garantiza que los datos sobrevivan a un corte repentino de electricidad.

Modo de almacenamiento en búferCuándo se transfiere la salida
Búfer completoCuando se llena el búfer, o cuando se vacía o cierra explícitamente
Búfer por líneaTambién cuando se escribe un salto de línea
Sin búferLo antes posible

Los archivos ordinarios abiertos con fopen usan búfer completo. Los dispositivos interactivos pueden usar otro modo. Un terminal o una tubería no ofrecen posiciones de archivo ordinarias para desplazarse hacia atrás y hacia delante.

Elegir el modo texto o binario

El modo texto maneja líneas legibles por personas. El modo binario conserva los valores de los bytes sin transformaciones de texto. Añade b al modo de apertura para datos binarios: "rb" los lee y "wb" los escribe. Las imágenes, los datos comprimidos y los registros en bruto necesitan el modo binario, aunque una versión en modo texto parezca funcionar en tu propio equipo.

En Linux y macOS, un salto de línea es un byte LF, 0x0A, y los dos modos normalmente se comportan igual. En Windows, la salida en modo texto transforma '\n' en los dos bytes CR LF, 0x0D 0x0A. La entrada en modo texto transforma CR LF de nuevo en un solo '\n'. La entrada en modo texto de Microsoft también reconoce 0x1A, Ctrl+Z, como fin de archivo.

Por ejemplo, escribir "a\nb\nc\n" en modo texto produce seis bytes en Linux o macOS y nueve en Windows. Tres letras aportan tres bytes; tres finales de línea de Windows aportan seis. Leer el archivo de Windows en modo texto en Windows da seis caracteres, mientras que el modo binario expone los nueve bytes.

Distinguir los bytes del archivo de su texto

Una línea creada en Windows y leída en Linux puede conservar "\r\n". Eliminar solo '\n' deja '\r', lo que puede hacer que falle una comparación con "yes". Una posición en un flujo de texto también puede reflejar el estado de la transformación, así que guarda y restaura las posiciones de texto en lugar de calcular desplazamientos en bytes.

La garantía de C de recuperar exactamente el texto escrito se aplica a caracteres imprimibles, tabulaciones y saltos de línea, sin espacios inmediatamente antes de un salto de línea y con un salto de línea al final de la última línea. Otras secuencias de bytes pertenecen a flujos binarios. Los bytes de C tienen al menos ocho bits; los ejemplos con valores de byte de 0 a 255 y formatos de archivo habituales usan bytes de ocho bits.

Puntos clave

  • Un FILE * da a las funciones de biblioteca acceso a un flujo y a su estado.
  • La salida almacenada en búfer puede fallar al vaciar el búfer o cerrar el flujo; comprueba esos resultados.
  • El modo texto de Windows transforma los finales de línea; el modo binario conserva los bytes.
  • Guarda las posiciones de texto; calcula desplazamientos en archivos binarios.
  • Explicita el supuesto de bytes de ocho bits al interpretar formatos binarios habituales.

1.2 Abrir y cerrar archivos con fopen y fclose

Elige un modo de apertura antes de escribir cualquier código de procesamiento. El modo controla si el archivo debe existir, si se conserva su contenido y dónde se realizan las escrituras. fopen actúa sobre el archivo inmediatamente: una apertura con "w" que tiene éxito borra un archivo existente aunque no se escriba nada después.

Elegir el modo adecuado para la tarea
ModoArchivo existenteArchivo inexistenteAcceso
"r"Conserva el contenidoFallaLectura desde el principio
"w"Borra el contenidoCrea el archivoEscritura desde el principio
"a"Conserva el contenidoCrea el archivoEscritura al final
"r+"Conserva el contenidoFallaLectura y escritura
"w+"Borra el contenidoCrea el archivoLectura y escritura
"a+"Conserva el contenidoCrea el archivoLectura en cualquier posición; escritura al final

Añade b para el modo binario; "r+b" y "rb+" significan lo mismo. C11 añade la creación exclusiva con x en los modos de escritura, como "wx" y "wbx": la apertura falla si el archivo existe. Usa una cadena de modo documentada; las letras de modo adicionales no son portables.

Comprobar antes de usar el puntero

fopen devuelve un puntero a un flujo nuevo si tiene éxito y NULL si falla. Los archivos inexistentes, las rutas inaccesibles y los directorios inexistentes pueden causar el fallo.

FILE *fp = fopen("scores.txt", "r");
if (fp == NULL) {
    fprintf(stderr, "Cannot open scores.txt\n");
    return EXIT_FAILURE;
}
/* Read through fp here. */
if (fclose(fp) == EOF) {
    fprintf(stderr, "Cannot close scores.txt\n");
    return EXIT_FAILURE;
}

El fragmento utiliza <stdio.h> y <stdlib.h>. Las funciones como fgetc, fprintf y fclose necesitan un flujo válido; pasar NULL produce comportamiento indefinido. fflush(NULL) es una excepción deliberada que vacía los búferes de todos los flujos de salida.

fclose devuelve 0 si tiene éxito y EOF si falla. Una vez llamada, el flujo queda cerrado, incluso cuando el cierre informa de un error. No vuelvas a llamar a fclose con el mismo puntero ni lo uses para más operaciones de entrada o salida. Cierra los archivos sin demora: los flujos disponibles son limitados y C garantiza la disponibilidad de al menos ocho flujos abiertos, incluidos los tres estándar.

Resolver rutas desde el programa en ejecución

Una ruta relativa como "data/input.txt" parte del directorio de trabajo actual, no de la carpeta del archivo fuente. Iniciar el programa en otro lugar cambia el destino de esa ruta. Las barras inclinadas también funcionan con la biblioteca de C de Microsoft. Una barra invertida en una cadena de C debe duplicarse, como en "C:\\data\\in.txt"; de lo contrario, una secuencia de escape como \n puede cambiar la cadena.

Para nombres proporcionados en la línea de comandos, usa int main(int argc, char *argv[]). En un comando de copia con dos nombres, argc debe ser 3, argv[1] es el nombre de entrada y argv[2] es el nombre de salida. Abre primero la entrada para que un nombre de entrada mal escrito no cree ni borre la salida. Si falla la apertura de la salida, cierra la entrada ya abierta. Usa archivos de entrada y salida distintos: abrir primero la entrada no la protege si el nombre de salida identifica ese mismo archivo.

Un retorno normal de main o exit cierra los flujos, pero los cierres explícitos permiten que el programa detecte errores de salida diferidos. Un cierre inesperado puede hacer que se pierdan datos almacenados en búfer; abort no ofrece la garantía de liberación de recursos de una salida normal.

Puntos clave

  • Abrir con "w" borra inmediatamente un archivo existente.
  • Comprueba si fopen devuelve NULL antes de usar el flujo.
  • Las rutas relativas parten del directorio de trabajo actual.
  • Cierra cada flujo abierto una sola vez y nunca lo reutilices después de fclose.
  • Abre la entrada de una copia antes que la salida y usa archivos distintos.
  • Los modos de escritura exclusivos de C11 fallan cuando el destino existe.

1.3 Utilizar stdin, stdout y stderr con redirecciones y tuberías

Un programa en C comienza con tres flujos abiertos: la entrada estándar stdin, la salida estándar stdout y la salida de error estándar stderr. Normalmente se conectan al terminal, pero el intérprete de comandos puede conectarlos a archivos u otros programas. Puedes pasarlos directamente a las funciones de flujo.

Mantener los resultados separados de los mensajes de diagnóstico

printf escribe en stdout; scanf lee de stdin. getchar() lee un carácter de stdin y putchar(c) escribe uno en stdout. puts(s) escribe una cadena en stdout y añade un salto de línea. Sus formas para flujos permiten que el mismo código funcione con un archivo:

void print_total(FILE *out, int total)
{
    fprintf(out, "Total: %d\n", total);
}

Llamar a print_total(stdout, 12) imprime un resultado; pasar un puntero a un archivo abierto dirige la misma disposición a un archivo. En código de producción, haz que la función auxiliar informe de un fallo de escritura a la función llamadora.

Escribe los mensajes de diagnóstico con fprintf(stderr, ...). Así, un programa de procesamiento de datos puede producir un archivo de resultados limpio y explicar los fallos por separado. Un error impreso en stdout puede corromper los datos que otro programa espera leer.

Dejar que el intérprete de comandos elija las conexiones

En un intérprete de comandos similar a Unix, este comando separa los tres flujos:

./sortnums < numbers.txt > sorted.txt 2> errors.txt

< proporciona la entrada, > crea o sustituye la salida, >> añade salida al final y 2> redirige los errores. Los operadores de redirección también funcionan en el símbolo del sistema de Windows, donde el nombre del programa suele escribirse como sortnums.exe. Una tubería, como en generate | sortnums, envía la salida estándar del primer programa a la entrada estándar del segundo. De forma predeterminada, no transporta stderr.

Un filtro puede aceptar un nombre de entrada opcional y, en caso contrario, leer de stdin. Lleva el control de la propiedad: cierra un flujo que tu función haya abierto, pero deja un flujo prestado para quien lo posee. Para un filtro sencillo de línea de comandos, if (in != stdin) identifica el archivo que abrió por sí mismo.

Vaciar el búfer de los mensajes antes de esperar la entrada

Un terminal suele hacer que stdout use búfer por línea. Un archivo redirigido o una tubería suelen hacer que use búfer completo. stderr no usa búfer completo. Esto explica por qué puede cambiar el orden de la salida cuando ambos flujos se envían a un mismo destino.

Después de printf("Saving..."), el texto puede permanecer en el búfer porque no hay un salto de línea. Usa fflush(stdout) y comprueba si devuelve EOF cuando deba aparecer antes de la siguiente operación. Vaciar el búfer envía la salida pendiente; no lee ni descarta la entrada. El estándar de C no define fflush(stdin) como una operación para limpiar la entrada. Para descartar una línea, lee caracteres hasta '\n' o EOF.

Si un programa imprime dos líneas en stdout y una advertencia en stderr entre ellas, un terminal suele mostrarlas en el orden del programa. Con > out.txt 2>&1, la advertencia puede llegar al archivo antes que la salida estándar almacenada en búfer. No uses el orden de visualización de flujos mezclados como registro del orden de ejecución.

Devolver un resultado utilizable a los scripts

Devuelve EXIT_SUCCESS o 0 cuando toda la tarea tenga éxito y EXIT_FAILURE cuando falle. Ambas macros están declaradas en <stdlib.h>. Un comando del intérprete como convert in.csv out.txt && echo done ejecuta el segundo comando solo después de un resultado satisfactorio. Un estado de salida fiel al resultado importa tanto como un mensaje de diagnóstico útil.

Puntos clave

  • Usa stdin, stdout y stderr sin abrirlos.
  • Envía los resultados del programa a stdout y los mensajes de diagnóstico a stderr.
  • La redirección cambia las conexiones; una tubería lleva la salida estándar a la entrada estándar.
  • Vacía el búfer de salida cuando un mensaje de solicitud deba verse inmediatamente.
  • Devuelve un estado de salida que indique fallo cuando falle la tarea solicitada.
2

Leer y escribir archivos de texto

El procesamiento de texto tiene tres escalas útiles: caracteres individuales, valores con formato y líneas completas. La elección cambia lo que el programa puede validar y cómo se recupera de una entrada incorrecta. Un bucle de caracteres debe distinguir los bytes del fin de archivo; una lectura con formato debe comprobar su número de asignaciones; un lector de líneas debe gestionar la capacidad y los registros incompletos. Los ejemplos resueltos muestran cómo conservar los datos realmente leídos mientras se mantienen bajo control el análisis posterior y los mensajes.

2.1 Leer y escribir carácter a carácter

La entrada y salida de caracteres es útil cuando cada carácter determina qué ocurre después: contar separadores, cambiar entre mayúsculas y minúsculas o reconocer un formato de texto sencillo. fgetc lee un carácter y fputc escribe uno. Ambas están declaradas en <stdio.h>.

Guardar el valor de retorno en un int

fgetc(fp) devuelve el carácter como un unsigned char convertido a int, o la constante negativa EOF cuando no hay ningún carácter disponible porque terminó la entrada o falló una lectura. En los sistemas habituales con bytes de ocho bits, los valores válidos de un byte van de 0 a 255. Un int mantiene esos valores separados de EOF.

int c;
while ((c = fgetc(in)) != EOF) {
    if (fputc(c, out) == EOF) {
        /* Report a write failure and clean up. */
        break;
    }
}
/* Check ferror(in) before declaring the input complete. */

Un char sin modificar puede perder esta distinción. Con char con signo, el byte 0xFF puede convertirse en -1 y parecer un fin de archivo. Con char sin signo, el valor negativo EOF se convierte en un byte y nunca puede ser igual a EOF en una comparación.

Conserva ambos paréntesis alrededor de la asignación. En c = fgetc(in) != EOF, la comparación se realiza primero, por lo que c recibe 1 o 0 en lugar del carácter. getc realiza la misma lectura y puede ser una macro; fputc devuelve el carácter escrito o EOF.

Contar lecturas realizadas, no intentos

La condición del bucle debe realizar la lectura. feof describe un intento anterior que llegó al final; no puede predecir el siguiente intento. Un bucle que comprueba !feof(in) y después cuenta incondicionalmente añade una pasada extra al final.

Para el texto "hi\nyo\n", seis lecturas realizadas dan seis caracteres y dos caracteres de salto de línea. Contar solo los caracteres de salto de línea funciona para líneas terminadas en salto de línea. El texto "red\ngreen\nblue" tiene dos saltos de línea, pero tres líneas, porque el "blue" final sigue siendo una línea.

Para incluir una línea final sin salto de línea, lleva también el control del último carácter:

size_t lines = 0;
int c, last = '\n';
while ((c = fgetc(in)) != EOF) {
    if (c == '\n') ++lines;
    last = c;
}
if (last != '\n') ++lines;

Inicializar last con '\n' hace que un archivo vacío cuente como cero líneas. Un error de lectura sigue requiriendo una ruta de fallo separada; un recuento parcial no es un resultado completo.

Transformar o examinar el siguiente carácter

toupper de <ctype.h> puede convertir letras antes de escribirlas. El resultado de una lectura correcta con fgetc ya está en el rango de entrada válido para toupper, por lo que fputc(toupper(c), out) es seguro dentro del bucle. Los valores arbitrarios de char con signo necesitan convertirse a unsigned char antes de pasarse a funciones de clasificación de caracteres.

ungetc(c, in) devuelve un carácter al flujo para que la siguiente lectura lo devuelva de nuevo. Se garantiza la devolución de un carácter; comprueba si se devuelve EOF cuando falle la devolución. Esto ayuda a un analizador a examinar el siguiente carácter sin perderlo. Una operación de posicionamiento descarta el carácter devuelto.

El recuento describe lo que proporciona el modo de flujo seleccionado. En Windows, el modo texto cuenta un par CR LF como un solo '\n'; el modo binario expone ambos bytes. Por tanto, un recuento de caracteres mediante un flujo de texto no tiene por qué coincidir con el recuento de bytes almacenados.

Puntos clave

  • Guarda los resultados de fgetc en int para distinguir los valores de bytes de EOF.
  • Comprueba el resultado de cada lectura antes de procesarlo o contarlo.
  • Cuenta como una línea una parte final no vacía sin salto de línea.
  • Se garantiza la devolución de un carácter con ungetc; el posicionamiento lo descarta.

2.2 Escribir y leer texto con formato mediante fprintf y fscanf

La entrada y salida con formato convierte entre valores de C y texto legible. fprintf escribe con la disposición que elijas; fscanf lee valores que coinciden con un formato. Sus especificaciones de conversión se parecen, pero la entrada requiere punteros a los tipos de destino adecuados.

Escribir valores legibles

Usa %d para un int, %ld para un long, %zu para un size_t, %s para una cadena y %c para un carácter. En la salida, %f imprime un double; un argumento float se promociona a double. %% imprime un signo de porcentaje.

int result = fprintf(fp, "%-8s%6.2f\n", "Oslo", 3.14159);
if (result < 0) {
    /* Handle a write failure. */
}

%-8s alinea "Oslo" a la izquierda en ocho columnas; %6.2f alinea "3.14" a la derecha en seis. La línea resultante es "Oslo 3.14\n", y el valor de retorno es 15 caracteres. El ancho de campo es un mínimo, no un límite de longitud de la salida. La precisión también cambia la información almacenada: %.2f escribe 3.14159 como "3.14", por lo que esos dígitos adicionales no pueden recuperarse del archivo.

Un programa sencillo que escribe CSV puede producir "Lima,2024,19.5" con un orden fijo y comas entre campos. El texto que contiene comas, comillas o saltos de línea necesita el entrecomillado de campos CSV. Encierra ese campo entre comillas dobles y duplica cualquier comilla que haya en su interior. Escribir con un %s sin más solo es adecuado cuando los campos de texto no contienen esos caracteres.

Dar formato en un array de tamaño limitado

sprintf no tiene un argumento para el tamaño del destino. Dar formato a "007.jpg" necesita ocho bytes incluido el terminador nulo. Es preferible usar snprintf:

char name[32];
int n = snprintf(name, sizeof name, "%03d.jpg", 7);
if (n < 0 || (size_t)n >= sizeof name) {
    /* Formatting failed or the full result did not fit. */
}

El valor de retorno no negativo es la longitud que necesitaría el texto completo, sin contar el terminador nulo. Un valor igual al tamaño del búfer ya significa que se ha producido truncamiento. Comprueba si el resultado es negativo antes de convertirlo a size_t.

Leer el número esperado de valores
char name[20];
int age;
int matched = fscanf(fp, "%19s %d", name, &age);

Esta llamada solo tiene éxito completo si devuelve 2. El ancho 19 deja un byte para el terminador. El nombre del array proporciona su dirección; el entero necesita &age. Para la entrada, %f necesita float *, mientras que %lf necesita double *. Una incompatibilidad produce comportamiento indefinido, no una conversión inofensiva.

La mayoría de las conversiones omiten los caracteres en blanco iniciales, incluidos los saltos de línea. Por tanto, fscanf no exige un registro por línea y %s no puede leer "New York" como un solo valor. Un conjunto de exploración como %19[^,] lee hasta una coma; para los registros suele ser más claro leer líneas completas.

Con "10 abc 20", %d primero almacena 10 y devuelve 1. La siguiente llamada devuelve 0 porque "abc" no coincide; ese texto permanece sin leer. Comprobar != EOF repite el fallo indefinidamente. Comprueba == 1 y después gestiona los datos no válidos por separado del fin de la entrada o de un error del flujo. El resultado de una conversión es un recuento de valores asignados, no un valor de verdad para todo el archivo.

Puntos clave

  • Haz coincidir cada especificación de formato con el tipo de argumento.
  • Limita el ancho de %s en la entrada al tamaño del array menos uno.
  • Compara el resultado de fscanf con el número exacto de asignaciones esperadas.
  • snprintf devuelve la longitud completa necesaria; un valor de retorno al menos igual a la capacidad indica truncamiento.
  • Los campos de texto CSV necesitan comillas cuando contienen comas, comillas o saltos de línea.
  • La salida con formato de coma flotante puede perder precisión.

2.3 Leer líneas de forma segura con fgets

Leer una línea completa antes de analizarla mantiene separado cada registro de texto. Si un registro no es válido, puedes informar de su número de línea y continuar con el siguiente. fgets limita cuánto escribe, pero aún debes gestionar los saltos de línea que conserva y las líneas más grandes que el array.

Leer en un espacio de capacidad conocida
char line[256];
while (fgets(line, sizeof line, fp) != NULL) {
    /* Process this successful read. */
}
if (ferror(fp)) {
    /* Report an interrupted read. */
}

fgets lee como máximo un carácter menos que la capacidad, se detiene después de un salto de línea si encuentra uno y añade un terminador nulo. Devuelve el búfer si tiene éxito. Un resultado NULL significa que no había caracteres disponibles al final del archivo o que se produjo un error; no proceses el búfer después de un error de lectura.

sizeof line proporciona la capacidad del array en este ámbito. En una función auxiliar cuyo parámetro es char *line, es el tamaño del puntero. Pasa la capacidad real por separado. La antigua función gets no puede limitar la entrada y se eliminó en C11.

Reconocer las partes de líneas largas

Con char buf[8], "temperature\n" llega como "tempera" y después "ture\n". La primera llamada usa siete bytes para caracteres y uno para el terminador. Una lectura correcta sin salto de línea podría ser una parte de una línea larga o la parte final sin terminación al final del archivo.

Elige una estrategia: unir las partes en un registro más grande, procesarlas como una secuencia continua o rechazar el registro y descartar todas sus partes restantes. Para aplicar un límite de tamaño, examina el siguiente carácter antes de rechazar un búfer exactamente lleno. Un salto de línea a continuación completa el registro; EOF sin un error del flujo completa una línea final sin salto de línea; otro carácter indica que hay más contenido. Devuelve un carácter al flujo solo si el código posterior necesita leerlo de nuevo.

Eliminar solo un final que se haya encontrado

Después de decidir si el registro está completo, elimina los finales de línea:

line[strcspn(line, "\r\n")] = '\0';

strcspn de <string.h> encuentra el primer carácter de los indicados, o el terminador existente si no aparece ninguno. Esto maneja tanto un CR LF conservado como un LF. Eliminar line[strlen(line) - 1] incondicionalmente puede borrar datos reales de una línea final sin salto de línea y no es válido para una cadena vacía.

fputs(line, out) escribe la cadena sin añadir un salto de línea; puts(line) escribe en stdout y añade uno. Una copia de texto puede pasar cada parte leída correctamente por fgets a fputs, comprobando si falla, incluso cuando una línea larga ocupa varias partes. Para obtener exactamente los bytes originales, usa entrada y salida binaria por bloques.

Analizar y validar por separado

sscanf(line, "%d %9s", &qty, item) devuelve 2 para "7 apples" y 0 para "seven apples". Un análisis fallido no deja ningún token incorrecto atascado en el flujo de entrada porque la línea ya se leyó. Las conversiones numéricas con sscanf siguen requiriendo una entrada representable; usa strtol para una comprobación estricta del rango.

Para strtol, establece errno en cero, pasa un puntero al final de la conversión y comprueba si no hay dígitos, si se produjo ERANGE y si hay texto adicional inesperado. Con "42abc", el resultado 42 es solo un prefijo numérico. Para un campo de número entero, permite los caracteres en blanco finales que hayas elegido y exige después el final de la cadena. Comprueba el rango del tipo de destino antes de convertir un long válido a int.

Puntos clave

  • fgets conserva un salto de línea cuando cabe y siempre reserva espacio para un terminador si tiene éxito.
  • Un búfer lleno sin salto de línea requiere comprobar si la línea está completa.
  • Pasa las capacidades explícitamente a las funciones auxiliares que usan punteros.
  • Usa strcspn para eliminar solo un final de línea que exista.
  • Lee primero y después analiza y valida cada registro.
  • Comprueba con strtol los dígitos, los errores de rango y los datos adicionales.
3

Guardar y cargar datos en archivos binarios

Los archivos binarios transfieren los bytes de los objetos sin convertirlos en texto legible. Los tamaños y números de elementos determinan cómo se manejan los arrays completos, los registros y los bloques finales parciales. Un archivo compartido entre máquinas también necesita una representación explícita: anchos de campo, orden de los bytes y disposición. Leer una firma es solo el comienzo de la comprobación de esa representación; las longitudes y los recuentos deben validarse antes de que el programa confíe en los datos restantes o reserve espacio para ellos.

3.1 Leer y escribir datos binarios con fread y fwrite

La entrada y salida binaria transfiere los bytes de los objetos sin convertirlos en números o palabras legibles. fread y fwrite reciben una dirección, un tamaño de elemento, un número de elementos y un flujo. Sus valores de retorno cuentan elementos completos, por lo que la elección del tamaño de elemento determina qué puedes deducir del resultado.

Escribir y leer arrays
int a[5] = {1, 2, 3, 4, 5};
if (fwrite(a, sizeof a[0], 5, out) != 5) {
    /* Handle a write failure. */
}

En un sistema con int de cuatro bytes, esto escribe 20 bytes y devuelve 5. Leer en otro array de cinco elementos con la misma representación permite recuperar los valores. Usa "wb" y "rb" para que las transformaciones de texto no alteren los bytes.

Para un solo objeto, pasa su dirección: fwrite(&rec, sizeof rec, 1, out). Para objetos a los que se accede mediante un puntero p, usa fwrite(p, sizeof *p, count, out). sizeof p mide el puntero y &p apunta a la propia variable de tipo puntero. Ninguno expresa la transferencia de datos deseada. Cuando el tamaño o el número de elementos es cero, ambas funciones devuelven cero sin transferir datos.

Copiar exactamente los bytes leídos
unsigned char buf[512];
size_t n;
while ((n = fread(buf, 1, sizeof buf, in)) > 0) {
    if (fwrite(buf, 1, n, out) != n) {
        /* Handle failure and stop copying. */
        break;
    }
}

Un tamaño de elemento de 1 hace que n sea un recuento de bytes. Una entrada de 1300 bytes proporciona 512, 512 y 276 bytes, y después cero. La última escritura debe usar 276, no la capacidad de 512. Escribir todo el búfer añade 236 bytes sobrantes de lecturas anteriores.

Con fread(buf, 512, 1, in), la misma entrada devuelve 1, 1 y después 0. Los últimos 276 bytes son solo un elemento parcial; no se cuentan y el valor de ese elemento parcial es indeterminado. Elige elementos de un byte cuando sea útil un bloque final parcial. Elige elementos del tamaño de un registro cuando deban rechazarse los registros incompletos.

Una lectura corta de fread puede indicar fin de archivo o un error. Comprueba ferror después de copiar y comprueba fclose en la salida: una escritura aceptada en un búfer puede fallar más tarde. Una cabecera o un registro parcial nunca debe tratarse como un objeto completo.

Examinar firmas y objetos almacenados

Usa unsigned char para bytes en bruto; en sistemas con bytes de ocho bits contiene valores de 0 a 255 sin valores negativos. Los datos JPEG comienzan con 0xFF 0xD8. Las fotos de cámaras y teléfonos suelen continuar con un marcador APPn, lo que produce el patrón de recuperación desde FF D8 FF E0 hasta FF D8 FF EF. Ese patrón es una prueba útil para identificar posibles archivos; valida el formato antes de confiar en él. Algunos archivos JPEG usan un segmento siguiente diferente.

Una estructura con char name[20] y un int score suele ocupar 24 bytes. Una escritura en bruto incluye todos sus bytes almacenados, incluido el relleno. Un miembro de tipo puntero guarda una dirección, no la cadena a la que apunta. Usa un array dentro de la estructura o escribe por separado la longitud y los caracteres de la cadena.

El texto legible puede ocupar más espacio: "1000000\n" usa ocho bytes en Linux y nueve en modo texto de Windows. Un entero de 32 bits codificado explícitamente usa cuatro bytes de ocho bits. El almacenamiento de objetos en bruto es compacto, pero vincula el archivo a la representación utilizada por quien lo creó.

Puntos clave

  • fread y fwrite devuelven recuentos de elementos completos, que no siempre son recuentos de bytes.
  • Usa un tamaño de elemento de 1 cuando importe un bloque final parcial.
  • Escribe la cantidad leída, no toda la capacidad del búfer.
  • Un miembro de tipo puntero almacenado en bruto contiene una dirección, no los datos a los que apunta.
  • Comprueba las transferencias cortas y el cierre de la salida.
  • Usa las firmas para identificar posibles archivos y después valida el archivo.

3.2 Diseñar formatos binarios que funcionen en distintas máquinas

Un flujo binario conserva los bytes, pero dos máquinas pueden interpretar los mismos bytes de forma distinta. Un formato portable define qué significa cada byte en lugar de adoptar la disposición que el compilador dé a un objeto.

Especificar tamaños, orden y disposición

Tres aspectos hacen que un volcado de objetos en bruto dependa de la máquina:

AspectoQué puede variar
Tamaño del tipoint puede ocupar dos o cuatro bytes; long suele diferir entre Windows y Linux de 64 bits
Orden de los bytesEl byte menos o más significativo puede ir primero
Disposición de la estructuraEl relleno y los desplazamientos de los miembros pueden cambiar

El orden con el byte menos significativo primero almacena primero ese byte. El orden con el byte más significativo primero almacena primero ese byte. El valor 258, en hexadecimal 0x00000102, es 02 01 00 00 con el byte menos significativo primero y 00 00 01 02 con el byte más significativo primero.

Una disposición habitual de una estructura con un char seguido de un int ocupa ocho bytes: un byte para el carácter, tres bytes de relleno y cuatro para el entero. Los valores del relleno no están especificados. Los tipos de ancho exacto de <stdint.h>, como uint32_t, fijan los anchos en bits cuando están disponibles; no fijan el orden de los bytes ni eliminan el relleno. Los ejemplos de formatos de archivo habituales presuponen bytes de ocho bits y la disponibilidad de esos tipos.

Decodificar los campos explícitamente

Lee cuatro bytes completos antes de interpretarlos. Para un campo con el byte menos significativo primero:

uint32_t v = (uint32_t)b[0]
           | (uint32_t)b[1] << 8
           | (uint32_t)b[2] << 16
           | (uint32_t)b[3] << 24;

Aquí b es un array de bytes sin signo. Cada conversión explícita de tipo se realiza antes del desplazamiento, de modo que la operación aritmética tiene el ancho sin signo necesario. Para codificar, extrae los ocho bits menos significativos, después los ocho siguientes y así sucesivamente. Comprueba cada operación de salida. Escribir v directamente con fwrite volvería a introducir el orden de los bytes de la máquina en el formato.

Definir un pequeño formato completo

Un formato de puntuaciones puede usar "SCR1" como firma de cuatro bytes, un recuento de cuatro bytes con el byte menos significativo primero y registros compuestos por 20 bytes para el nombre más cuatro bytes para la puntuación con el byte menos significativo primero. La firma también identifica la versión. La cabecera tiene ocho bytes; cada registro tiene exactamente 24 bytes.

Cinco registros ocupan 128 bytes. El registro con índice 3 comienza en el byte 80: se omiten ocho bytes de cabecera y tres registros completos. Indica la codificación del campo de nombre y la política de terminación o relleno como parte de un formato real; un campo de nombre fijo de 20 bytes no es automáticamente una cadena de C.

Comprueba la longitud completa y la firma de una cabecera antes de usar sus campos. Después comprueba los recuentos y las longitudes frente a límites razonables y a los datos disponibles antes de reservar memoria. Un recuento plausible no basta si faltan registros posteriores.

Leer la estructura real del formato

Algunos archivos PCM WAV tienen una cabecera sencilla de 44 bytes, con la frecuencia de muestreo en los bytes 24 a 27. Los bytes 44 AC 00 00 se decodifican como 44 100 muestras por segundo. Otros archivos WAV contienen bloques adicionales, por lo que un lector general sigue los identificadores y tamaños de los bloques para localizar el bloque fmt . Suponer una disposición de cabecera fija para todos los archivos puede hacer que se lea un campo sin relación como si fuera la frecuencia.

El texto como CSV evita problemas de tamaño de los enteros, orden de los bytes y relleno de estructuras, y es fácil de examinar. Sigue necesitando una disposición de campos definida, reglas de entrecomillado y un análisis comprobado. Elígelo cuando la legibilidad y el intercambio importen más que una representación binaria compacta.

Puntos clave

  • Un formato binario portable define los anchos de campo, el orden de los bytes y los desplazamientos.
  • Los tipos enteros de ancho exacto por sí solos no hacen portable un volcado de una estructura.
  • Convierte los bytes al ancho sin signo previsto antes de desplazarlos.
  • Valida toda la cabecera y limita los recuentos antes de confiar en ellos.
  • Sigue la estructura de bloques cuando un formato permita bloques adicionales.
  • Un campo de texto de ancho fijo necesita una política explícita de codificación y longitud.
4

Desplazarse a cualquier posición de un archivo

Las posiciones en el archivo hacen posible el acceso directo cuando los registros tienen ubicaciones conocidas. Calcular esas ubicaciones exige prestar atención a las cabeceras, los anchos de los registros y los índices que empiezan en cero. Las posiciones de texto tienen reglas más estrictas porque la transformación puede cambiar su significado. Cuando un flujo admite tanto lectura como escritura, el posicionamiento también controla los cambios válidos de dirección. Por tanto, actualizar un registro combina el cálculo de una ubicación con una secuencia comprobada que conserva los datos circundantes.

4.1 Obtener y establecer la posición en el archivo con ftell, fseek y rewind

Las lecturas secuenciales recorren los datos en orden. El acceso aleatorio permite que un programa salte a una ubicación conocida, como un registro en un archivo grande. El posicionamiento solo funciona cuando el flujo subyacente lo admite, y el significado de una posición difiere entre flujos binarios y de texto.

Obtener y cambiar la posición

ftell(fp) devuelve una posición de tipo long o -1L si falla. En un archivo binario, una posición cuenta los bytes desde su inicio. fseek(fp, offset, whence) se desplaza con respecto a un punto de referencia seleccionado y devuelve 0 si tiene éxito y un valor distinto de cero si falla.

ReferenciaSignificado del desplazamiento
SEEK_SETDesde el principio
SEEK_CURDesde la posición actual
SEEK_ENDDesde el final

Por ejemplo, fseek(fp, -4L, SEEK_END) solicita los últimos cuatro bytes de un archivo binario en un sistema que admite desplazamientos relativos al final. Comprueba el resultado antes de leer. Una solicitud sobre una tubería o un terminal, o una solicitud anterior al principio de un archivo ordinario, puede fallar.

Calcular la ubicación de un registro

Para registros binarios de tamaño fijo sin cabecera, el índice que empieza en cero multiplicado por el ancho del registro da el desplazamiento inicial. Con registros de 24 bytes, el índice 3 comienza en el byte 72. Después de leer todo ese registro, la posición es 96.

long offset = 3L * (long)sizeof(struct record);
if (fseek(fp, offset, SEEK_SET) != 0) {
    /* Handle the failed move before reading. */
}

Este ejemplo presupone que el archivo se escribió con la misma disposición de estructura. En cambio, un formato portable especificado usa el ancho de registro definido en él. Incluye los bytes de cabecera cuando los haya. El tercer registro contado desde 1 tiene índice 2, no índice 3. Para índices grandes, valida la multiplicación y asegúrate de que el resultado cabe en long antes de desplazarte.

En los sistemas habituales, desplazarse al final y usar ftell permite medir un archivo binario: un archivo de 120 bytes con registros de 24 bytes contiene cinco registros. Comprueba ambas llamadas y restaura la posición después. El estándar de C no exige que SEEK_END tenga un significado útil para todos los flujos binarios, por lo que el método depende de que ese flujo lo admita.

Guardar posiciones de texto sin operaciones aritméticas

El modo texto puede transformar los finales de línea. Una posición de texto devuelta es información para volver a un lugar, no un recuento al que sumar o restar. Un desplazamiento de texto distinto de cero usa un valor devuelto anteriormente por ftell para el mismo archivo, con SEEK_SET. Se permite un desplazamiento de cero con cualquier punto de referencia.

rewind(fp) vuelve al principio y borra tanto el indicador de fin de archivo como el de error. No devuelve ningún resultado, por lo que debes usar fseek(fp, 0L, SEEK_SET) y comprobarlo cuando sea necesario confirmar que el desplazamiento tuvo éxito. Una llamada a fseek que tiene éxito borra el indicador de fin de archivo y descarta el carácter devuelto con ungetc, pero deja activado cualquier indicador de error existente.

Conservar un valor de posición

fgetpos(fp, &pos) guarda una posición en fpos_t; fsetpos(fp, &pos) la restaura. Comprueba si ambas devuelven un valor distinto de cero que indique fallo. Trata fpos_t como un valor opaco, sin operaciones aritméticas. Puede contener información de posición que va más allá de un simple recuento de bytes.

fseek y ftell usan long, que suele tener 32 bits en Windows y limita las posiciones representables a unos 2 GiB. Un valor de posición evita vincular la interfaz a long, pero el tamaño de archivo admitido sigue dependiendo de la implementación y la configuración.

Puntos clave

  • Comprueba si fseek devuelve un valor distinto de cero y si ftell devuelve -1L.
  • El desplazamiento de un registro incluye la cabecera y todos los registros anteriores.
  • Usa de forma coherente índices que empiecen en cero.
  • Restaura las posiciones de texto con valores guardados, sin operaciones aritméticas sobre desplazamientos.
  • rewind borra ambos indicadores; una llamada a fseek que tiene éxito borra el de fin de archivo.
  • El posicionamiento requiere un flujo que admita desplazamientos y desplazamientos representables.

4.2 Actualizar registros de tamaño fijo en su misma posición

Un flujo de actualización lee y escribe el mismo archivo. Usa "r+b" para conservar un archivo binario existente mientras modificas sus registros. "w+b" borra inmediatamente el archivo antiguo y los modos de adición al final fuerzan cada escritura al final.

Realizar cambios de dirección válidos

Un flujo de actualización tiene dos reglas de alternancia:

CambioAcción requerida entre operaciones
De escritura a lecturaVaciar el búfer de salida o realizar una operación de posicionamiento
De lectura a escrituraRealizar una operación de posicionamiento, salvo que la lectura haya llegado al fin de archivo

Las funciones de posicionamiento incluyen fseek, fsetpos y rewind. Comprueba las funciones que devuelven un resultado antes de continuar. Un cambio de dirección sin la acción requerida produce comportamiento indefinido; no puedes predecir que solo afectará al siguiente registro.

Actualizar un registro completo

Supón que un archivo sin cabecera contiene cinco registros de 24 bytes con la misma representación que struct record. Para modificar el índice 3:

  1. Abre con "r+b" y comprueba el puntero.
  2. Desplázate al byte 72 y comprueba que la operación tuvo éxito.
  3. Lee exactamente un registro completo.
  4. Cambia su miembro score a 99.
  5. Vuelve al principio del registro.
  6. Escribe exactamente un registro y comprueba el resultado del cierre.

Las operaciones intermedias clave son:

if (fread(&rec, sizeof rec, 1, fp) != 1) {
    /* Report the incomplete input, then clean up. */
    goto cleanup;
}
rec.score = 99;
if (fseek(fp, -(long)sizeof rec, SEEK_CUR) != 0) {
    /* Report the failed seek, then clean up. */
    goto cleanup;
}
if (fwrite(&rec, sizeof rec, 1, fp) != 1) {
    /* Report the failed write, then clean up. */
    goto cleanup;
}

La función que contiene este código proporciona una etiqueta cleanup que cierra su flujo y devuelve un fallo en estas ramas. Después de la lectura, la posición es 96. Retroceder 24 bytes selecciona el registro original y permite pasar de lectura a escritura. Una sustitución correcta deja el archivo con 120 bytes y cinco registros. Restaurar una posición inicial guardada es otra forma válida de realizar la actualización.

Decidir cuándo reescribir

Añadir un registro de 24 bytes aumenta ese archivo a 144 bytes. Desplazarse al principio de un flujo "ab" o "a+b" no puede convertir su siguiente escritura en una sobrescritura; la escritura sigue realizándose en el final actual.

Una sustitución en la misma posición debe caber en el espacio que sustituye. Cambiar "Bo,7" por "Bo,9" cabe. Escribir "Bo,12" sobre "Bo,7\n" consume el salto de línea y une el texto siguiente al registro. Para ampliar o reducir registros, escribe un archivo nuevo corregido. El estándar de C no tiene ninguna función de flujo que elimine un intervalo de bytes del medio de un archivo. En su lugar, la eliminación puede copiar todos los registros que se conservan o marcar un registro de tamaño fijo como eliminado.

Mantener recuperable la sustitución

Comprueba remove y rename; ambas devuelven 0 si tienen éxito. Que rename sustituya un destino existente es un comportamiento definido por la implementación. Linux y macOS admiten la sustitución; la biblioteca de C de Microsoft falla cuando el destino existe.

Un plan de recuperación portable escribe y cierra el archivo nuevo, cambia el nombre del original por un nombre de copia de seguridad distinto y cambia el nombre del archivo nuevo por el nombre original. Si falla la instalación, conserva la copia de seguridad disponible para restaurarla e informa de dónde está. Elimina la copia de seguridad solo después de que la instalación tenga éxito. Esta secuencia permite la recuperación; no es una transacción atómica portable ni una garantía frente a un corte de electricidad.

Puntos clave

  • Usa "r+b" para actualizar un archivo existente sin truncarlo.
  • Sigue la regla de alternancia entre lectura y escritura incluso cuando la posición deseada parezca obvia.
  • Vuelve a la posición anterior después de leer un registro y antes de sustituirlo.
  • Las escrituras en modo de adición siempre van al final.
  • Reescribe los datos cuando cambie su longitud.
  • Comprueba cada paso de la sustitución y conserva un original recuperable.
5

Detectar errores de archivo, informar de ellos y recuperarse

Una operación con archivos puede fallar después de que la apertura haya tenido éxito, y la salida almacenada en búfer puede fallar solo al cerrar. Los programas fiables leen los valores de retorno, distinguen los datos no válidos de los problemas de acceso, conservan información útil sobre los errores y liberan los recursos en todas las rutas. Estas tareas funcionan conjuntamente: el mensaje de diagnóstico debe explicar el fallo original, mientras que el estado final también debe reflejar los fallos detectados durante la liberación de recursos. Un programa de copia completo muestra cómo encajan estas decisiones en el flujo de control habitual de C.

5.1 Comprobar cada resultado y distinguir el fin de archivo de los errores

Un archivo puede abrirse correctamente y aun así fallar durante la lectura, la escritura, el posicionamiento o el cierre. Un programa robusto comprueba el resultado de la operación que realmente intentó realizar. Distingue una lectura completa de una entrada interrumpida y los datos mal formados de un fallo del flujo.

Conocer cada señal de fallo
OperaciónSeñal que debe gestionarse
fopen, fgetsNULL
fgetc, fputc, fflush, fcloseEOF
fprintfUn resultado negativo
fputsEOF
fread, fwriteMenos elementos completos de los solicitados
fscanfMenos asignaciones de las esperadas, o EOF
fseek, fgetpos, fsetposUn resultado distinto de cero
ftell-1L

rewind, clearerr y perror no devuelven ningún valor. Si es necesario comprobar que el desplazamiento al principio tuvo éxito, usa fseek en lugar de confiar en un resultado de rewind.

Examinar el flujo después de que se detenga una lectura

El flujo mantiene indicadores separados de fin de archivo y de error. feof(fp) comprueba el primero; ferror(fp) comprueba el segundo. Cada una devuelve un valor distinto de cero si su indicador está activado.

while (fgets(line, sizeof line, fp) != NULL) {
    /* Process successful input. */
}
if (ferror(fp)) {
    fprintf(stderr, "Input could not be completed\n");
    /* Return failure after cleanup. */
}

El valor devuelto por fgets por sí solo no distingue los dos motivos de detención. Del mismo modo, fgetc devuelve EOF y fread devuelve un recuento corto tanto al llegar al fin de archivo como al fallar la lectura. No compruebes feof antes de leer para predecir si quedan datos.

Los indicadores permanecen activados. clearerr borra ambos, igual que rewind. Una llamada a fseek o fsetpos que tiene éxito borra el indicador de fin de archivo, pero no un error existente. Borrar un indicador reconoce su estado; no vuelve a conectar una unidad retirada ni repara un archivo dañado. Vuelve a intentarlo solo cuando se haya solucionado la causa.

Distinguir los datos no válidos de un fallo de acceso

Si fscanf(fp, "%d", &value) devuelve 0 con "abc", la conversión falló antes de cualquier asignación. No es necesario que se haya llegado al fin de archivo ni que haya un error de lectura. Informa de que el campo no es válido, preferiblemente con un número de línea. Un mensaje sobre el disco describiría un problema equivocado.

Si una cabecera obligatoria se lee como un elemento y fread devuelve 0, la cabecera está incompleta. No examines ese objeto parcialmente lleno. Si ferror está activado, informa de un error de entrada; si el archivo terminó, informa de datos truncados. Un archivo vacío y una cabecera parcial pueden producir el mismo recuento de elementos, por lo que el formato esperado establece el requisito de que la cabecera exista.

Detectar fallos de salida diferidos

Un disco puede llenarse después de que el programa haya abierto su salida. Las escrituras almacenadas en búfer pueden parecer correctas hasta que fflush o fclose transfieren realmente los bytes pendientes. Comprueba el cierre final y permite que convierta una tarea que, por lo demás, tuvo éxito en un fallo. No vuelvas a cerrar el mismo flujo después.

En un terminal, Ctrl+D al principio de una línea en Linux o macOS, o Ctrl+Z y después Enter en Windows, suelen señalar el fin de la entrada. clearerr(stdin) borra el indicador resultante si el programa necesita otro intento. La acción en el terminal y un error de lectura siguen siendo causas distintas.

Puntos clave

  • Comprueba cada función según su propio valor de retorno documentado.
  • Lee primero y después usa los indicadores del flujo para identificar el motivo de la detención.
  • Una falta de coincidencia de formato indica datos no válidos, no necesariamente un error del flujo.
  • Rechaza las cabeceras y los registros obligatorios incompletos.
  • Un error diferido al cerrar la salida debe hacer que la tarea falle.

5.2 Explicar los fallos con errno, perror y strerror

Un valor de retorno te indica que una operación ha fallado. Un código de error puede ayudar a explicar por qué. Usa errno solo en el contexto del comportamiento documentado de la operación y consérvala antes de que otras llamadas a la biblioteca puedan cambiarla.

Dejar que la operación indique el fallo

errno es una expresión int modificable de <errno.h>, con duración de almacenamiento local a cada hilo en C11. Empieza en cero. Las llamadas a la biblioteca no la restablecen a cero y una llamada que tiene éxito puede dejar o establecer un valor distinto de cero. Por tanto, comprobar errno después de una llamada a fopen que tuvo éxito no indica que la apertura haya fallado.

En sistemas POSIX, una llamada fallida a fopen establece un código de error. La biblioteca de C de Microsoft también proporciona códigos de error de archivo. El estándar de C no exige que fopen establezca errno. Para informar de forma portable, se puede poner a cero antes de la apertura y usar un mensaje general si no se proporcionó ningún código:

errno = 0;
FILE *fp = fopen(name, "r");
if (fp == NULL) {
    int saved = errno;
    if (saved != 0)
        fprintf(stderr, "Cannot open %s: %s\n",
                name, strerror(saved));
    else
        fprintf(stderr, "Cannot open %s\n", name);
    return EXIT_FAILURE;
}

Este fragmento también necesita <stdio.h>, <stdlib.h> y <string.h>. Guardar el código inmediatamente evita que llamadas posteriores para informar del error o liberar recursos sustituyan el motivo original. Un código guardado es útil incluso si el mensaje final se imprime mucho más tarde.

Elegir una función de mensajes

perror(label) escribe la etiqueta, dos puntos y un espacio, el mensaje de error actual y un salto de línea en stderr. Un mensaje típico de archivo inexistente es "missing.txt: No such file or directory"; la redacción exacta depende del sistema.

strerror(code) devuelve el mensaje de la biblioteca para un código proporcionado, por lo que sirve para un mensaje de diagnóstico personalizado que indique el programa, la operación y el archivo. No modifiques la cadena devuelta. Usa strerror(saved) después de liberar los recursos en lugar de consultar el nuevo valor de errno.

C define EDOM, ERANGE y EILSEQ. Los códigos de archivo habituales como ENOENT, EACCES, EEXIST y ENOSPC los proporcionan POSIX y bibliotecas de C ampliamente disponibles. Adapta tu código a la interfaz y la plataforma de destino. No supongas que los valores numéricos de los códigos ni el texto exacto de los mensajes en inglés son universales.

Gestionar un valor de retorno ambiguo

Para algunas funciones, el resultado por sí solo no puede distinguir el éxito de un error de rango. strtol puede devolver LONG_MAX como número válido o como resultado de un desbordamiento. Pon errno a cero antes de la conversión y después examina el código de rango documentado:

errno = 0;
char *end;
long value = strtol(text, &end, 10);
if (end == text) {
    /* No digits were converted. */
} else if (errno == ERANGE) {
    /* The value is outside the long range. */
} else {
    /* Validate trailing characters and the target range. */
}

Un mensaje de diagnóstico útil proporciona al usuario información con la que actuar. Indica el archivo y la acción intentada; conserva el motivo del sistema cuando esté disponible. Envíalo a stderr y deja stdout disponible para datos de resultados válidos.

Puntos clave

  • Usa el resultado de la función para determinar que ha fallado antes de interpretar errno.
  • Guarda errno inmediatamente antes de las llamadas para informar del error o liberar recursos.
  • perror usa el valor actual de errno; strerror acepta un código guardado.
  • Pon errno a cero antes de strtol y comprueba ERANGE.
  • Incluye el archivo y la acción intentada en un mensaje de diagnóstico.

5.3 Liberar los recursos e informar del resultado

La gestión de errores solo está completa cuando se liberan los recursos y el programa informa del resultado real. Planifica la propiedad cuando abras un flujo y haz que todas las rutas posteriores respeten ese plan.

Cerrar una vez cada flujo abierto

Si falla la apertura de la entrada, no hay ningún flujo que cerrar. Si falla la apertura de la salida después de que la entrada se haya abierto correctamente, cierra la entrada. Si la copia falla después de abrir ambos, cierra ambos, comprueba el cierre de la salida y conserva un estado de fallo. Cerrar un puntero dos veces no es una protección adicional; usa un flujo ya cerrado.

El código con retornos anticipados suele cerrar los recursos en el orden inverso al de su adquisición. Una etiqueta compartida para liberar recursos es útil cuando varias rutas de fallo necesitan el mismo trabajo. Inicializa los punteros en NULL, mantén un estado de fallo de forma predeterminada y establece el éxito solo después de que termine la fase de procesamiento.

El siguiente programa completo copia archivos de entrada y salida distintos en modo binario. Usa mensajes generales porque el estándar de C no exige que todos los fallos de stdio proporcionen errno.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    FILE *in = NULL, *out = NULL;
    int status = EXIT_FAILURE;
    int output_acquired = 0;
    unsigned char buf[512];
    size_t n;

    if (argc != 3) {
        fprintf(stderr, "Usage: %s input output\n", argv[0]);
        return EXIT_FAILURE;
    }
    in = fopen(argv[1], "rb");
    if (in == NULL) {
        fprintf(stderr, "Cannot open input: %s\n", argv[1]);
        goto cleanup;
    }
    out = fopen(argv[2], "wb");
    if (out == NULL) {
        fprintf(stderr, "Cannot open output: %s\n", argv[2]);
        goto cleanup;
    }
    output_acquired = 1;
    while ((n = fread(buf, 1, sizeof buf, in)) > 0) {
        if (fwrite(buf, 1, n, out) != n) {
            fprintf(stderr, "Write failed: %s\n", argv[2]);
            goto cleanup;
        }
    }
    if (ferror(in)) {
        fprintf(stderr, "Read failed: %s\n", argv[1]);
        goto cleanup;
    }
    status = EXIT_SUCCESS;

cleanup:
    if (out != NULL && fclose(out) == EOF) {
        fprintf(stderr, "Close failed: %s\n", argv[2]);
        status = EXIT_FAILURE;
    }
    if (in != NULL && fclose(in) == EOF) {
        fprintf(stderr, "Close failed: %s\n", argv[1]);
        status = EXIT_FAILURE;
    }
    if (output_acquired && status != EXIT_SUCCESS) {
        if (remove(argv[2]) != 0)
            fprintf(stderr, "Cannot remove incomplete output: %s\n",
                    argv[2]);
    }
    return status;
}

El bucle de entrada procesa solo los bytes realmente leídos. Una escritura corta salta a la liberación de recursos; se comprueba si hay un error de entrada después del bucle. El cierre de la salida aún puede convertir el éxito en fallo. Solo se intenta eliminar la salida cuando esta ejecución la abrió correctamente, por lo que un fallo de apertura no provoca la eliminación de un archivo ajeno. El requisito de usar archivos distintos es importante: "wb" borraría la entrada si los dos nombres identificaran el mismo archivo.

Conservar los datos existentes importantes

Abrir directamente la salida no permite deshacer el truncamiento. Para sustituir datos valiosos, escribe primero con un nombre temporal distinto. Comprueba cada escritura y el cierre final antes de cambiar los nombres. Conserva el original con un nombre de copia de seguridad hasta que el archivo nuevo esté instalado; comprueba cada llamada a rename y remove. Si la instalación falla, informa de la ubicación del archivo recuperable en lugar de eliminarlo.

Una función auxiliar debe cerrar lo que haya abierto y devolver un resultado de éxito o fallo a la función llamadora. La función llamadora puede decidir si vuelve a intentarlo o termina. Devolver EXIT_FAILURE después de cualquier paso incompleto permite que un script se detenga antes de una acción dependiente, como eliminar el original después de una copia de seguridad.

Puntos clave

  • Inicializa la propiedad de los flujos y mantén el fallo como estado predeterminado.
  • Cierra cada flujo abierto correctamente exactamente una vez en cada ruta.
  • Deja que un fallo de cierre cambie el estado final.
  • Elimina la salida incompleta solo cuando esta ejecución la haya creado o abierto.
  • Escribe las sustituciones por separado y conserva el original hasta que la instalación tenga éxito.
  • Las funciones auxiliares informan de los fallos a sus funciones llamadoras para que estas puedan elegir cómo recuperarse.

Ejemplos de Entrada y salida de archivos en C

5 Lecciones Interactivas

1

Abrir un flujo sin perder datos existentes

12 pasos
Elegir un modo de archivo, seguir la transformación de texto y conectar el mismo código de procesamiento a los flujos estándar.
  1. 1
    IntroducciónDecidir qué debe conservarse

    Un programa está a punto de guardar resultados. Antes de abrir nada, decide si deben conservarse los datos antiguos y si el archivo contiene líneas legibles o bytes exactos. Esas decisiones determinan el modo, y una elección equivocada puede borrar datos antiguos.

    Seguirás una escritura desde el texto del programa a través de su flujo (el canal de la biblioteca hacia un archivo o terminal) y después elegirás dónde deben ir los resultados normales y los mensajes de diagnóstico (los flujos estándar). La apertura ya es una operación sobre el archivo, por lo que esta decisión precede a la primera escritura.

  2. 2
    ExplicaciónAcceder a los datos mediante un flujo

    Un flujo es el canal de la biblioteca estándar hacia un archivo, un terminal o una tubería. Guarda su referencia como un FILE * de <stdio.h> y pásala a funciones como fprintf.

    El objeto de la biblioteca recuerda el búfer, la posición y los indicadores de estado. No modifiques sus campos. La posición en un archivo avanza a medida que se procesan los datos; un terminal o una tubería no pueden tratarse como un archivo ordinario para desplazarse por él.

  3. 3
    EjemploSeguir los saltos de línea hasta los bytes almacenados

    Escribir "a\nb\nc\n" proporciona tres letras y tres caracteres de salto de línea. En Linux o macOS, el archivo de texto contiene seis bytes. En Windows, cada salto de línea se convierte en CR LF, lo que da nueve bytes almacenados.

    Leer ese archivo de Windows en modo texto de Windows recupera seis caracteres. La entrada binaria expone los nueve bytes. El texto del programa y la secuencia de bytes almacenada son dos formas de ver las mismas líneas.

  4. 4
    ConexiónElegir un modo para una imagen

    Una secuencia de bytes en una imagen comprimida puede contener valores que el modo texto transforma. Añadir b selecciona el modo binario y conserva esos valores.

    Esto explica por qué un lector de imágenes que funciona con "r" en Linux puede fallar en Windows. Debe usar "rb" porque maneja una secuencia definida de bytes, no líneas que la biblioteca deba transformar.

  5. 5
    DesafíoComprobar un recuento de caracteres

    En Windows, una escritura en modo texto almacena "m\nn\n". ¿Cuántos bytes contiene el archivo resultante y por qué?

    ---reveal---

    Contiene seis bytes: dos letras más dos pares CR LF. Los cuatro caracteres proporcionados por el programa se amplían porque cada salto de línea se convierte en dos bytes almacenados. En modo binario, esos mismos cuatro bytes proporcionados se escribirían sin esa transformación.

  6. 6
    ExplicaciónDecidir qué conservar antes de acceder

    Para un archivo existente, "r" permite leer, "w" borra y permite escribir, y "a" conserva los datos y añade al final. Un + permite tanto la entrada como la salida.

    Usa "r+" para conservar un archivo existente al actualizarlo. "w+" sigue borrándolo. "wx" de C11 falla si el archivo existe, lo que resulta útil cuando debe protegerse un destino existente.

  7. 7
    ConsejoAbrir y cerrar un flujo

    Después de FILE *fp = fopen(name, "r");, comprueba fp == NULL antes de cualquier operación sobre el flujo. Un fallo no proporciona ningún flujo que procesar o cerrar.

    Si tiene éxito, el programa posee un flujo que necesita una llamada a fclose. Comprueba también ese cierre. El flujo queda cerrado después de la llamada incluso si el cierre falla; volver a intentar cerrarlo usa un flujo que ya no es válido.

  8. 8
    DesafíoProteger el registro anterior

    Un archivo de registro existente debe conservar sus entradas y hay que añadir una línea nueva. Una persona que está aprendiendo elige "w" porque la tarea escribe. ¿Qué modo debe usarse y cuándo destruiría "w" las entradas antiguas?

    ---reveal---

    Usa "a". El modo "w" destruye el contenido existente en cuanto la apertura tiene éxito, incluso antes de una escritura. La elección debe proteger el registro durante la apertura, no solo durante el código de procesamiento posterior.

  9. 9
    ExplicaciónSeparar los resultados de las explicaciones

    Los flujos ya abiertos son stdin para la entrada, stdout para los resultados y stderr para los mensajes de diagnóstico. Una función que acepta FILE *out puede escribir la misma disposición en un archivo o en stdout.

    Un intérprete de comandos puede redirigir la salida estándar a un archivo o enviarla por una tubería a otro programa. Mantén el texto de diagnóstico en stderr para que un resultado legible por una máquina no incluya mensajes de error entre sus filas de datos.

  10. 10
    Idea claveHacer que aparezca el texto almacenado en búfer

    La salida puede esperar en un búfer de memoria. La salida estándar a un terminal suele usar búfer por línea; la salida redirigida suele usar búfer completo. La salida de error estándar no usa búfer completo.

    Un mensaje de solicitud sin salto de línea puede necesitar una llamada a fflush(stdout) cuyo resultado se compruebe antes de que comience la entrada. Vaciar el búfer no descarta la entrada. Para omitir una línea de entrada no deseada, consume caracteres hasta su salto de línea o el fin de archivo.

  11. 11
    DesafíoSeguir la salida de un filtro

    Un filtro lee la entrada estándar, escribe resultados en la salida estándar y escribe errores en la salida de error estándar. Se ejecuta como filter < raw.txt > clean.txt. ¿Dónde debe aparecer un mensaje sobre un registro rechazado y qué estado debe devolver si no puede completar la tarea?

    ---reveal---

    El mensaje de diagnóstico va al destino de error heredado, normalmente el terminal. Devuelve EXIT_FAILURE. El archivo de resultados permanece separado del mensaje y el intérprete de comandos puede detectar el fallo.

  12. 12
    RepasoGestionar conscientemente el ciclo de vida de un flujo

    Elige qué conservar y el comportamiento de texto o binario antes de abrir. Comprueba que la apertura haya producido un flujo, procesa solo mediante punteros válidos y cierra una vez cada flujo que poseas.

    Los flujos estándar permiten que el intérprete de comandos proporcione las conexiones. Separa los resultados de los mensajes de diagnóstico y devuelve un estado que describa la tarea completada. Estas decisiones permiten que el mismo programa pequeño funcione de forma interactiva, con archivos o dentro de una cadena de programas conectados por tuberías.

2

Leer un registro de texto y validar su contenido

15 pasos
Pasar de lecturas de caracteres a valores con formato y líneas completas, gestionando los límites que causan errores habituales de entrada.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónLeer a la escala adecuada
  2. 2
    ExplicaciónDistinguir un carácter de EOF
  3. 3
    EjemploContar solo una lectura correcta
  4. 4
    DesafíoIncluir la línea final sin terminación
  5. 5
    EjemploEscribir con una disposición controlada
  6. 6
    ConsejoReservar espacio para el terminador de la cadena
  7. 7
    ExplicaciónUsar el número de asignaciones
  8. 8
    DesafíoElegir un nombre con formato de tamaño limitado
  9. 9
    ExplicaciónLeer una línea en un espacio de almacenamiento conocido
  10. 10
    EjemploSeguir una línea a través de dos lecturas
  11. 11
    ConsejoEliminar el final sin eliminar datos
  12. 12
    ExplicaciónAnalizar la línea ya leída
  13. 13
    DesafíoAceptar una línea que cabe exactamente
  14. 14
    DesafíoRechazar un prefijo con un sufijo no válido
  15. 15
    RepasoMantener separadas la lectura y la interpretación
3

Transferir bytes y definir su significado

12 pasos
Copiar correctamente un bloque final corto y después decodificar registros mediante una disposición binaria explícita.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónSeparar los bytes de los valores
  2. 2
    ExplicaciónElegir qué cuenta el valor de retorno
  3. 3
    EjemploSeguir el bloque final corto
  4. 4
    Idea claveDistinguir un registro de un bloque de bytes
  5. 5
    DesafíoUsar el recuento de la lectura correcta
  6. 6
    ExplicaciónNo dejar que el compilador diseñe el formato
  7. 7
    EjemploDecodificar un valor con el byte menos significativo primero
  8. 8
    EjemploLocalizar un registro a partir de su disposición
  9. 9
    DesafíoComprobar la cantidad de datos declarada
  10. 10
    ConexiónSeguir la estructura que permite el formato
  11. 11
    DesafíoExigir un campo completo antes de decodificar
  12. 12
    RepasoHacer que la transferencia y el formato coincidan
4

Encontrar un registro y sustituirlo de forma segura

13 pasos
Calcular un desplazamiento, conservar una posición guardada y seguir las reglas de los flujos de actualización al sustituir un registro.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónAcceder directamente a los datos que necesitas
  2. 2
    ExplicaciónSeleccionar un punto de referencia
  3. 3
    EjemploLocalizar el registro con índice 3 desde cero
  4. 4
    ConsejoRestaurar posiciones de texto como valores opacos
  5. 5
    DesafíoEncontrar el tercer registro
  6. 6
    ExplicaciónConservar el archivo existente
  7. 7
    EjemploRestaurar el principio del registro
  8. 8
    Idea claveCompletar la sustitución
  9. 9
    DesafíoElegir tanto el modo como el desplazamiento
  10. 10
    ConexiónReescribir cuando un registro crece
  11. 11
    ConsejoMantener recuperable la instalación
  12. 12
    DesafíoInterpretar una adición completada
  13. 13
    RepasoEl posicionamiento forma parte de una actualización válida
5

Reflejar el fallo en los mensajes y la liberación de recursos

12 pasos
Diagnosticar si la entrada se completó, conservar el error original y hacer que los fallos tardíos de salida cambien el resultado final.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónEl éxito incluye el cierre final
  2. 2
    ExplicaciónLeer el resultado de cada función
  3. 3
    ExplicaciónExplicar por qué se detuvo la entrada
  4. 4
    DesafíoRechazar una cabecera truncada
  5. 5
    ExplicaciónGuardar el motivo original
  6. 6
    EjemploImprimir a partir del código guardado
  7. 7
    DesafíoElegir la fuente correcta del mensaje de diagnóstico
  8. 8
    ExplicaciónLlevar el control de los flujos abiertos
  9. 9
    EjemploPermitir que la liberación de recursos cambie el éxito
  10. 10
    DesafíoDecidir la siguiente acción de un script
  11. 11
    Idea claveConservar el original después de un cambio de nombre fallido
  12. 12
    RepasoDevolver el resultado de la tarea completa

Ejercicios de Entrada y salida de archivos en C

40 Preguntas de Práctica en 4 sets

Set 1: Elegir flujos y procesar entradas completas10 Preguntas de Práctica

Pregunta 1 de 10

Un campo de 32 bits con el byte menos significativo primero contiene los bytes de ocho bits 07 02 00 00. ¿Qué valor representa?
  1. 1794
  2. 7
  3. 131079
  4. 519
Mostrar respuestaOcultar respuesta
Respuesta: D
El orden con el byte menos significativo primero da al primer byte un peso de 1 y al segundo un peso de 256, lo que produce 7 más 512, es decir, 519. Leer 07 02 como un par con el byte más significativo primero daría 1794. El orden de los bytes de la propia máquina no cambia la interpretación especificada por el formato de archivo.

Pregunta 2 de 10

¿Qué modo lee un archivo comprimido sin transformación de texto?
  1. "r"
  2. "rb"
  3. "wb"
  4. "ab"
Mostrar respuestaOcultar respuesta
Respuesta: B
"rb" abre un archivo existente para entrada binaria y conserva sus bytes almacenados. "r" selecciona el modo texto, que puede transformar los finales de línea y reconocer Ctrl+Z como fin de la entrada en Windows. Los modos de escritura no proporcionan el acceso de lectura solicitado.

Pregunta 3 de 10

Un programa debe añadir una entrada nueva a un archivo de registro existente y conservar las anteriores. ¿Qué modo de apertura es adecuado?
  1. "w"
  2. "r"
  3. "w+"
  4. "a"
Mostrar respuestaOcultar respuesta
Respuesta: D
El modo de adición conserva el contenido existente y sitúa cada escritura al final. El modo "w" borraría las entradas anteriores del registro en cuanto la apertura tuviera éxito. El modo "r" conserva los datos, pero no permite escribir la nueva entrada; "w+" permite la entrada y la salida, pero también borra el archivo.

Pregunta 4 de 10

fgets lee correctamente la última línea, que contiene "maple" sin salto de línea. ¿Qué deja line[strlen(line) - 1] = '\0';?
  1. "mapl"
  2. "maple"
  3. "maple\n"
  4. "map"
Mostrar respuestaOcultar respuesta
Respuesta: A
El código siempre sustituye el último carácter almacenado, por lo que elimina la e de "maple". fgets no inventa un salto de línea cuando el archivo no lo tiene. Localiza CR o LF con strcspn antes de eliminar el final para que una última línea sin terminación conserve todos sus datos reales.

Pregunta 5 de 10

En un sistema con char de ocho bits con signo, un archivo binario comienza con el byte 0xFF y contiene más datos. ¿Por qué puede detenerse inmediatamente char c; while ((c = fgetc(fp)) != EOF)?
  1. El modo binario convierte 0xFF en fin de archivo.
  2. La asignación compara antes de guardar el byte.
  3. El byte puede convertirse en -1 al pasar a char.
  4. La primera lectura correcta activa el indicador EOF.
Mostrar respuestaOcultar respuesta
Respuesta: C
fgetc devuelve el byte como un int no negativo, pero almacenarlo en un char de ocho bits con signo puede convertir 255 en -1. Ese valor puede ser igual al EOF de la implementación en una comparación, deteniendo el bucle antes de los bytes posteriores. Los paréntesis son correctos aquí; el problema lo causa el tipo de destino más estrecho.

Pregunta 6 de 10

Dados char tag[14]; int count;, ¿qué llamada lee de forma segura una palabra y un entero en estos objetos?
  1. fscanf(fp, "%14s %d", tag, &count)
  2. fscanf(fp, "%13s %d", tag, &count)
  3. fscanf(fp, "%13s %d", tag, count)
  4. fscanf(fp, "%14s %d", tag, count)
Mostrar respuestaOcultar respuesta
Respuesta: B
La conversión de la palabra debe permitir como máximo 13 caracteres para que el array de 14 bytes conserve un byte para su terminador nulo. La conversión del entero también requiere &count, un puntero al destino. El ancho 14 coincide con el tamaño del array, pero permite un carácter de entrada más de los que el array puede contener de forma segura junto con su terminador.

Pregunta 7 de 10

Un informe se redirige a un archivo. ¿Qué flujo debe llevar un mensaje que explique que un registro de entrada no es válido?
  1. stderr
  2. stdout
  3. stdin
  4. El flujo de salida del informe
Mostrar respuestaOcultar respuesta
Respuesta: A
stderr mantiene los mensajes de diagnóstico separados de los datos del informe enviados a stdout. Imprimir el mensaje en stdout lo situaría dentro del informe redirigido y podría alterar su formato esperado. La entrada estándar proporciona datos para leer; no es el destino de un mensaje de diagnóstico.

Pregunta 8 de 10

Una llamada correcta a fwrite(a, 4, 7, fp) escribe todos los elementos solicitados. ¿Qué devuelve?
  1. 4
  2. 28
  3. 7
  4. 1
Mostrar respuestaOcultar respuesta
Respuesta: C
fwrite devuelve el número de elementos completos escritos, por lo que devuelve 7. La transferencia abarca 28 bytes porque cada elemento tiene tamaño 4, pero ese total de bytes no es el valor de retorno. Los recuentos de bytes y de elementos solo coinciden cuando el tamaño de elemento es 1.

Pregunta 9 de 10

Un archivo binario tiene una cabecera de 12 bytes y registros de 20 bytes. Después de desplazarse al byte 12, un programa lee dos registros completos. ¿Qué llamada relativa a fseek selecciona ahora el cuarto registro contado desde 1?
  1. fseek(fp, 40L, SEEK_CUR)
  2. fseek(fp, 60L, SEEK_CUR)
  3. fseek(fp, 20L, SEEK_CUR)
  4. fseek(fp, 72L, SEEK_CUR)
Mostrar respuestaOcultar respuesta
Respuesta: C
Las dos lecturas avanzan del byte 12 al byte 52. El cuarto registro tiene índice 3, por lo que comienza en el byte 72, después de la cabecera y tres registros anteriores; avanzar 20 bytes permite alcanzarlo. Pasar 72 con SEEK_CUR sumaría esa ubicación absoluta a la posición actual en lugar de seleccionarla.

Pregunta 10 de 10

Se lee una cabecera obligatoria de 16 bytes mediante fread(&h, 16, 1, fp). La llamada devuelve 0, ferror(fp) es cero y feof(fp) es distinto de cero. ¿Cómo debe proceder el lector?
  1. Rechazar la cabecera incompleta sin interpretar sus campos.
  2. Interpretar la cabecera porque no hubo un error del flujo.
  3. Repetir la lectura sin cambiar el estado del flujo.
  4. Borrar los indicadores y aceptar los campos rellenados con ceros.
Mostrar respuestaOcultar respuesta
Respuesta: A
No llegó ninguna cabecera completa y los indicadores muestran fin de archivo, no un error de acceso al flujo. Por tanto, al archivo le faltan datos exigidos por el formato, aunque el mecanismo de lectura no haya fallado. El objeto puede contener un elemento parcial con un valor indeterminado, por lo que la ausencia de ferror no hace seguro interpretar sus campos.
Set 2: Gestionar límites de texto y disposiciones binarias10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

Un programa se inicia en /work/run y abre "data/items.txt". ¿Qué ruta se resuelve?
  1. /work/data/items.txt
  2. /work/run/items.txt
  3. /work/run/data/items.txt
  4. La ruta junto al archivo fuente
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

En el comando producer | consumer > result.txt de un intérprete de comandos, ¿a dónde va de forma predeterminada la salida de error estándar de producer?
  1. A la entrada estándar de consumer
  2. A su destino de error heredado
  3. A result.txt junto con los resultados
  4. A la entrada estándar de producer
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

Se copia un archivo de 1540 bytes con un búfer de 600 bytes y fread(buf, 1, 600, in). ¿Qué tamaños deben usar las escrituras correctas?
  1. 600, 600, 340
  2. 600, 600, 600
  3. 600, 340, 600
  4. 600, 600, 0
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

char name[8]; recibe el resultado de snprintf(name, sizeof name, "part-%d", 2468), que devuelve 9. ¿Qué debe concluir el programa?
  1. El destino contiene ahora el nombre completo.
  2. El nombre de nueve caracteres cabe en el búfer.
  3. Nueve bytes guardados incluyen el terminador nulo.
  4. El resultado se truncó y debe gestionarse.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

Un validador permite como máximo siete caracteres de contenido por línea. Un archivo sin errores contiene "cedars\nmaplesx". El programa llama repetidamente a fgets(buf, 8, fp). ¿Qué límites de registro debe reconocer?
  1. Un registro válido formado al unir ambas partes.
  2. Un registro válido: «cedars»; rechazar «maplesx».
  3. Dos registros válidos: «cedars» y «maples».
  4. Dos registros válidos: «cedars» y «maplesx».
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

Una entrada sin errores contiene "north\nsouth\neast". ¿Cuántas líneas y caracteres de salto de línea contiene?
  1. 3 líneas y 3 saltos de línea
  2. 2 líneas y 2 saltos de línea
  3. 3 líneas y 2 saltos de línea
  4. 2 líneas y 3 saltos de línea
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

Dos sistemas proporcionan uint32_t, pero difieren en el orden de los bytes y el relleno de estructuras. Un programa que escribe un formato vuelca struct { char kind; uint32_t count; } con una llamada a fwrite. ¿Qué cambio de diseño hace que la representación sea independiente de ambas diferencias?
  1. Codificar cada campo definido en un orden de bytes elegido.
  2. Sustituir el miembro por un unsigned int sin modificar.
  3. Escribir sizeof en la cabecera y conservar el volcado.
  4. Conservar la estructura y abrir el archivo con "wb".
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

La posición de un flujo de texto se guardó mediante long p = ftell(fp); y se comprobó. Después de leer más, ¿qué llamada válida vuelve a ella?
  1. fseek(fp, p, SEEK_CUR)
  2. fseek(fp, p, SEEK_SET)
  3. fseek(fp, p + 1, SEEK_SET)
  4. fseek(fp, -p, SEEK_END)
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

Un archivo binario tiene una cabecera de 8 bytes y cinco registros de 16 bytes. Un flujo "r+b" se desplaza al byte 40 y lee un registro completo sin llegar a EOF. Se modifica un campo. ¿Qué operación antes de escribir permite el cambio de dirección y selecciona ese mismo registro?
  1. fseek(fp, -16L, SEEK_CUR), para volver al byte 40.
  2. fseek(fp, 0L, SEEK_CUR), para quedarse en el byte 56.
  3. fseek(fp, 24L, SEEK_SET), para ir al byte 24.
  4. fflush(fp), para dejar la posición en el byte 56.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

Una llamada fallida a una biblioteca establece errno. El programa debe cerrar otro flujo antes de informar de la causa original. ¿Qué debe conservar primero?
  1. La longitud actual del búfer de salida
  2. El siguiente puntero a flujo disponible
  3. El valor actual de errno
  4. El resultado de una nueva llamada correcta
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Set 3: Actualizar registros y conservar resultados fiables10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

En Windows con bytes de ocho bits, se escribe "x\ny\n" en modo texto. ¿Cuántos bytes se almacenan?
  1. 4
  2. 6
  3. 8
  4. 5
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

Un programa C11 debe crear una nueva exportación binaria, pero debe conservar cualquier archivo existente con ese nombre. ¿Qué modo es adecuado?
  1. "wb"
  2. "ab"
  3. "r+b"
  4. "wbx"
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

Un formato tiene una cabecera de 8 bytes y registros de exactamente 18 bytes. Su campo de recuento indica 6 registros, pero el archivo completo solo tiene 98 bytes. ¿Qué debe concluir un lector antes de reservar memoria para esos registros?
  1. El archivo no puede proporcionar los seis registros que declara.
  2. El recuento es válido porque la cabecera está completa.
  3. El archivo contiene seis registros al redondear la longitud.
  4. El último registro puede completarse con bytes de valor cero.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

Se pasa una línea completa "64km" a strtol después de poner errno a cero. El valor de retorno es 64, errno sigue siendo 0 y end apunta a k. El campo debe ser un entero completo con caracteres en blanco finales opcionales. ¿Cuál es la decisión correcta?
  1. Aceptar porque errno permaneció en cero.
  2. Aceptar después de descartar las dos letras.
  3. Rechazar porque queda texto que no es blanco.
  4. Rechazar porque no se encontró un prefijo numérico.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

Un archivo binario sin errores tiene 27 bytes. Se realizan dos llamadas a fread(b, 16, 1, fp) con un array de 16 bytes. ¿Qué devuelve la segunda llamada y cómo puede usarse su elemento?
  1. 11; sus once bytes forman un elemento completo.
  2. 1; los cinco bytes que faltan se rellenan con ceros.
  3. 0; su valor parcial puede servir como el siguiente registro.
  4. 0; el elemento parcial no debe interpretarse.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

La entrada es "18 pear 26". Después de una llamada correcta a fscanf(fp, "%d", &n), la misma llamada devuelve 0 dos veces. ¿Por qué no ha llegado a 26?
  1. La primera lectura consumió automáticamente los tres campos.
  2. La palabra que no coincide sigue sin leerse en la siguiente conversión.
  3. La segunda lectura llegó a EOF y eliminó la palabra.
  4. El destino entero debe cambiarse por un double.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

¿Qué valor indica que fseek ha fallado?
  1. Un resultado distinto de cero
  2. El nuevo desplazamiento en bytes
  3. Siempre exactamente EOF
  4. Siempre exactamente -1L
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

Un archivo binario que admite desplazamientos contiene una cabecera de 10 bytes y cuatro registros de 14 bytes. Un lector con "r+b" se desplaza al byte 38 y lee un registro completo sin llegar a EOF. Modifica un campo. ¿Qué operación posterior selecciona el mismo registro y permite escribir la sustitución?
  1. fflush(fp)
  2. fseek(fp, 0L, SEEK_CUR)
  3. fseek(fp, 38L, SEEK_SET)
  4. fseek(fp, 52L, SEEK_SET)
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

Todas las escrituras de salida devolvieron los recuentos esperados, pero fclose(out) devuelve EOF. ¿Qué resultado debe comunicar el programa?
  1. Éxito, porque todos los datos llegaron al búfer de escritura.
  2. Éxito, después de volver a llamar a fclose con el mismo flujo.
  3. Fallo, solo si feof(out) también está activado.
  4. Fallo, porque la salida almacenada en búfer puede estar incompleta.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

La entrada se abre correctamente y después la apertura de la salida devuelve NULL. ¿Qué debe hacer esta ruta antes de devolver un fallo?
  1. Cerrar la entrada una vez e informar del fallo de apertura de la salida.
  2. Cerrar ambos punteros, incluido el puntero nulo de salida.
  3. Eliminar la ruta de salida aunque no se haya abierto.
  4. Retornar inmediatamente y dejar la entrada abierta para la función llamadora.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Set 4: Diagnosticar fallos en un proceso completo con archivos10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

Un programa lee en Linux una línea creada en Windows y solo elimina su LF. La comparación del resultado con "ready" falla aunque las letras visibles coinciden. ¿Qué carácter conservado explica esto?
  1. Una tabulación antes de las letras
  2. Un CR antes del LF eliminado
  3. Un segundo terminador nulo
  4. Un byte EOF almacenado por fgets
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

Un programa debe añadir su salida normal al final de un archivo llamado totals.txt desde el intérprete de comandos. ¿Qué operador de redirección necesita?
  1. < totals.txt
  2. 2> totals.txt
  3. > totals.txt
  4. >> totals.txt
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

Un archivo tiene tres registros de 12 bytes con puntuaciones de 10, 20 y 30. En modo "a+b", un programa se desplaza al byte 12, lee un registro, cambia su puntuación a 25, vuelve al byte 12 y escribe el registro. Todas las llamadas tienen éxito. ¿Qué puntuaciones tienen después el segundo y el último registro?
  1. Segundo: 20; último: 25; cuatro registros en total.
  2. Segundo: 25; último: 30; tres registros en total.
  3. Segundo: 25; último: 25; cuatro registros en total.
  4. Segundo: 20; último: 30; tres registros en total.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

Los registros de enteros completos pueden contener como máximo siete caracteres de contenido. Con char buf[8], las lecturas devuelven "8642kg\n" y después "1234567"; la siguiente lectura comprobada confirma el fin de archivo normal. strtol encuentra 8642 con kg al final en el primer registro y convierte todos los dígitos del segundo, sin errores de rango. ¿Qué registros son válidos?
  1. Aceptar ambos prefijos numéricos completos.
  2. Rechazar ambos por ser demasiado largos para el búfer.
  3. Rechazar el primero y aceptar el segundo.
  4. Aceptar solo el primero, que termina en LF.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

Una sustitución se ha escrito y cerrado por completo. El cambio de nombre del original a una copia de seguridad tiene éxito; la instalación de la sustitución falla porque su destino está ahora ocupado. ¿Qué acción conserva el original sin sobrescribir el nuevo archivo que ocupa el destino?
  1. Eliminar la copia de seguridad, conservar la sustitución y devolver un fallo.
  2. Conservar la copia de seguridad y la sustitución, informar del fallo y resolver el conflicto de nombres antes de reintentar.
  3. Cambiar el nombre de la copia de seguridad al nombre ocupado sin comprobar el resultado.
  4. Eliminar inmediatamente el destino ocupado y volver a intentar la instalación.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

Un archivo sin errores contiene "a\nb". Un programa usa int c; size_t n = 0, lines = 0; while (c = fgetc(in) != EOF) { ++n; if (c == '\n') ++lines; }. ¿Qué totales se obtienen y qué corrección permite contar correctamente las líneas?
  1. n = 4, lines = 0; comprobar feof antes de leer y contar la línea final.
  2. n = 3, lines = 1; corregir los paréntesis de la asignación sin gestionar la línea final.
  3. n = 3, lines = 0; corregir los paréntesis de la asignación y contar la línea final sin terminación.
  4. n = 2, lines = 1; conservar la condición y cambiar c de int a char.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

Una lectura con elementos de tamaño 1 solicita una cabecera obligatoria de 12 bytes, pero obtiene 9 bytes. feof está activado y ferror está desactivado. Después se realiza correctamente un fseek al principio. ¿Qué sigue siendo cierto y qué debe hacer el analizador?
  1. EOF está desactivado; rechazar la cabecera incompleta salvo que una nueva lectura completa tenga éxito.
  2. EOF sigue activado; borrar ambos indicadores y decodificar los nueve bytes.
  3. La cabecera se completó; decodificarla después de comprobar feof de nuevo.
  4. El indicador de error está ahora activado; informar de un nuevo fallo de posicionamiento.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

Una apertura de entrada falla y su errno se guarda como open_error. Después falla el cierre de una salida abierta anteriormente y proporciona un código diferente, guardado como close_error. ¿Cómo debe un mensaje de diagnóstico conservar ambos fallos?
  1. Describir ambas operaciones con strerror(close_error); el código más reciente sustituye las causas anteriores.
  2. Describir la apertura con perror después de liberar recursos y omitir el mensaje del cierre por redundante.
  3. Describir el error de apertura guardado, pero devolver éxito si la liberación de recursos llegó a su última sentencia.
  4. Describir la apertura con strerror(open_error) y el cierre con strerror(close_error); devolver un fallo.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

fopen devuelve un flujo válido, pero errno sigue conteniendo un valor anterior distinto de cero. ¿Qué demuestra ese valor sobre esta apertura?
  1. El flujo debe cerrarse como si la apertura hubiera fallado.
  2. No demuestra que esta apertura correcta haya fallado.
  3. La siguiente lectura fallará inmediatamente con seguridad.
  4. El archivo se abrió con un modo de acceso incorrecto.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

Una copia abrió flujos de entrada y salida distintos. La entrada informa de un error de lectura; después, durante la liberación de recursos, se cierra la salida y se devuelve EOF. La entrada sigue abierta y la salida está incompleta. ¿Qué acciones restantes y qué resultado protegen el archivo fuente y liberan los recursos?
  1. Volver a cerrar la salida, cerrar una vez la entrada, eliminar la salida incompleta, conservar el original y devolver un fallo.
  2. Cerrar una vez la entrada, eliminar la salida incompleta, conservar el original y devolver éxito si la liberación tiene éxito.
  3. Borrar el error de lectura, cerrar una vez la entrada, conservar ambos archivos y devolver éxito si el último cierre tiene éxito.
  4. Cerrar una vez la entrada, intentar eliminar la salida incompleta y comprobarlo, conservar el original y devolver un fallo.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

¿Te atascas con una pregunta tuya? Ayuda con Tareas

Términos Clave

61 Términos Clave, cada uno con su definición

A

Acceso aleatorio
El acceso aleatorio consiste en desplazarse directamente a una ubicación elegida de un archivo que admite posicionamiento, sin leer todos los datos anteriores.
Una cabecera y un ancho fijo de registro permiten que un programa calcule dónde comienza un registro seleccionado.
Actualización en la misma posición
Una actualización en la misma posición sustituye datos dentro del espacio que ya ocupan en el archivo sin desplazar ni reescribir los registros posteriores.
Un registro modificado de tamaño fijo debe escribirse de nuevo en su posición inicial original.
Almacenamiento en búfer
El almacenamiento en búfer consiste en reunir datos temporalmente en memoria para que muchas solicitudes pequeñas de entrada y salida puedan compartir transferencias más grandes.
Un informe puede permanecer en el búfer de salida hasta que el búfer se vacíe o el flujo se cierre.
Análisis de los campos de una línea
El análisis de los campos de una línea consiste en interpretar los campos de una línea de entrada completa después de haberla leído en memoria.
Puede informarse de una cantidad incorrecta con su número de línea antes de leer el siguiente registro.
Ancho de campo
El ancho de campo controla un ancho mínimo de salida o un ancho máximo de entrada, según la función de entrada y salida con formato.
%23s en la entrada deja espacio para un terminador en un array de caracteres de 24 bytes.

C

Cabecera del archivo
Una cabecera del archivo es una parte inicial de un archivo que contiene campos de identificación y estructura necesarios para interpretar los datos posteriores.
Comprueba la firma y el recuento completos antes de confiar en los registros indicados por una cabecera.
clearerr
clearerr borra tanto el indicador de fin de archivo como el de error de un flujo sin corregir la causa de ningún fallo.
Después de resolver un problema de entrada, un programa puede borrar los indicadores antes de un nuevo intento controlado.
Copia por bloques
Una copia por bloques transfiere un archivo mediante un búfer reutilizable y escribe solo los bytes proporcionados por cada lectura correcta.
Una lectura final corta debe producir una escritura final corta para que no se añadan datos sobrantes del búfer.
Creación exclusiva
La creación exclusiva consiste en abrir un archivo nuevo solo si su nombre no identifica ya un archivo existente.
El modo "wx" de C11 protege un informe existente para que no se borre durante la apertura.

D

Devolución de un carácter al flujo
La devolución de un carácter al flujo consiste en devolver un carácter a un flujo de entrada para que la siguiente lectura lo recupere de nuevo.
Un analizador puede examinar un separador y usar ungetc para dejarlo para la siguiente etapa.
Directorio de trabajo actual
El directorio de trabajo actual es la carpeta de referencia del programa en ejecución para resolver nombres de rutas relativas.
Iniciar un programa en otra carpeta cambia el archivo al que hace referencia "data/input.txt".

E

Elemento parcial
Un elemento parcial es una unidad incompleta del tamaño de un objeto obtenida mediante una lectura y omitida del recuento de elementos completos de fread.
Con una entrada de elementos del tamaño de un registro, los bytes restantes al final no pueden tratarse como un registro válido.
Entrada estándar
La entrada estándar es el flujo ya abierto stdin del que un programa recibe normalmente su entrada principal.
Con < values.txt, un filtro lee datos de un archivo mediante stdin en lugar del teclado.
Entrecomillado de campos CSV
El entrecomillado de campos CSV encierra entre comillas los campos de texto que contienen comas, comillas o saltos de línea y duplica las comillas internas.
Un nombre de ciudad que contiene una coma debe seguir siendo un solo campo cuando se vuelva a leer el registro.
EOF
EOF es una constante entera negativa que usan las funciones de entrada de caracteres cuando termina la entrada o se produce un error de lectura.
Guarda el valor devuelto en un int para que un byte real no se confunda con este indicador.
ERANGE
ERANGE es el código estándar de error de rango que se usa cuando una conversión o un cálculo produce un valor fuera de su rango admitido.
Pon errno a cero antes de strtol para que un error de rango antiguo no se confunda con uno nuevo.
errno
errno es una expresión entera modificable que contiene un código de error cuyo significado depende del comportamiento de error documentado de una función.
Guarda su valor inmediatamente después de un fallo comunicado, antes de que otra llamada a la biblioteca pueda cambiarlo.
Especificación de formato
Una especificación de formato es una instrucción que comienza con un signo de porcentaje y selecciona cómo la entrada y salida con formato imprime o convierte un valor.
Para la entrada, %lf requiere un destino double *, mientras que %f requiere un destino float *.
Estado de salida
Un estado de salida es el resultado que un programa devuelve a su entorno para que los scripts puedan distinguir una ejecución correcta de una fallida.
Un comando dependiente después de && no debe ejecutarse tras una copia de archivo incompleta.

F

Fallo de coincidencia
Un fallo de coincidencia ocurre cuando los caracteres de entrada no se ajustan a una conversión con formato solicitada, sin que sea necesario un error de entrada o salida.
Leer un entero de "oak" puede devolver 0 mientras los indicadores de fin de archivo y de error del flujo permanecen desactivados.
fclose
fclose es la función que vacía el búfer de salida pendiente, cierra un flujo e informa de éxito con 0 o de fallo con EOF.
Después de que fclose(fp) retorne, incluso con un error, ese flujo no puede volver a usarse.
fgetc
fgetc es la función que lee un carácter como un valor de carácter sin signo convertido a int, o devuelve EOF.
Un bucle cuenta un separador solo después de que fgetc haya devuelto correctamente un carácter.
fgets
fgets lee una secuencia limitada de caracteres, conserva un salto de línea si lo encuentra y añade un terminador nulo si tiene éxito.
Una línea más larga que un búfer de 32 bytes se devuelve en varias lecturas correctas.
Firma de archivo
Una firma de archivo es una secuencia definida de bytes iniciales que ayuda a un lector a identificar un formato o una versión de archivo.
El marcador de inicio de JPEG ayuda a localizar posibles imágenes antes de comprobar el resto de la estructura.
Flujo
Un flujo es un canal de la biblioteca estándar que conecta un programa con una secuencia de caracteres de entrada o salida.
Un lector puede procesar un archivo en disco o la entrada de un terminal mediante la misma interfaz de flujo.
Flujo de actualización
Un flujo de actualización es un flujo abierto con un modo + que permite tanto la entrada como la salida bajo las reglas de cambio de dirección.
Abrir un archivo existente de registros binarios con "r+b" lo conserva para acceso de lectura y escritura.
fopen
fopen es la función de la biblioteca estándar que abre un archivo indicado en un modo seleccionado y devuelve un puntero a un flujo o NULL.
Una apertura para lectura fallida no deja un flujo válido para una llamada posterior a fgetc o fclose.
fpos_t
fpos_t es el tipo opaco que usan fgetpos y fsetpos para guardar y restaurar toda la información necesaria de posición en el archivo.
Un valor guardado se restaura mediante las funciones de biblioteca, sin realizar operaciones aritméticas sobre él.
fputc
fputc es la función que escribe un carácter en un flujo y devuelve el valor de ese carácter o EOF si falla.
Un filtro que convierte a mayúsculas comprueba cada llamada a fputc después de transformar el carácter leído.
fread
fread transfiere bytes de entrada a la memoria y devuelve el número de elementos completos obtenidos para el tamaño y el número solicitados.
Una lectura corta de un registro debe comprobarse antes de interpretar cualquiera de sus campos.
fseek
fseek solicita una nueva posición en el archivo con respecto al principio, la posición actual o el final, y devuelve un valor distinto de cero si falla.
Un programa comprueba el desplazamiento antes de leer el registro esperado en el desplazamiento solicitado.
ftell
ftell indica la posición de un flujo como un long y devuelve -1L si falla; una posición de texto debe tratarse como una ubicación guardada.
Un lector de registros binarios puede comprobar su posición después de consumir un registro completo de tamaño fijo.
fwrite
fwrite transfiere bytes de objetos desde la memoria a un flujo y devuelve el número de elementos completos escritos.
Escribir un array requiere la dirección de sus datos, el tamaño de elemento y el número de elementos previsto.

I

Indicador de error
El indicador de error registra un fallo de lectura o escritura del flujo y permanece activado hasta que se borra explícitamente.
Después de que fgets devuelva NULL, ferror puede distinguir un fallo de acceso de una finalización normal.
Indicador de fin de archivo
El indicador de fin de archivo registra que una operación de entrada anterior encontró el final del flujo.
Se comprueba después de leer; comprobarlo primero no puede predecir si existe el siguiente byte.

M

Modo binario
El modo binario es un modo de acceso a un flujo que conserva los valores de los bytes sin las transformaciones de caracteres utilizadas para el texto.
Abre una imagen con "rb" para que la transformación de texto no pueda cambiar sus bytes comprimidos.
Modo de adición al final
El modo de adición al final es un acceso que fuerza cada operación de salida al final actual del archivo, independientemente de los desplazamientos anteriores.
Desplazarse al byte cero en un flujo "a+b" puede seleccionar la entrada, pero no puede redirigir la siguiente escritura.
Modo de apertura
Un modo de apertura es una cadena que indica a fopen qué acceso se permite y si el contenido existente se conserva o se borra.
Elegir "a" conserva las entradas anteriores del registro y sitúa cada nueva escritura al final.
Modo texto
El modo texto es un modo de acceso a un flujo para líneas legibles en el que la biblioteca puede transformar caracteres para ajustarse a las convenciones del sistema.
En Windows, la salida en modo texto cambia un salto de línea del programa por la secuencia almacenada CR LF.

N

Número de asignaciones
El número de asignaciones es la cantidad de valores que una llamada de entrada con formato almacena correctamente en sus destinos.
Un registro de dos campos leído con fscanf solo está completo cuando el número de asignaciones devuelto es 2.

O

Orden con el byte más significativo primero
El orden con el byte más significativo primero sitúa ese byte de un valor de varios bytes al principio de la secuencia.
El valor 258 aparece como 00 00 01 02 en un campo de 32 bits con el byte más significativo primero.
Orden con el byte menos significativo primero
El orden con el byte menos significativo primero sitúa ese byte de un valor de varios bytes al principio de la secuencia.
Los cuatro bytes 02 01 00 00 representan 258 en un campo de 32 bits con el byte menos significativo primero.
Orden de los bytes
El orden de los bytes es el orden en que se disponen los bytes de un valor de varios bytes en memoria o en un archivo.
Un formato de archivo especifica su orden de los bytes independientemente de la máquina que lo lea.

P

perror
perror escribe una etiqueta y el mensaje correspondiente al valor actual de errno en la salida de error estándar, seguidos de un salto de línea.
Una etiqueta que indica el archivo hace que un mensaje de diagnóstico sobre un archivo ausente sea más útil que uno sin etiqueta.
Posición en el archivo
La posición en el archivo es la ubicación de un flujo donde comienza la siguiente lectura o escritura, cuando ese flujo admite posicionamiento.
Leer un registro binario de 24 bytes adelanta la posición hasta después de sus 24 bytes.
Propiedad de los recursos
La propiedad de los recursos identifica qué parte de un programa es responsable de liberar un flujo u otro recurso adquirido.
Una función auxiliar cierra un flujo que ha abierto y deja un flujo prestado para su función llamadora.
Puntero a FILE
Un puntero a FILE es un valor de tipo FILE * que da a las funciones de biblioteca acceso a un flujo y a su estado almacenado.
Pasa fp a fgetc después de comprobar que la apertura devolvió un puntero válido a un flujo.
Puntero al final de la conversión
Un puntero al final de la conversión devuelto por strtol señala el primer carácter después del prefijo numérico aceptado por la conversión.
Para "86cm", el puntero llega a la c, lo que permite que un campo de número entero rechace el sufijo.

R

Redirección
La redirección es una operación del intérprete de comandos que conecta los flujos estándar de un programa a archivos sin modificar su código de entrada y salida.
El operador 2> puede guardar los mensajes de diagnóstico de un programa en un archivo separado.
Relleno de una estructura
El relleno de una estructura consiste en bytes adicionales que un compilador puede insertar entre miembros o después del último miembro para lograr la alineación.
Un char seguido de un int puede ocupar ocho bytes aunque sus tamaños sumen cinco.
rename
rename cambia el nombre de un archivo y devuelve 0 si tiene éxito; la gestión de un destino existente depende de la implementación.
Mantén disponible una copia de seguridad si falla la instalación de una sustitución terminada con el nombre original.
Ruta de liberación de recursos
Una ruta de liberación de recursos es el recorrido del flujo de control que libera los recursos adquiridos antes de determinar si hubo éxito o fallo.
Una etiqueta puede cerrar los flujos abiertos después de varios fallos de procesamiento diferentes.

S

Salida de error estándar
La salida de error estándar es el flujo ya abierto stderr que se usa para mensajes de diagnóstico independientemente del flujo de resultados normales de un programa.
Una conversión fallida puede describirse en stderr mientras los datos válidos van a stdout.
Salida estándar
La salida estándar es el flujo ya abierto stdout que se usa para los resultados normales y otras salidas principales de un programa.
Una tubería del intérprete de comandos envía stdout de un convertidor a la entrada estándar de otro programa.
snprintf
snprintf escribe texto con formato en un array de tamaño limitado y devuelve la longitud completa necesaria, sin contar el terminador, o un valor negativo si hay un error.
Un valor de retorno igual a la capacidad ya indica que el texto completo no cupo.
strcspn
strcspn encuentra la longitud inicial de una cadena anterior a cualquier carácter de un conjunto de rechazo indicado, o la longitud completa si no aparece ninguno.
Usar "\r\n" como conjunto de rechazo permite localizar un final sin eliminar datos finales ordinarios.
strerror
strerror devuelve el texto de un mensaje perteneciente a la biblioteca para un código de error proporcionado, lo que permite a un programa construir su propio mensaje de diagnóstico.
Usa un código guardado cuando la liberación de recursos pueda haber sustituido el valor actual de errno.
Sustitución recuperable
Una sustitución recuperable mantiene disponible un archivo existente hasta que se haya instalado correctamente una nueva versión completa.
Si falla el cambio de nombre que instala la nueva versión, conserva la copia de seguridad e informa de su ubicación para restaurarla.

T

Terminador nulo
Un terminador nulo es el carácter de valor cero que marca el final de una cadena de C sin contar como parte de su texto visible.
Un búfer necesita un byte adicional además de los caracteres que fgets puede leer.
Tipo entero de ancho exacto
Un tipo entero de ancho exacto tiene un ancho en bits especificado y exacto cuando está disponible, sin determinar un orden externo de los bytes.
Un campo uint32_t sigue necesitando una codificación explícita de bytes para que un archivo de intercambio sea portable.
Tubería
Una tubería conecta la salida estándar de un programa con la entrada estándar de otro como un flujo de datos.
Un generador puede proporcionar datos directamente a un programa de ordenación sin guardar primero un archivo intermedio.

Sobre esta unidad

Por StudeliInformar de un error

Crea tus propios Materiales de Estudio

Convierte tus notas, diapositivas y documentos en Guías de Estudio, Preguntas de Práctica, Flashcards y 6 herramientas más.

Comenzar