обновить файл произвольного доступа в c - PullRequest
1 голос
/ 07 апреля 2011

Я хочу сделать следующее в C.

У меня есть файл данных произвольного доступа, содержащий несколько записей.

Записи в следующем формате:

Acct#  First Name     Last Name    Balance
0     ""             ""             0.0
0     ""             ""             0.0
0     ""             ""             0.0
05    Joe             Costanza      0.50
 0     ""             ""             0.0
 0     ""             ""             0.0
 0     ""             ""             0.0
19    Jason           Bourne        58.00
0     ""              ""            0.0
0     ""             ""             0.0
42    Andy            Der          -15.12
0     ""             ""             0.0
0     ""             ""             0.0

Я хочу вычесть сумму из баланса из всех записей с ненулевым номером счета и записать новый обновленный баланс в файл для этих записей.

Это то, что я до сих пор пытался выполнить выше.

#include <stdio.h>

struct clientData 
{ 
int acctNum;          
char lastName[15];  
char firstName[10]; 
double balance;       
};

void textFile(FILE *readPtr);

int main(void)
{ 
     FILE *cfPtr;

     struct clientData client = {0, "", "", 0.0};

     double serviceCharge = 5.0;

     cfPtr = fopen("credit.dat", "rb+");

     fread(&client, sizeof(struct clientData), 1, cfPtr);

     client.balance -= serviceCharge;

     fseek(cfPtr,(client.acctNum - 1) * sizeof(struct clientData)
     , SEEK_CUR);

     fwrite(&client, sizeof(struct clientData), 1, cfPtr);

     fclose(cfPtr);

     return 0;
}

Независимо от того, что я пытаюсь, я просто не могу записать в файл ни одной обновленной записи. Я даже пробовал одну запись без цикла while или if, и она все еще не работает. Кто-нибудь может сказать мне, что мне не хватает.

цикл:

fread( &client, sizeof( struct clientData ), 1, cfPtr);

while (!feof(cfPtr))
{ 
if ( client.acctNum != 0 )
{
    client.balance -= serviceCharge;
    fseek(cfPtr, (-1 * sizeof(struct clientData)), SEEK_CUR); 

    fwrite( &client, sizeof( struct clientData ), 1, cfPtr);
}

fread( &client, sizeof( struct clientData ), 1, cfPtr);
}

Ответы [ 3 ]

