Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Archivos de Texto

Universidad Nacional de Rio Negro - Sede Andina

Trabajando con archivos (de texto) en C

El manejo de archivos es una capacidad fundamental en la mayoría de las aplicaciones. En C, la librería estándar de E/S (stdio.h) provee un conjunto robusto y de bajo nivel para interactuar con el sistema de archivos. Este apunte amplía el manejo de archivos de texto, cubriendo no solo las operaciones básicas sino también el posicionamiento dentro del archivo y, de manera crucial, una gestión de errores detallada y profesional.

Flujo completo de operaciones con archivos

Figure 1:Diagrama de flujo que muestra la secuencia completa de operaciones al trabajar con archivos: abrir, verificar NULL, realizar operaciones, verificar errores y cerrar.

El FILE, la conexión con el archivo

Toda operación sobre archivos en C se realiza a través de un puntero a una estructura especial y opaca llamada FILE. Esta estructura, definida en la biblioteca estándar <stdio.h>, actúa como un intermediario que contiene toda la información de estado necesaria para gestionar el flujo de datos ( stream ) hacia y desde el archivo.

Concepto del puntero FILE* como intermediario

Figure 2:El puntero FILE* actúa como “manija” o “handle” que conecta tu programa con el archivo físico en disco. La estructura FILE contiene toda la información necesaria para gestionar las operaciones.

Dentro de esta estructura, el sistema operativo y la biblioteca estándar de C manejan los detalles como:

Al ser una estructura opaca, vos no necesitás conocer ni manipular sus miembros internos directamente. En su lugar, interactuás con el archivo a través de funciones que reciben un puntero a esta estructura.

Para declarar un puntero a FILE, la sintaxis es simple:

FILE *puntero_archivo;

Este puntero, una vez que la función fopen() lo inicializa exitosamente, se convierte en tu identificador único para interactuar con ese archivo específico hasta que lo cierres con fclose().

Una Analogía con Arreglos y Punteros

La idea de usar un puntero para manejar una entidad compleja les debe resultar familiar, ya que hemos trabajado con arreglos. El concepto es similar y se relaciona directamente con el manejo de punteros:

Por ahora, es suficiente que entiendas que puntero_archivo es tu “manija” o “handle” para leer, escribir y manipular el archivo que abriste.

Otro detalle importante: los argumentos de tipo cadena suelen declararse con la notación char *modo (puntero a carácter). Aunque a nivel de acceso podamos indexarlos de forma similar a un arreglo, no hay equivalencia de identidad: una declaración como char *modo = "r" crea un puntero a un literal de cadena almacenado en una región de memoria de solo lectura, mientras que char modo[] = "r" define un arreglo mutable en la pila que se inicializa con una copia de dicho texto. Debemos ser conscientes de esto al manipular cadenas para evitar accesos inválidos o intentos de escritura sobre literales.

Apertura de Archivos: fopen()

La función fopen() es el punto de entrada crucial para cualquier operación de archivo. Actúa como un puente entre tu programa y el sistema de archivos del sistema operativo. Su tarea es solicitar el acceso a un archivo específico en un modo determinado.

Si el sistema operativo concede el acceso, fopen() reserva los recursos necesarios, inicializa la estructura FILE con la información pertinente y te devuelve un puntero a dicha estructura. Si por alguna razón la operación falla (el archivo no existe, no tenés permisos, etc.), la función te devolverá NULL.

La sintaxis, definida en <stdio.h>, es la siguiente:

FILE *fopen(const char *pathname, const char *mode);

Program 1:Sintaxis de fopen()

Modos de apertura

Elegir el modo correcto es fundamental, ya que determina el comportamiento del puntero del archivo y lo que sucede con el contenido que ya estaba en el archivo.

Modos de apertura de archivos con fopen()

Figure 3:Guía visual de los diferentes modos de apertura y un diagrama de decisión para elegir el modo correcto según tus necesidades.

Modo

Descripción

Si el archivo no existe

Si el archivo existe

Caso de Uso Típico

"r"

Lectura (Read): Abre un archivo de texto para leer.

Falla (devuelve NULL).

El puntero se posiciona al inicio.

Leer un archivo de configuración, procesar datos de entrada.

"w"

Escritura (Write): Abre un archivo de texto para escribir.

Se crea un archivo nuevo.

El contenido se borra (trunca a cero).

Guardar un nuevo documento, generar un archivo de log desde cero.

"a"

