【问题标题】:Updating a certain column and line on a CSV file更新 CSV 文件中的特定列和行
【发布时间】:2019-01-12 14:20:35
【问题描述】:

我和我的朋友正在研究一个简单的(事实证明它并不像一开始听起来那么简单)ATM 项目,我们认为该项目适合像我们这样的初学者。这个控制台应用程序可以让用户注册一个帐户,然后登录做其他取款/存款的事情。我们可以成功地将客户信息写入 CSV 文件,然后对其进行解析以进行 ID 和密码检查,并让用户进入以使用其他功能。

我们不知道如何更新某个字符串。假设 ID 为 64 的用户登录并想要取款。然后程序必须找到客户在 CSV 上的行并更新相应的列(例如第 5 列)以减去一些金额。

我们尝试实现fseekfscanf,但没有成功。我们应该研究什么功能?

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

int loginState = 0, line=0; /*Kept the line variable as a global one so I can set the cursor to desired line if needed */

struct Customers customer;
struct Customers{
    int id;
    char fname[20];
    char lname[20];
    int password;
    int cashAmount;
};

void registerAccount(){
    srand(time(NULL));
    customer.id = rand()%99999;

    FILE *cstm = fopen("customers.csv", "a+");

    printf("An ID is set automatically for you.\n");
    printf("Please enter your first name.\n");
    scanf("%s", customer.fname);
    printf("Please enter your last name.\n");
    scanf("%s", customer.lname);
    printf("Please set a password.\n");
    scanf("%d", &customer.password);
    customer.cashAmount = 0;

    fprintf(cstm, "%d,%s,%s,%d,%d\n", customer.id, customer.fname, customer.lname, customer.password, customer.cashAmount);
    fclose(cstm);
}

int parser(int idSearch, int passwordCheck){ /*Takes input from login() function and does an ID and password check*/
    char lineBuffer[255];

    FILE *cstm = fopen("customers.csv", "r");

    while(fgets(lineBuffer,sizeof(lineBuffer),cstm))
    {
        ++line;
        char* id = strtok(lineBuffer, ",");
        if (atoi(id) == idSearch){
            customer.id = atoi(id);

            char* fname = strtok(NULL, ",");
            if (fname != NULL){
                strcpy(customer.fname, fname);
            }

            char* lname = strtok(NULL, ",");
            if (lname != NULL){
                strcpy(customer.lname, lname);
            } 

            char* password=strtok(NULL, ",");
            if (password != NULL){
                if(atoi(password) == passwordCheck){
                    customer.password = atoi(password);
                    loginState = 1;
                }
                else{
                    printf("You have entered the wrong password.\n");
                }
            }       

            char* cashAmount=strtok(NULL, "\n");
            if (cashAmount != NULL){
                customer.cashAmount = atoi(cashAmount);
            }
            fclose(cstm);
            return 1;
        }
    }
    printf("Could not find the ID.\n");
    fclose(cstm);
}

int login(){
    int passwordCheck, idSearch;

    printf("Please put your ID in.\n");
    scanf("%d", &idSearch);
    printf("Please put your password.\n");
    scanf("%d", &passwordCheck);

    if(parser(idSearch, passwordCheck) == 1){
        return 1;
    }
}

void balanceOperations(int option){
    int amount;
    FILE *cstm = fopen("customers.csv", "a+");

    if(option == 1){
        printf("\nYour current balance is: %d dollars.\n", customer.cashAmount);
        printf("How much would you like to deposit?\n");
        scanf("%d", &amount);
        customer.cashAmount = customer.cashAmount + amount;
        /* update function comes here */
        printf("Your new balance is %d dollars.\n", customer.cashAmount);
    }

    else if(option == 2){
        printf("\nYour current balance is: %d dollars.\n", customer.cashAmount);
        printf("How much would you like to withdraw?\n");
        scanf("%d", &amount);
        customer.cashAmount = customer.cashAmount - amount;
        printf("Your new balance is %d dollars.\n", customer.cashAmount);
    }

    else{
        printf("Something went wrong. Terminating in 5 seconds...\n");
        sleep(5);
        exit(0);
    }
}

void transaction(){

}

