如何将二进制文件中的最后一个结构标记为二进制文件中的“已删除”,C

问题描述 投票:0回答:1

我需要删除文件 file.dat 中写入的最后一个结构,并用单词

deleted
对其进行标记。 这是代码:

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

struct s_cliente {
    int codice;
    char nome[10];
    char merce[10];
    float prezzo;
};

typedef struct s_cliente cliente;

cliente inserisciCliente(cliente c1);
void inserisciOrdine();
void stampaFile();
float calcolaPrezzo(char nome[10]);
void eliminaLast();

int main() {

    char nome[10];
    float prezzotot = 0;
    int opz = 0;
    
    do {
        printf("\nInserisci un'opzione: \n1)Inserisci un cliente\n2)Stampa i clienti all'interno del file\n3)Ricerca un cliente e calcola l'importo dovuto\n");
        scanf("%d", &opz);
        switch (opz) {
          case 1:
            inserisciOrdine();
            break;
          case 2:
            stampaFile();
            break;
          case 3:
            getchar();
            scanf("%s", nome);
            prezzotot = calcolaPrezzo(nome);
            if (prezzotot != 0) {
                printf("\nImporto dovuto dal cliente %s: %2.f euro", nome, prezzotot);
            } else {
                printf("\nCliente non trovato");
            }
            break;
          default:
            printf("\nOpzione non valida");
            break;
        }
    } while (opz != 5);    
    return 0;
}

cliente inserisciCliente(cliente c1) {
    printf("\nInserisci il codice: ");
    scanf("%d", &c1.codice);
    getchar();
    printf("Inserisci il nome: ");
    scanf("%s", c1.nome);
    getchar();
    printf("Inserisci la merce: ");
    scanf("%s", c1.merce);
    printf("Inserisci prezzo: ");
    scanf("%f", &c1.prezzo);

    return c1;
}

void inserisciOrdine() {
    FILE *foutput = fopen("file.dat", "ab");
    cliente c1;
    c1 = inserisciCliente(c1);
    fwrite(&c1, sizeof(c1), 1, foutput);
    fclose(foutput);
}

void stampaFile() {
    FILE *file_lettura = fopen("file.dat", "rb");
    if (file_lettura != NULL) {
        cliente c1;
        while (fread(&c1, sizeof(cliente), 1, file_lettura) == 1) {
            printf("Codice: %d, Nome: %s, Merce: %s, Prezzo: %.2f\n", c1.codice, c1.nome, c1.merce, c1.prezzo);
        }
        fclose(file_lettura);
    } else {
        printf("Errore nell'apertura del file per la lettura.\n");
    }
}

float calcolaPrezzo(char nome[10]) {
    float prezzotot = 0;
    FILE *file_lettura = fopen("file.dat", "rb");
    cliente c1;
    if (file_lettura != NULL) {
        while (fread(&c1, sizeof(cliente), 1, file_lettura) == 1) {
            if (strcmp(nome, c1.nome) == 0) {
                prezzotot += c1.prezzo;
            }
        }
        fclose(file_lettura);
    } else {
        printf("\nErrore nella lettura");
    }

    return prezzotot;
}

我知道我可以使用该函数

fseek();
,我只是不太明白如何将结构标记为已删除。

c binaryfiles fseek
1个回答
0
投票

谷歌翻译告诉我,

int codice;
在英语中的意思是“代码”,所以你可以使用该字段来编码你的标志。这意味着您的问题是错误的,因为您表示您想使用“删除”一词。如果你走这条路,那么你必须审核你的代码并处理这个标志。您可能不想打印它,如果您想删除第二条记录,您可能想跳过它。

我建议您通过截断文件来删除记录。我还通过读取没有最大字段宽度的

scanf()
字符串来修复潜在的缓冲区溢出,引入符号常量,将文件操作(重新打开除外)移至
main()
,使用缺少的提示更新菜单并使示例运行更容易运行我只在开始时打印一次菜单:

#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define LEN 9
#define DAT "file.dat"
#define str(s) str2(s)
#define str2(s) #s

typedef struct {
    int codice;
    char nome[LEN+1];
    char merce[LEN+1];
    float prezzo;
} cliente;