Añadir (Append): Abre un archivo de texto para escribir al final.

Se crea un archivo nuevo.

El puntero se posiciona al final. Los datos existentes se conservan.

Añadir eventos a un archivo de log existente.

"r+"

Lectura y Escritura: Abre para actualizar.

Falla (devuelve NULL).

El puntero se posiciona al inicio. Permite leer y sobreescribir.

Modificar un registro específico en un archivo de datos.

"w+"

Escritura y Lectura: Abre para actualizar, borrando el contenido.

Se crea un archivo nuevo.

El contenido se borra. Permite escribir y luego leer desde el inicio.

Archivos temporales que necesitás escribir y luego releer.

"a+"

Añadir y Lectura: Abre para actualizar, posicionando la escritura al final.

Se crea un archivo nuevo.

El puntero se posiciona al final para escribir, pero podés moverlo para leer.

Leer datos de un log y luego añadir nuevos eventos al final.

Manejo de Errores en la Apertura

Cuando fopen() devuelve NULL, la variable global errno (definida en <errno.h>) se establece con un código de error específico del sistema. Para mostrar un mensaje de error legible por humanos, podés usar la función perror().

#include <stdio.h>
#include <errno.h> // Necesario para perror()

int main() {
    FILE *p_archivo;
    p_archivo = fopen("archivo_inexistente.txt", "r");

    if (p_archivo == NULL) {
        // Imprime un mensaje descriptivo del último error ocurrido
        perror("Error al intentar abrir el archivo");
        return 1; // Termina el programa con un código de error
    }

    printf("Archivo abierto con éxito.\n");
    // ... operaciones con el archivo ...
    fclose(p_archivo);

    return 0;
}

Program 2:Verificación de errores al abrir un archivo

Al ejecutar este código, perror() probablemente imprimiría algo como:

