Manejo de Archivos Binarios en C: Lectura, Escritura, Edición y Ordenamiento de Registros

Informática10,66 KB

Manejo de archivos binarios en C

A continuación se presentan funciones para cargar, imprimir, editar y convertir archivos binarios que almacenan registros de tipo Persona, Cartelera y Reserva, además de funciones para el merge de archivos, la generación de índices y el ordenamiento de vectores.

Carga e impresión de archivos binarios

La función cargarArchivoBin escribe un vector de personas en un archivo, mientras que imprimirArchivoBin lee el archivo y muestra cada registro en pantalla.

void cargarArchivoBin (char *ruta)
{
    Persona p [5] = {{123,"facu",21},{456,"belu",20},{789,"luli",25},{123,"facu",21},{654,"nacho",34}};
    FILE *f = fopen (ruta,"wb");
    if(f == NULL)
    {
        puts("No se pudo abrir el archivo\n");
        return;
    }
    fwrite(p, sizeof(p),1,f);
    fclose(f);
}

void imprimirArchivoBin (char *ruta)
{
    Persona p;
    FILE *f = fopen (ruta,"rb");
    if(f == NULL)
    {
        puts("No se pudo abrir el archivo\n");
        return;
    }
    fread(&p, sizeof (Persona),1,f);
    while (!feof(f))
    {
        printf("%d %s %d\n", p.dni, p.nya, p.edad);
        fread(&p, sizeof (Persona),1,f);
    }
    fclose(f);
}

Edición de registros en un archivo binario

La función editarArchivoBin abre el archivo en modo r+b, busca la primera persona con edad menor a 30 y actualiza su edad a 28.

void editarArchivoBin (char *ruta)
{
    Persona p;
    FILE *f = fopen (ruta,"r+b");
    if(f == NULL)
    {
        puts("No se pudo abrir el archivo\n");
        return;
    }
    fread(&p, sizeof (Persona),1,f);
    while(!feof(f))
    {
        if (p.edad < 30)
        {
            p.edad = 28;
            fseek(f, -sizeof(Persona), SEEK_CUR);
            fwrite(&p, sizeof(Persona),1,f);
            break;
        }
        fread(&p, sizeof (Persona),1,f);
    }
    fclose(f);
}

Conversión entre texto y binario

Las funciones binAText y TextABin permiten convertir un archivo binario de personas a texto plano separado por comas, y viceversa.

void binAText (FILE *fb, FILE *ft)
{
    Persona p;
    fread(&p,sizeof(Persona),1,fb);
    while (!feof(fb))
    {
        fprintf(ft,"%d,%s,%d\n", p.dni, p.nya, p.edad);
        fread(&p,sizeof(Persona),1,fb);
    }
}

void TextABin (FILE *ft, FILE *fb)
{
    char registro[REG];
    Persona p;
    while (fgets(registro,REG,ft))
    {
        cargarStruct (registro,&p);
        fwrite(&p,sizeof(Persona),1,fb);
    }
}

void cargarStruct (const char *registro, Persona *p)
{
    sscanf(registro,"%d,%s,%d", &p->dni, p->nya, &p->edad);
}

Merge de archivos de productos y movimientos

La función mergeProd combina un archivo maestro de productos con un archivo de movimientos, actualizando el stock. Los productos nuevos se incorporan y el archivo temporal reemplaza al original.