2 голосов
/ 07 апреля 2011
     while ( !feof( readPtr ) )
     { 
         if ( client.acctNum != 0 )
         {

На данный момент в коде вы не прочитали ничего.Ничего такого.:)

Вы открыли файл, проверили, достигли ли вы конца файла, но пока нет кода для чтения чего-либо из файла, поэтому ваше условие ifпросто проверяет инициализированную структуру в начале.

Цикл ввода обычно работает лучше всего, если вход считывается в top цикла.(Есть исключения, но это не похоже на одно из них.)

Попробуйте это как отправную точку для вашего цикла:

while(fread(&client, sizeof(struct clientData), 1, filePtr)) {
    if (client.acctNum) {
        client.balance -= charge;
        fseek(filePtr, - sizeof(struct clientData), SEEK_CUR);
        if (1 != fwrite(&client, sizeof(struct clientData), 1, filePtr))
            perror("Error writing to file");
    }
}

Обработка ошибок, вероятно, может быть улучшена;возможно, все редактирование должно быть прервано.(При принудительной блокировке записи в файле может произойти сбой , некоторые , а некоторые записи завершатся успешно, но это маловероятно.)

Обновление

Вашfseek() вызов основывается на новой позиции файла, основанной на умножении номера счета на размер struct clientData.Это работает ТОЛЬКО ЕСЛИ ваши записи отсортированы, номера не пропускаются, и начинается с 0 и работает.(Ваш пример входного файла не отсортирован; у вас даже есть запись с 0 номером счета в середине «допустимых» записей.) Вместо этого переключитесь на fseek(..., SEEK_CUR).

0 голосов
/ 07 апреля 2011

Это соответствующая часть кода, отображаемого в данный момент:

 cfPtr = fopen("credit.dat", "rb+");
 fread(&client, sizeof(struct clientData), 1, cfPtr);
 client.balance -= serviceCharge;
 fseek(cfPtr,(client.acctNum - 1) * sizeof(struct clientData), SEEK_CUR);
 fwrite(&client, sizeof(struct clientData), 1, cfPtr);

Я предполагаю, что проверка ошибок возвращаемых значений функции «не нужна»;это должно быть там, но это немного усложнит вещи.Однако я бы не стал доверять себе, чтобы написать программу без проверки ошибок - слишком много вещей может пойти не так, как мне хочется (и горький опыт).

  • Вы читаете запись со смещением 0 вфайл.Затем вы обновляете баланс, ищите позицию на основе номера счета клиента относительно текущей позиции и затем записываете данные обратно.

В другое время мы можем обсудить мудрость двоичного кодаформат данных, который вы используете;на данный момент этого достаточно.

Вот код, который «работает»:

#include <stdio.h>

struct clientData 
{ 
    int acctNum;          
    char lastName[15];  
    char firstName[10]; 
    double balance;       
};

static void print_client(struct clientData *data)
{
    printf("%04d %-15s %-15s %6.2f\n", data->acctNum, data->lastName,
           data->firstName, data->balance);
}

int main(void)
{ 
    FILE *cfPtr;
    struct clientData client = {0, "Me", "Mine", 50.0};
    double serviceCharge = 5.0;

    /* Initialize */
    cfPtr = fopen("credit.dat", "wb");
    fwrite(&client, sizeof(struct clientData), 1, cfPtr);
    fclose(cfPtr);

    /* Update */
    cfPtr = fopen("credit.dat", "rb+");
    fread(&client, sizeof(struct clientData), 1, cfPtr);
    print_client(&client);
    client.balance -= serviceCharge;
    fseek(cfPtr, 0, SEEK_SET);
    fwrite(&client, sizeof(struct clientData), 1, cfPtr);
    fclose(cfPtr);

    /* Validate */
    cfPtr = fopen("credit.dat", "rb");
    fread(&client, sizeof(struct clientData), 1, cfPtr);
    fclose(cfPtr);
    print_client(&client);

    return 0;
}

Это тоже работает ... не пропускает 0 идентификаторов клиентов, потому что негенерируй.Но вы можете справиться с этим.

#include <stdio.h>

struct clientData 
{ 
    int acctNum;          
    char lastName[15];  
    char firstName[10]; 
    double balance;       
};

static void print_client(const struct clientData *data)
{
    printf("%04d %-15s %-15s %6.2f\n", data->acctNum, data->lastName,
           data->firstName, data->balance);
}

/* Initialize file */
static void init_file(const char *filename)
{
    FILE *cfPtr = fopen(filename, "wb");
    int i;
    for (i = 1; i <= 30; i++)
    {
        struct clientData client = { i, "", "", i * 50.0};
        sprintf(client.lastName, "Me (%d)", i);
        sprintf(client.firstName, "Mine (%d)", i);
        fwrite(&client, sizeof(struct clientData), 1, cfPtr);
    }
    fclose(cfPtr);
}

static void print_file(const char *filename)
{
    struct clientData client;
    FILE *cfPtr = fopen(filename, "rb");
    while (fread(&client, sizeof(struct clientData), 1, cfPtr) == 1)
        print_client(&client);
    fclose(cfPtr);
}

int main(void)
{ 
    FILE *cfPtr;
    double serviceCharge = 5.0;
    const char *filename = "credit.dat";
    struct clientData client;

    init_file(filename);
    printf("Post-initialization: %s\n", filename);
    print_file(filename);

    /* Update */
    cfPtr = fopen(filename, "rb+");
    while (fread(&client, sizeof(struct clientData), 1, cfPtr) == 1)
    {
        client.balance -= serviceCharge;
        fseek(cfPtr, -1 * (long)sizeof(struct clientData), SEEK_CUR);
        fwrite(&client, sizeof(struct clientData), 1, cfPtr);
        fseek(cfPtr, 0, SEEK_CUR);
    }
    fclose(cfPtr);

    printf("Post-update: %s\n", filename);
    print_file(filename);

    return 0;
}

Смотрите также комментарии ...

0 голосов
/ 07 апреля 2011

Помимо логических ошибок в вашем коде, на которые указывал @sarnold, вы никогда не fflush() ваш файловый поток или fclose() его.Любые сделанные вами обновления, вероятно, остаются в буфере потока и теряются при завершении вашей программы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...