void loginChoices(){
    int answer;

    printf("Please select an operation.");

    while(1){
    printf("\n1. Deposit\n2. Withdraw\n3. Transaction\n");
    scanf("%d", &answer);
    switch(answer){
        case 1:
            balanceOperations(answer);
            break;
        case 2:
            balanceOperations(answer);
            break;
        case 3:
            transaction(answer);
            break;
        default:
            printf("\nInvalid request. Please enter a valid option.\n");
    }
}
}

int main(){

    int answer;

    printf("\nWelcome.\nPlease enter the digit of corresponding operation.\n");
    printf("1. Login.\n2. Register.\n");
    scanf("%d",&answer);

    if(answer == 1){
        if(login() == 1 && loginState == 1){
            printf("\nYou have logged in successfully.\n");
            printf("Your current balance is: %d dollars.\n\n", customer.cashAmount);
            loginChoices();
        }
    }

    else if(answer == 2){
        registerAccount();
    }

    else{
        printf("Please enter a valid number.\n");
        exit(0);
    }
}

【问题讨论】:

  • 如果更新改变了数据的长度,你就有问题了。如果您将固定大小的记录写入文件,这不是问题,但使用printf() 是。要使用不同大小的条目更新文件,到目前为止,最简单(通常也是最有效)的技术是制作文件副本,并在适当时编辑条目(或条目)。老式大型机批处理将这一点发挥到了极致,但即便如此,通常也使用固定大小的记录。

标签: c


【解决方案1】:

我会说你通过维护当前客户的全局变量和文件中当前客户的行号来设计你的程序很糟糕。


反正对你​​当前的代码没有太多的编辑,你可以做如下。

在代码 cmets 中找到我的解释。

void balanceOperations(int option){
    int amount;
    FILE *cstm = fopen("customers.csv", "r+"); //Open file for update, not a+

    FILE *tempFile = fopen("temp.csv", "w+");

    char lineBuffer[255];
    int temp = line-1;  //Your global variable which maintains the line number


    /*Loop till you get the current customer from the file*/
    while(fgets(lineBuffer,sizeof(lineBuffer),cstm))
    {
            if(option == 1){

                if (!temp)
                {
                   printf("\nYour current balance is: %d dollars.\n", customer.cashAmount);
                   printf("How much would you like to deposit?\n");
                   scanf("%d", &amount);

                   customer.cashAmount = customer.cashAmount + amount;

                   /*Overwrite the correct amount*/
                   fprintf(tempFile, "%d,%s,%s,%d,%d\n", customer.id, customer.fname, customer.lname, customer.password, customer.cashAmount);
                   printf("Your new balance is %d dollars.\n", customer.cashAmount);


                }
                else
                {
                     fputs(lineBuffer, tempFile);
                }
            }
            else if(option == 2){
                printf("\nYour current balance is: %d dollars.\n", customer.cashAmount);
                printf("How much would you like to withdraw?\n");
                scanf("%d", &amount);
                if (!temp)
                {
                   customer.cashAmount = customer.cashAmount - amount;

                   /*Overwrite the correct amount*/
                   fprintf(tempFile, "%d,%s,%s,%d,%d\n", customer.id, customer.fname, customer.lname, customer.password, customer.cashAmount);
                   printf("Your new balance is %d dollars.\n", customer.cashAmount);
                }
                else
                {
                     fputs(lineBuffer, tempFile);
                }
            }
            else{
                printf("Invalid operation. Terminating in 5 seconds...\n");
                exit(5);
            }
            temp--;
      }
      fclose(cstm);
      fclose(tempFile);
      remove("customers.csv");
      rename ("temp.csv","customers.csv");
 }

【讨论】:

  • 是的,但它确实添加了一个新行,但这并不能真正解决问题。我正在尝试更新该行,而不是在保留旧行的同时添加新行。
  • @ÖzençB。不,它不添加新行我已经尝试过了。
  • 对不起,我忘记将“a+”模式更新为“r”。它现在可以工作,但仅适用于 csv 文件的第一行。它不会对其余部分做任何事情。
  • @ÖzençB。它适用于所有行,只需替换完整的代码并尝试。
  • 我有,不幸的是它不会更新其他客户。我在这里上传当前版本:code
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-08
  • 2014-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多