int mergeProd (const char *nombreArchProd, const char *nombreArchMov)
{
    FILE *archProd = fopen(nombreArchProd,"rb");
    if(archProd==NULL)
    {
        printf("Error al abrir el archivo %s\n", nombreArchProd);
        return ERR_ARCH;
    }

    FILE *archMov = fopen(nombreArchMov,"rb");
    if(archMov==NULL)
    {
        printf("Error al abrir el archivo %s\n", nombreArchMov);
        fclose(archProd);
        return ERR_ARCH;
    }

    FILE *archProdTemp = fopen("ProductosTemp","wb");
    if(archProdTemp==NULL)
    {
        printf("Error al abrir el archivo %s\n", "ProductosTemp");
        fclose(archProd);
        fclose(archMov);
        return ERR_ARCH;
    }

    Producto prod, prodNue;
    Movimiento mov;
    int comp;

    fread(&prod,sizeof(Producto),1,archProd);
    fread(&mov,sizeof(Movimiento),1,archMov);

    while(!feof(archProd) && !feof(archMov))
    {
        comp = strcmp(prod.cod,mov.cod);

        if(comp == 0)
        {
            prod.stock += mov.cant;
            fread(&mov,sizeof(Movimiento),1,archMov);
        }

        if(comp < 0)
        {
            fwrite(&prod,sizeof(Producto),1,archProdTemp);
            fread(&prod,sizeof(Producto),1,archProd);
        }

        if(comp > 0)
        {
            strcpy(prodNue.desc,"    ");
            strcpy(prodNue.cod, mov.cod);
            prodNue.stock = mov.cant;

            fread(&mov,sizeof(Movimiento),1,archMov);
            while(!feof(archMov) && (strcmp(prodNue.cod,mov.cod) == 0))
            {
                prodNue.stock += mov.cant;
                fread(&mov,sizeof(Movimiento),1,archMov);
            }
            fwrite(&prodNue,sizeof(Producto),1,archProdTemp);
        }
    }
    while(!feof(archProd))
    {
        fwrite(&prod,sizeof(Producto),1,archProdTemp);
        fread(&prod,sizeof(Producto),1,archProd);
    }

    while(!feof(archMov))
    {
        strcpy(prodNue.desc,"    ");
        strcpy(prodNue.cod, mov.cod);
        prodNue.stock = mov.cant;

        fread(&mov,sizeof(Movimiento),1,archMov);
        while(!feof(archMov) && (strcmp(prodNue.cod,mov.cod) == 0))
        {
            prodNue.stock += mov.cant;
            fread(&mov,sizeof(Movimiento),1,archMov);
        }
        fwrite(&prodNue,sizeof(Producto),1,archProdTemp);
    }

    fclose(archProd);
    fclose(archMov);
    fclose(archProdTemp);
    remove(nombreArchMov);
    rename("ProductosTemp",nombreArchProd);
    return OK;
}

Eliminación de duplicados en vectores ordenados

La función elimDupliArchOrd recorre un vector ordenado y copia en un auxiliar únicamente los elementos distintos del anterior.

void elimDupliArchOrd (Persona *p, Cmp cmp, int ce)
{
    Persona aux[ce];
    aux[0] = p[0];
    int j = 0;
    for (int i = 1; i < ce; i++)
    {
        if (cmp(&p[i], &p[i-1]) != 0)
        {
            j++;
            aux[j] = p[i];
        }
    }
}

Generación de índice de empleados

La función generarIndiceEmpleados crea un archivo índice que asocia el legajo de cada empleado con su número de registro dentro del archivo original.

int generarIndiceEmpleados(const char* nomArchEmpl, const char* nomArchIdx)
{
    EmpleadoIdx emplIdx;

    FILE* arch = fopen(nomArchEmpl, "rb");
    if(!arch)
        return ERR_ARCH;

    FILE* archIdx = fopen(nomArchIdx, "wb");
    if(!archIdx)
    {
        fclose(arch);
        return ERR_ARCH;
    }

    Empleado empl;
    long nroReg = 0;

    fread(&empl, sizeof(Empleado), 1, arch);

    while(!feof(arch))
    {
        emplIdx.legajo = empl.legajo;
        emplIdx.nroReg = nroReg++;
        fwrite(&emplIdx, sizeof(emplIdx), 1, archIdx);
        fread(&empl, sizeof(Empleado), 1, arch);
    }

    putchar('\n');

    fclose(arch);
    fclose(archIdx);

    return TODO_OK;
}

Carga de archivo a vector y ordenamiento genérico

La función ArchAVec lee el archivo de personas en un vector, mientras que vectorOrdenarInser ordena cualquier vector mediante inserción usando una función de comparación y intercambiarGen para intercambiar elementos de tamaño arbitrario.