cliente inserisciCliente() {
    cliente c1;
    printf("\nInserisci il codice: ");
    scanf("%d", &c1.codice);
    getchar();
    printf("Inserisci il nome: ");
    scanf("%" str(LEN) "s", c1.nome);
    getchar();
    printf("Inserisci la merce: ");
    scanf("%" str(LEN) "s", c1.merce);
    printf("Inserisci prezzo: ");
    scanf("%f", &c1.prezzo);
    return c1;
}

void inserisciOrdine(FILE *lettura) {
    fseek(lettura, 0, SEEK_END);
    cliente c1 = inserisciCliente();
    fwrite(&c1, sizeof(c1), 1, lettura);
}

void stampaFile(FILE *lettura) {
    fseek(lettura, 0, SEEK_SET);
    cliente c1;
    while (fread(&c1, sizeof(cliente), 1, lettura) == 1) {
        printf("Codice: %d, Nome: %s, Merce: %s, Prezzo: %.2f\n", c1.codice, c1.nome, c1.merce, c1.prezzo);
    }
}

float calcolaPrezzo(FILE *lettura, char nome[10]) {
    fseek(lettura, 0, SEEK_SET);
    float prezzotot = 0;
    cliente c1;
    while (fread(&c1, sizeof(cliente), 1, lettura) == 1) {
        if (strcmp(nome, c1.nome) == 0) {
            prezzotot += c1.prezzo;
        }
    }
    return prezzotot;
}

void delete(FILE **lettura) {
    if(fseek(*lettura, 0, SEEK_END)) {
        perror("");
        return;
    }
    long end = ftell(*lettura);
    if(!end) return; // empty
    if(ftruncate(fileno(*lettura), end - sizeof(cliente))) {
        perror("");
        return;
    }
    *lettura = freopen(NULL, "a+r", *lettura);
    if(!*lettura) {
        perror("");
        return;
    }
}

int main() {
    FILE *lettura = fopen(DAT, "a+b");
    if(!lettura) {
        perror("Errore nell'apertura del file per la lettura.\n");
        return 1;
    }
    printf(
        "\n"
        "Inserisci un'opzione:\n"
        "1)Inserisci un cliente\n"
        "2)Stampa i clienti all'interno del file\n"
        "3)Ricerca un cliente e calcola l'importo dovuto\n"
        "4)Delete\n"
        "5)Exit\n"
    );
    for(;;) {
        printf("> ");
        enum { INSERT=1, SHOW, CALC, DELETE, EXIT=5 } opz;
        int rv = scanf("%d", &opz);
        if(rv == EOF)
            break;
        if(rv != 1)
            continue;
        switch (opz) {
            case INSERT:
                inserisciOrdine(lettura);
                break;
            case SHOW:
                stampaFile(lettura);
                break;
            case CALC: {
                       char nome[LEN+1];
                       float prezzotot = 0;
                       getchar();
                       scanf("%" str(LEN) "s", nome);
                       prezzotot = calcolaPrezzo(lettura, nome);
                       if (prezzotot)
                           printf("\nCliente non trovato");
                       else
                           printf("\nImporto dovuto dal cliente %s: %2.f euro", nome, prezzotot);
                       break;
                   }
            case DELETE:
                   delete(&lettura);
                   break;
            case EXIT:
                   goto done;
            default:
                   printf("\nOpzione non valida");
                   break;
        }
    }
done:
    fclose(lettura);
    return 0;
}
Inserisci un'opzione:
1)Inserisci un cliente
2)Stampa i clienti all'interno del file
3)Ricerca un cliente e calcola l'importo dovuto
4)Delete
5)Exit
> 1

Inserisci il codice: 1
Inserisci il nome: 2
Inserisci la merce: 3
Inserisci prezzo: 4
> 1

Inserisci il codice: 2
Inserisci il nome: 3
Inserisci la merce: 4
Inserisci prezzo: 5
> 2
Codice: 1, Nome: 2, Merce: 3, Prezzo: 4.00
Codice: 2, Nome: 3, Merce: 4, Prezzo: 5.00
> 4
> 2
Codice: 1, Nome: 2, Merce: 3, Prezzo: 4.00
> 5
© www.soinside.com 2019 - 2024. All rights reserved.