Error al intentar abrir el archivo: No such file or directory`

Binario vs. Texto

Por defecto, los modos listados arriba operan en modo texto. Esto implica que el sistema puede realizar conversiones automáticas de los finales de línea para adaptarse a la convención de la plataforma (por ejemplo, convertir \n a \r\n en Windows).

Para trabajar con archivos binarios —como imágenes, audio, ejecutables o cualquier archivo donde cada byte importa—, es crucial evitar estas traducciones. Para ello, simplemente agregá una b al final del modo (ej. "rb", "wb+", "ab").

Trabajar con archivos binarios es importante, pero complejo y requiere de un par de cosas más que no hemos visto del lenguaje. Para quienes deseen chusmear como se hace, en la sección extra, hay un apunte referido a como trabajar de esta forma los archivos.

Escribiendo

Existen tres funciones para escribir en archivos, que van desde caracteres individuales, cadenas, y terminando en cadenas con formato.

fputc

La función fputc se utiliza para escribir un único carácter en un flujo de archivo (file stream). Es una herramienta fundamental para la manipulación de archivos a bajo nivel en C.

/**
 * Escribe un carácter en un flujo de archivo.
 *
 * @param character a escribir. Se pasa como un `int` pero
 *               se convierte internamente a `unsigned char`.
 * @param stream Puntero al objeto `FILE` que identifica el
 *               flujo donde se escribirá el carácter.
 *
 * @return Si la operación es exitosa, devuelve el mismo
 *               carácter que se escribió (promocionado a `int`).
 *         Si ocurre un error, devuelve la constante `EOF`
 *               y activa el indicador de error del flujo.
 */
int fputc(int character, FILE *stream);

fputs

Escribe una cadena. No añade el carácter de nueva línea (\n) automáticamente. Devuelve un valor no negativo si tiene éxito, o EOF en caso de error.

/**
 * Escribe una cadena de caracteres en un flujo de archivo.
 *
 * @param cadena de caracteres terminada en nulo que se va a escribir.
 * @param stream Puntero al objeto `FILE` que identifica el flujo de salida.
 *
 * @return Devuelve un valor no negativo si la operación es exitosa.
 *         Devuelve la constante `EOF` para indicar un error.
 */
int fputs(const char *cadena, FILE *stream);

fprintf

La opción más versátil. Escribe datos con formato, análogamente a printf(). Devuelve el número de caracteres escritos, o un valor negativo si ocurre un error.

/**
 * @brief Escribe datos con formato en un flujo de archivo.
 *
 * @param stream Puntero al objeto `FILE` que identifica el
 *                   flujo de salida.
 * @param formato Cadena de caracteres que contiene el texto
 *                   a escribir. Puede contener especificadores
 *                   de formato (ej. %d, %f, %s) que serán reemplazados
 *                   por los argumentos subsiguientes.
 * @param ... Lista variable de argumentos. Debe haber un argumento
 *               por cada especificador de formato en la cadena `format`.
 *
 * @return Si la operación es exitosa, devuelve el número total de caracteres escritos.
 *         Si ocurre un error de escritura, devuelve un número negativo.
 */
int fprintf(FILE *stream, const char *formato, ...);

Ejemplo de escritura completo

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

int main(void) {
    // 1. Abrir el archivo en modo escritura ("w").
    FILE *salida = fopen("factura_completa.txt", "w");
    if (salida == NULL) {
        perror("Error al abrir el archivo 'factura_completa.txt'");
        return EXIT_FAILURE;
    }

    // 2. Escribir un encabezado usando fputs()
    // fputs() escribe una cadena de caracteres en el archivo.
    const char *encabezado = "--- Documento de Factura ---\n\n";
    if (fputs(encabezado, salida) == EOF) {
        perror("Error escribiendo el encabezado con fputs()");
        fclose(salida);
        return EXIT_FAILURE;
    }

    // 3. Escribir datos formateados usando fprintf()
    // fprintf() permite escribir datos con formato (como printf, pero a un archivo).
    const char *item_1 = "Placa de Video RTX 4080";
    int cantidad_1 = 1;
    double precio_1 = 1200000.75;
    int chars_escritos_1 = fprintf(salida, "Item: %s\nCantidad: %d\nPrecio: %.2f ARS\n\n", item_1, cantidad_1, precio_1);
    if (chars_escritos_1 < 0) {
        perror("Error al formatear y escribir el item 1 con fprintf()");
        fclose(salida);
        return EXIT_FAILURE;
    }

    // 4. Escribir un separador de línea usando fputc()
    // fputc() escribe un solo carácter en el archivo.
    int i;
    for (i = 0; i < 30; i++) {
        if (fputc('-', salida) == EOF) {
            perror("Error escribiendo separador con fputc()");
            fclose(salida);
            return EXIT_FAILURE;
        }
    }
    if (fputc('\n', salida) == EOF) {
        perror("Error escribiendo nueva linea con fputc()");
        fclose(salida);
        return EXIT_FAILURE;
    }

    // 5. Escribir otro item usando una combinación de las tres funciones.
    const char *item_2 = "Memoria RAM DDR5 32GB";
    int cantidad_2 = 2;
    double precio_2 = 180000.00;

    if (fputs("Detalle del Item 2:\n", salida) == EOF) {
        perror("Error escribiendo detalle del item 2 con fputs()");
        fclose(salida);
        return EXIT_FAILURE;
    }
    if (fprintf(salida, "  Nombre: %s\n", item_2) < 0) {
        perror("Error escribiendo nombre del item 2 con fprintf()");
        fclose(salida);
        return EXIT_FAILURE;
    }
    if (fprintf(salida, "  Unidades: %d\n", cantidad_2) < 0) {
        perror("Error escribiendo unidades del item 2 con fprintf()");
        fclose(salida);
        return EXIT_FAILURE;
    }
    if (fprintf(salida, "  Valor Unitario: %.2f ARS\n", precio_2) < 0) {
        perror("Error escribiendo valor unitario del item 2 con fprintf()");
        fclose(salida);
        return EXIT_FAILURE;
    }

    // 6. Cerrar el archivo. Es crucial para asegurar que todos los datos en el búfer se guarden en el disco.
    if (fclose(salida) != 0) {
        perror("Error al cerrar el archivo");
        return EXIT_FAILURE;
    }

    printf("Archivo 'factura_completa.txt' creado y cerrado exitosamente.\n");
    return EXIT_SUCCESS;
}

Program 3:Ejemplo de escritura y gestión de errores

Leyendo

fgetc

La función fgetc se utiliza para leer un único carácter desde un flujo de archivo. Es la contraparte directa de fputc.

/**
 * @brief Lee un carácter desde un flujo de archivo.
 *
 * @param stream Puntero al objeto `FILE` que identifica el flujo de entrada.
 *
 * @return Si la operación es exitosa, devuelve el carácter leído (promocionado a `int`).
 * @return Si se alcanza el final del archivo o si ocurre un error, devuelve `EOF`.
 */
int fgetc(FILE *stream);

fgets

La función fgets se utiliza para leer una línea o una cadena de caracteres desde un flujo de archivo. Es más segura que la antigua función gets porque permite especificar un tamaño máximo para el búfer, evitando desbordamientos, una práctica recomendada por la regla Regla 0x5006h: Preferí fgets sobre gets y scanf para leer cadenas.

/**
 * @brief Lee una cadena de caracteres desde un flujo de archivo.
 *
 * La lectura se detiene cuando se encuentra un carácter de nueva línea (`\n`),
 * cuando se alcanza el final del archivo (EOF), o después de que se hayan
 * leído (num - 1) caracteres. El carácter de nueva línea, si es leído,
 * se incluye en la cadena. Se añade un carácter nulo (`\0`) al final.
 *
 * @param cadena de caracteres donde se almacenará la cadena leída.
 * @param numero máximo de caracteres a ser leídos (incluyendo el carácter nulo final).
 * @param stream Puntero al objeto `FILE` que identifica el flujo de entrada.
 *
 * @return En caso de éxito, devuelve el puntero `str`.
 *         Si se alcanza el final del archivo antes de leer algún carácter, 
                o si ocurre un error, devuelve `NULL`.
 */
char *fgets(char *cadena, int numero, FILE *stream);

fscanf

La función fscanf se utiliza para leer datos con formato desde un flujo de archivo. Funciona de manera análoga a scanf, pero operando sobre un archivo en lugar de la entrada estándar.

/**
 * @brief Lee datos con formato desde un flujo de archivo.
 *
 * @param[in] stream Puntero al objeto `FILE` que identifica el flujo de entrada.
 * @param[in] format Cadena de caracteres que especifica cómo interpretar los datos leídos.
 * @param[out] ... Lista variable de punteros a las variables donde se almacenarán los datos leídos.
 *
 * @return Devuelve el número de elementos de entrada asignados exitosamente.
 * @return Puede devolver `EOF` si se encuentra el final del archivo o ocurre un error antes de la primera asignación.
 */
int fscanf(FILE *stream, const char *format, ...);

Leyendo un archivo, paso a paso

El código de ejemplo es una demostración de cómo leer un archivo de texto de manera segura y eficiente en C. La estrategia principal es separar la entrada/salida (E/S) del procesamiento de datos. En lugar de intentar interpretar los datos directamente desde el archivo con fscanf(), lee el archivo línea por línea en un espacio de memoria temporal (un búfer) y luego analiza esa línea. Este enfoque es más resiliente a errores de formato.

A continuación, se descompone el código sección por sección.

1. Inclusiones y definiciones (#include y #define)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LINEA 512
#define NOMBRE_ARCHIVO "factura.txt"
2. Apertura del archivo y manejo de errores
FILE *entrada = fopen(NOMBRE_ARCHIVO, "r");
if (!entrada) {
    perror("No se pudo abrir 'factura.txt' para lectura");
    return EXIT_FAILURE;
}
3. Lazo principal de lectura
char buffer[MAX_LINEA];
int numero_linea = 0;

while (fgets(buffer, sizeof(buffer), entrada) != NULL) {
    numero_linea++;
    // ... procesamiento de la línea ...
}
4. Procesamiento y análisis de cada línea (Parsing)
if (strncmp(buffer, "Item:", 5) == 0) {
    char item_nombre[100];
    int cantidad;
    double precio;

    int campos_leidos = sscanf(buffer, "Item: %99[^,], Cantidad: %d, Precio: %lf ARS",
                               item_nombre, &cantidad, &precio);

    if (campos_leidos == 3) {
        // ... éxito ...
    } else {
        // ... fallo ...
    }
}
5. Verificación post-lazo
if (ferror(entrada)) {
    perror("Ocurrió un error de lectura en el archivo");
} else if (feof(entrada)) {
    printf("\nProcesamiento completado. Se llegó al final del archivo.\n");
}
6. Limpieza y cierre
clearerr(entrada);
fclose(entrada);
return EXIT_SUCCESS;

Cierre de Archivos: fclose(), el Paso Final

fclose(FILE *stream) disocia el archivo del puntero FILE. Es una operación crítica que:

  1. Vacía el búfer de salida: Asegura que todos los datos escritos con funciones como fprintf o fputs se escriban físicamente en el disco.

  2. Libera recursos del sistema: El sistema operativo tiene un límite en la cantidad de archivos que un proceso puede tener abiertos simultáneamente.

Devuelve 0 si tiene éxito y EOF si ocurre un error.

Aunque parezca una simple formalidad, la llamada a fclose() también puede fallar. Esto es particularmente cierto al escribir archivos: si el disco se llena o el medio de almacenamiento se desconecta, el vaciado final del búfer (el flush) fallará. Ignorar el valor de retorno de fclose() podría hacerte creer que la operación fue exitosa cuando en realidad los últimos datos se perdieron. La única forma de estar 100% seguro de que toda la información se guardó correctamente es verificar el resultado del cierre.

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

int main(void) {
    FILE *log_file = fopen("app.log", "a");
    if (log_file == NULL) {
        perror("No se pudo abrir el log");
        return EXIT_FAILURE;
    }

    fprintf(log_file, "El programa inició una operación crítica.\n");

    // ... el resto del programa ...

    fprintf(log_file, "La operación crítica finalizó.\n");

    // Cerramos el archivo y VERIFICAMOS el resultado.
    if (fclose(log_file) != 0) {
        // Si fclose falla, el error queda registrado en errno.
        perror("FALLO CRÍTICO al cerrar el archivo de log");
        // En un programa real, esto podría requerir una acción de emergencia,
        // ya que los últimos datos podrían no haberse guardado.
        return EXIT_FAILURE;
    }

    printf("Log escrito y cerrado correctamente.\n");
    return EXIT_SUCCESS;
}

Program 4:Verificación del cierre de un archivo

Funciones y variables para la gestión de errores

stderr: El flujo de error estándar

En C, tenés tres flujos de comunicación estándar:

¿Por qué separar stdout de stderr? Para poder redirigir la salida. Imaginate que ejecutás tu programa y guardás el resultado en un archivo: ./mi_programa > salida.txt

Si usaras printf (que escribe en stdout) para los errores, estos quedarían mezclados con los datos correctos en salida.txt, haciendo difícil su detección. Al usar fprintf(stderr, ...) o perror(), los mensajes de error se imprimen en la consola por separado, permitiéndote ver los problemas incluso cuando la salida “buena” está siendo redirigida.

Uso general: Se utilizá stderr para mensajes de error, diagnósticos o advertencias.

errno: El código del último error

errno es una variable global (técnicamente, una macro que se expande a una expresión modificable) definida en <errno.h>. Las funciones de sistema y de la biblioteca estándar de C la utilizan para comunicar qué salió mal cuando fallan.

Uso general: Consultá errno solo después de haber detectado que una función ha fallado (por ejemplo, verificando un retorno NULL o -1).

perror(const char *s): El informador directo

perror es la forma más sencilla de reportar un error. Hace dos cosas:

  1. Imprime la cadena que le pasaste como argumento.

  2. Inmediatamente después, imprime dos puntos (:) y la descripción textual correspondiente al valor actual de errno.

Situación de uso: Ideal para herramientas de línea de comandos o scripts donde necesitás un mensaje de error rápido, estándar y sin formato complejo. Es menos flexible pero muy conveniente.

// Si errno es 2 ("No such file or directory")
perror("Error al leer el archivo de configuración");
// Salida en stderr:
// Error al leer el archivo de configuración: No such file or directory

strerror(int errnum): El traductor flexible

strerror te da más control. Toma un número de error (casi siempre le pasarás errno) y devuelve un puntero a una cadena de caracteres (char *) con la descripción del error. Vos sos responsable de cómo y dónde imprimir esa cadena.

Situación de uso: Imprescindible cuando necesitás:

// Si errno es 13 ("Permission denied")
fprintf(stderr, "[FATAL] Imposible acceder al recurso. Razón: %s\n", strerror(errno));
// Salida en stderr:
// [FATAL] Imposible acceder al recurso. Razón: Permission denied

Posicionamiento en Archivos: Acceso Aleatorio

No siempre querés leer un archivo secuencialmente. Las funciones de posicionamiento te permiten moverte a cualquier punto del archivo.

ftell

La función ftell se utiliza para obtener la posición actual del indicador de posición del fichero (el “cursor”) dentro de un flujo. Devuelve esta posición como un número de bytes desde el inicio del archivo.

/**
 * @brief Obtiene la posición actual del indicador de posición del fichero.
 *
 * @param[in] stream Puntero al objeto `FILE` que identifica el flujo.
 *
 * @return Si es exitoso, devuelve el valor actual del indicador de posición.
 * @return En caso de error, devuelve -1L y la variable global `errno` se establece a un valor positivo.
 */
long int ftell(FILE *stream);

fseek

La función fseek es la herramienta principal para mover el indicador de posición del fichero a una ubicación específica dentro del flujo. Permite un control preciso, moviendo el cursor un número determinado de bytes (offset) desde un punto de origen (origin).

/**
 * @brief Establece el indicador de posición del fichero a una nueva posición.
 *
 * @param stream Puntero al objeto `FILE` que identifica el flujo.
 * @param offset Desplazamiento en bytes relativo al parámetro `origin`.
 * @param origin Posición desde donde se calcula el desplazamiento. Los valores pueden ser:
 * - `SEEK_SET`: Inicio del archivo.
 * - `SEEK_CUR`: Posición actual.
 * - `SEEK_END`: Final del archivo.
 *
 * @return Devuelve 0 si la operación es exitosa.
 *         Devuelve un valor distinto de cero en caso de error.
 */
int fseek(FILE *stream, long int offset, int origin);

rewind

La función rewind es un caso especial y simplificado de fseek. Su única función es mover el indicador de posición del fichero de vuelta al inicio del archivo. Además, limpia cualquier indicador de error que pudiera tener el flujo.

/**
 * Reposiciona el indicador de posición del fichero al inicio del flujo.
 *
 * Esta función es funcionalmente equivalente a fseek(stream, 0L, SEEK_SET),
 * pero además borra el indicador de error del flujo.
 *
 * @param stream Puntero al objeto `FILE` que identifica el flujo.
 */
void rewind(FILE *stream);

Ejemplo de uso

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

int main(void) {
    FILE *archivo = fopen("factura.txt", "r");
    if (!archivo) {
        perror("No se pudo abrir el archivo");
        return EXIT_FAILURE;
    }

    // Moverse al final del archivo
    if (fseek(archivo, 0, SEEK_END) != 0) {
        perror("Error en fseek a SEEK_END");
        fclose(archivo);
        return EXIT_FAILURE;
    }

    // Obtener la posición actual, que es el tamaño del archivo
    long tamano = ftell(archivo);
    if (tamano == -1L) {
        perror("Error en ftell");
        fclose(archivo);
        return EXIT_FAILURE;
    }
    printf("El archivo tiene %ld bytes.\n", tamano);

    // Moverse a la posición ANTERIOR al último byte para leerlo.
    // Si el archivo termina con \n, esto leerá el carácter previo.
    if (tamano > 1 && fseek(archivo, -2L, SEEK_END) != 0) {
        perror("Error en fseek para leer el último carácter");
        fclose(archivo);
        return EXIT_FAILURE;
    }

    int ultimo_caracter = fgetc(archivo);
    if (ultimo_caracter != EOF) {
        printf("El último carácter imprimible del archivo es: \x27%c\x27\n", (char)ultimo_caracter);
    }

    // Volver al principio
    rewind(archivo);
    printf("Después de \x27rewind\x27, la posición es: %ld\n", ftell(archivo));

    fclose(archivo);
    return EXIT_SUCCESS;
}

Program 5:Uso de fseek() y ftell() para leer el último carácter

Glosario

Búfer

En el contexto de la programación y los sistemas operativos, un búfer (del inglés buffer) es una región de memoria física (generalmente en la RAM) que se utiliza para almacenar datos de forma temporal mientras se transfieren de un lugar a otro.

El objetivo principal de un búfer es optimizar el rendimiento y gestionar las diferencias de velocidad entre dos procesos o dispositivos. Por ejemplo, en las operaciones de entrada/salida (I/O), los datos se acumulan en un búfer antes de ser procesados o escritos en un dispositivo físico como un disco duro. Esto permite que el sistema realice menos operaciones de escritura/lectura, pero de mayor tamaño, lo cual es significativamente más eficiente.

Pensá en el proceso de escribir en un archivo como si fuera enviar una carta. Escribir carácter por carácter directamente al disco (sin búfer) sería como llevar cada letra individualmente hasta el correo. Es ineficiente y lento.

Usar un búfer es como escribir la carta completa en una hoja de papel (el búfer en la memoria). Una vez que terminaste la carta (el búfer se llenó o cerraste el archivo), la llevás al correo en un solo viaje. Este método es mucho más rápido y organizado.

Concepto de búfer en operaciones de archivos

Figure 4:Comparación entre operaciones sin búfer (ineficientes) y con búfer (eficientes), mostrando cómo el búfer optimiza las operaciones de E/S.