int ArchAVec (const char *nombreArchPersonas)
{
    FILE *archPer = fopen (nombreArchPersonas,"r+b");
    if(archPer==NULL)
    {
        puts("No se pudo abrir el archivo");
        return ERR_ARCH;
    }
    fseek(archPer,0,SEEK_END);
    int ce = ftell(archPer)/sizeof(Persona);
    fseek(archPer,0,SEEK_SET);

    Persona p[ce];

    for(int i = 0; i < ce; i++)
    {
        fread(&p[i],sizeof(Persona),1,archPer);
    }
    fclose(archPer);
    return ce;
}

void vectorOrdenarInser(void *p, int ce, int tamElem, Cmp cmp)
{
    int i, j;
    for(i = 1; i < ce; i++)
    {
        j = i;
        while(j > 0 && cmp((char*)p + (j - 1) * tamElem, (char*)p + j * tamElem) > 0)
        {
            intercambiarGen((char*)p + j * tamElem, (char*)p + (j - 1) * tamElem, tamElem);
            j--;
        }
    }
}

int compPers(const void *a, const void *b)
{
    const Persona *auxA = (const Persona*)a;
    const Persona *auxB = (const Persona*)b;
    return auxA->dni - auxB->dni;
}

void intercambiarGen (void *elem1, void *elem2, size_t tamElem)
{
    char *aux = malloc(tamElem);
    memcpy(aux, elem1, tamElem);
    memcpy(elem1, elem2, tamElem);
    memcpy(elem2, aux, tamElem);
    free(aux);
}

Escritura de vector en archivo

La función cargarVecAArch escribe un vector completo de personas en un archivo binario. Nota: sizeof(p) sobre un puntero devuelve el tamaño del puntero, por lo que se recomienda escribir n * sizeof(Persona) elementos.

void cargarVecAArch (const Persona *p, int ce, char *ruta)
{
    FILE *f = fopen (ruta,"wb");
    if(f == NULL)
    {
        puts("No se pudo abrir el archivo\n");
        return;
    }
    fwrite(p, sizeof(Persona), ce, f);
    fclose(f);
}

Manejo de cartelera de cine

Las siguientes funciones permiten cargar, imprimir y ordenar registros de Cartelera y Reserva, así como convertir datos de texto a binario.

void cargarArchivoBin (FILE *fb)
{
    Cartelera carte [5] = {{421,"endgame",10,0,150},{205,"matrix",15,0,120},{930,"spiderman",12,30,100},{271,"ts4",17,30,180},{194,"interstellar",20,0,200}};
    fwrite(carte, sizeof(carte),1,fb);
}

void imprimirArchivoBin (FILE *fb)
{
    Cartelera carte;
    fread(&carte, sizeof (Cartelera),1,fb);
    while (!feof(fb))
    {
        printf("%d %s %d:%d %d\n", carte.id, carte.nom, carte.hora, carte.min, carte.asientos);
        fread(&carte, sizeof (Cartelera),1,fb);
    }
}

void imprimirArchivoBin2 (FILE *fb)
{
    Reserva carte;
    fread(&carte, sizeof (Reserva),1,fb);
    while (!feof(fb))
    {
        printf("%d %d\n", carte.id, carte.asientos);
        fread(&carte, sizeof (Reserva),1,fb);
    }
}

int compararCarteleraPorId (const void *a, const void *b)
{
    const Cartelera *auxA = (const Cartelera*)a;
    const Cartelera *auxB = (const Cartelera*)b;
    return auxA->id - auxB->id;
}

void TextABin (FILE *ft, FILE *fb)
{
    char registro[REG];
    Cartelera carte;
    while (fgets(registro,REG,ft))
    {
        cargarStruct (registro,&carte);
        fwrite(&carte,sizeof(Cartelera),1,fb);
    }
    puts("Mostrar txt a bin\n");
}

void cargarStruct (const char *registro, Cartelera *carte)
{
    sscanf(registro,"%3d%3d", &carte->id, &carte->asientos);
}

Descargar

PDF Word HTML