【问题标题】:Reading values from a file in c从c中的文件中读取值
【发布时间】:2021-11-14 00:32:24
【问题描述】:

我有两个文件要读取。其中之一包含两列,例如:

Account Number      Amount
100                 27.14
300                 62.11
400                 100.56
900                 82.17

另一个文件有5列,内容如下:

Account Number      Name           Surname        Balance        
100                 Alan           Jones          348.17
300                 Mary           Smith          27.19
500                 Sam            Sharp          0.00
700                 Suzy           Green          -14.22

我想比较两个文件的账号,把第一个文件的余额加上第二个文件的余额。到目前为止,我尝试从第一个文件中获取帐号并将其打印在屏幕上。我尝试使用fread 函数,但它不起作用。

我的尝试是:

struct clientData{
    unsigned int acctNum;
    char name[20];
    char surname[20];
    double balance;
};
int main(){

FILE *fPtr, *fPtr2;
    
    if(!(fPtr = fopen("transaction_file.txt", "r"))){
        printf("[ERROR] File could not be found!\n");
        return;
    }
    fseek(fPtr, (0) * sizeof(struct clientData), SEEK_SET);
    
    struct clientData client = {0, "", "", 0.0};
    
    //read record from file
    fread(&client, sizeof(struct clientData), 1, fPtr);
    printf("%-6u%10.2lf\n\n", client.acctNum, client.balance);
}

【问题讨论】:

  • 信息可能以纯文本形式存储,因此您不能将fread 直接发送到client,您必须先解析输入。
  • 那些“5 列”在我看来很像 4 列。
  • 它们是文本文件,因此使用fgets() 读取每一行然后提取信息,可能使用sscanf()strtok() 等等。
  • 要“将第一个文件的余额添加到第二个文件的余额”,您需要创建一个包含所有数据和修改后余额的新文件。
  • 我不确定它是否真的有效:fread(&client, sizeof(struct clientData), 1, fPtr); -> 你怎么知道 fread 将数据准确地放入 clientData 结构的字段中?你用gdb检查了吗?在我看来,您应该首先解析数据,或者至少知道文件中的余额数据放在哪个offest数据上。然后你可以将行读入缓冲区并将余额从固定位置复制到其他缓冲区,甚至转换(atoi,scanf)等

标签: c file fread


【解决方案1】:

类似于@William Pursell,但具有更强的解析测试。

// if (2 == sscanf(line, "%d %f", &n.number, &n.balance) ||
//     4 == sscanf(line, "%d %31s %31s %f", &n.number, n.name, n.surname, &n.balance)

int end = 0;
sscanf(line, "%d %f %n", &n.number, &n.balance, &end);
if (end > 0 && line[end] == 0) {
  ; // Handle file 1 type line
} else {
  end = 0;
  sscanf(line, "%d %31s %31s %f %n", &n.number, n.name, n.surname, &n.balance, &end);
  if (end > 0 && line[end] == 0) {
    ; // Handle file 2 type line
  }
}

【讨论】:

  • 语句`sscanf(line, "%d %31s %31s %f %n", &n.number, n.name, n.surname, &n.balance, &end);`能否处理表头?我刚刚找到了另一个解决方案,但它不能通过标题? %n 是做什么的?
  • @akoluacik 1) 当 table header 行被解析时你想发生什么。我希望您希望该行既不是文件 1 也不是文件 2 行。这就是上面代码的作用。 2)“找到了另一个解决方案,但它不能通过标题?” --> 不清楚 other 解决方案是什么,因此不再对此发表评论。 "%n" 指示 sscanf() 保存扫描的当前字符偏移量。有关这方面的更多详细信息,请参阅您的库文档。
【解决方案2】:

您需要解析输入。尽管它完全不适合生产工作(即使不是不可能,也很难稳健地避免意外输入上的未定义行为),但使用scanf 是一种简单的方法。 您将希望使用一种使查找变得容易的数据结构。最简单的(IMO)实现是不平衡树。比如:

#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void * xmalloc(size_t s);
FILE * xfopen(const char *path, const char *mode);
int die(const char *fmt, ... );

struct account {
    int number;
    float balance;
    char name[32];
    char surname[32];
    struct account *next[2];
};

void
insert(struct account **root, const struct account *n)
{
    struct account *r = *root;

    if( r == NULL ){
        r = *root = xmalloc(sizeof **root);
        memcpy(r, n, sizeof *n);
    } else if( n->number == r->number ){
        r->balance += n->balance;
        if( *r->name == '\0' ){
            strcpy(r->name, n->name);
            strcpy(r->surname, n->surname);
        }
    } else {
        insert(r->next + (n->number > r->number), n);
    }
}

const char *hdr[2] = {
    "Account Number      Amount\n",
    "Account Number      Name           Surname        Balance\n"
};
void
read_file(struct account **root, FILE *ifp)
{
    size_t cap = 0;
    char *line = NULL;
    struct account n = {0};
    while( getline(&line, &cap, ifp) > 1 ){
        if( 2 == sscanf(line, "%d %f", &n.number, &n.balance) \
        || 4 == sscanf(line, "%d %31s %31s %f",
            &n.number, n.name, n.surname, &n.balance)
        ) {
            insert(root, &n);
        } else if( strcmp(line, hdr[0]) && strcmp(line, hdr[1]) ) {
            die("invalid input: %s\n", line);
        }
    }
    free(line);
}

void
print(struct account *r)
{
    if( r ){
        print(r->next[0]);
        printf("%d %-31s %-31s %.2f\n",
            r->number, r->name, r->surname, r->balance
        );
        print(r->next[1]);
    }
}

int
main(int argc, char **argv)
{
    struct account *root = NULL;
    if( argc > 1 ){
        FILE *fp;
        for(char *const* path = argv + 1; *path; path += 1 ){
            read_file(&root, fp = xfopen(*path, "r"));
            if( fclose(fp) ){
                perror(*path);
            }
        }
    } else {
        read_file(&root, stdin);
    }
    print(root);
}

FILE *
xfopen(const char *path, const char *mode)
{
    FILE *fp = path[0] != '-' || path[1] != '\0' ? fopen(path, mode) :
        *mode == 'r' ? stdin : stdout;
    if( fp == NULL ){
        perror(path);
        exit(EXIT_FAILURE);
    }
    return fp;
}

void *
xmalloc(size_t s)
{
    void *rv = malloc(s);
    if( rv == NULL ){
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    return rv;
}

int
die(const char *fmt, ... )
{
    va_list ap;
    va_start(ap, fmt);
    vfprintf(stderr, fmt, ap);
    va_end(ap);
    exit(EXIT_FAILURE);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-03
    • 2015-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多