[英]C Binary File not updating/reading
下面提供了我的代碼。 我要根據提供的帳號“存入”錢。 名稱,帳號和余額都在以下“ accounts.dat”文件中。
Herman T Travis 3 $500
Sam L Travis 1 $40
Henry O Billiam 2 $6000
我不確定這是我創建文件的方式(使用簡單的vi編輯器)還是代碼中存在問題,但是當我運行該文件並將帳號和余額提供給程序時,不會在其中報告新余額文件。 有什么建議么?
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char first[15];
char middle[2];
char last[15];
float balance;
long int acct;
} data;
int main() {
int choice = -1, i = 0, n = 0;
long int number;
double amount;
FILE *aPtr;
data accounts[50];
aPtr = fopen("accounts.dat", "ab+");/* Opens file for read/write; appends to file if exist */
if (aPtr == NULL) {
printf("File could not be opened");
exit(1);
}
fseek(aPtr, 0, SEEK_SET); /* Moving pointer to start of file*/
while (fread(accounts + 1, sizeof(data), 1, aPtr) == 1) /* Read and store info in file, into accounts array */
i++;
n = i; /* Num. of records in file */
do {
printf("Select Option\n" );
printf("0: Exit\n1: Deposit\n2: Withdrawl\n3: Add Account\n4: Remove Account\n5: Balance Inquiry\n6: View Accounts\n: ");
scanf("%d", &choice);
switch (choice) {
case 0: /* Exit */
fclose(aPtr);
break;
case 1: /* Deposit*/
fseek(aPtr, 0, SEEK_SET);
printf("Enter account number:\n");
scanf("%ld", &number);
printf("Enter amount to be deposited:\n");
scanf("%lf", &amount);
for (i = 0; i < n; i++) {
if (accounts[i].acct == number) {
accounts[i].balance = accounts[i].balance + amount;
fseek(aPtr, i * sizeof(data), SEEK_SET); /* Pointer goes to accountlocation in file*/
fwrite(accounts + i, sizeof(data), 1, aPtr); /* Write modified account into file */
break;
}
}
if (i == n) {
printf ( "Account does not exist\n" );
}
break;
}
} while (choice != 0);
return 0;
}
這種while
循環讀取數據不正確
while( fread(accounts+1, sizeof(data), 1, aPtr) == 1 ) /* Read and store info in file, into accounts array */
i++;
它只是讀到accounts[1]
,所以無論文件中有多少個賬戶,數組中都只有一個。
您要做的就是將每條記錄讀入accounts[i]
,這是下面的代碼。
while( fread(&accounts[i], sizeof(data), 1, aPtr) == 1 ) /* Read and store info in file, into accounts array */
i++;
或更妙的是,如果您計算出文件的大小
fseek(aPtr, 0, SEEK_END);
unsigned long len = (unsigned long)ftell(aPtr);
那么您知道len
除以sizeof(data)
就是有多少條記錄
n = len/sizeof(data);
您可以一次性讀取所有記錄。
if(fread(accounts, sizeof(data), n, aPtr) != n)
{
/* Oops! Did not read everything in */
}
這具有您可以使用malloc
的額外好處,因此您不會設置50個帳戶的硬限制。
同樣,打開文件的方式也不正確,因為無論您使用fseek
做什么,它都會將您寫入的所有內容附加到文件末尾。 您需要使用“ rb +”代替,但是如果文件不存在,則需要首先使用“ wb +”創建它。
正確填充該結構是此答案的重點。
文件的命名約定表明它應為二進制文件(即, .dat
在行業中通常用於二進制文件)。 但是您顯示的內容清楚地表明它是一個文本文件,因此在以下示例中,我使用data.txt作為文件名。 而且由於它是一個文本文件,並且包含定義明確的行字段,因此將內容解析為一個結構將非常簡單
文件的格式是嚴格定義的,並使用空格作為分隔符。 沒關系,但是選擇在字段內容中通常不使用的可見分隔符(例如逗號:) ,
將在不使用字段(例如沒有中間名)時使事情變得容易。 但這不是必需的,下面的示例將使用空格分隔符。
如果您將在此實現中原諒fgets()
和strtok()
的使用(幾乎沒有錯誤檢查/處理),它提供了一個使用數據文件內容填充結構的示例:
typedef struct
{
char first[15];
char middle[2];
char last[15];
float balance;
long int acct;
}DATA;
const char filename[] = {".\\data.txt"};
int lineCount(const char *fname);
DATA * populateData(int lines, const char *fname);
int main(void)
{
int lines = lineCount(filename);//count number of accounts in file (lines in file)
DATA *data = populateData(lines, filename);//Create and populate data structure
if(data)
{
; //use data here
free(data); //free data memory when finished using it.
}
return 0;
}
int lineCount(const char *fname)
{
int count=0;
char line[260];
FILE *fp = fopen(fname, "r");
if(fp)
{
while(fgets(line, 260, fp)) count++;
fclose(fp);
}
return count;
}
DATA * populateData(int lines, const char *fname)
{
int i;
char *tok;
char *endPtr;
char line[260];
DATA *data = calloc(lines, sizeof(*data ));
if(data)
{
FILE *fp = fopen(fname, "r");
if(fp)
{
for(i=0;i<lines;i++)
{
if(fgets(line, 260, fp))
{
//get first name
tok = strtok(line, " ");
if(tok)
{
strcpy(data[i].first, tok);
//get Middle name
tok = strtok(NULL, " ");
if(tok)
{
strcpy(data[i].middle, tok);
//get last name
tok = strtok(NULL, " ");
if(tok)
{
strcpy(data[i].last, tok);
//get balance
tok = strtok(NULL, " ");
if(tok)
{
data[i].acct = atoi(tok);
//get acct
tok = strtok(NULL, "$");
if(tok)
{
data[i].balance = strtod(tok, &endPtr);
}
}
}
}
}
}
}
fclose(fp);
}
}
return data;
}
您的程序中存在一個主要錯誤:
while (fread(accounts + 1, sizeof(data), 1, aPtr) == 1) /* Read and store info in file, into accounts array */
沒有{
將所有語句括在一個塊中。 因此,在while
語句中僅重復第一個( i++;
),其余的僅執行一次。
我的建議是:
{
和}
將所有命令語句括在塊中。 {
與if
, while
,for and
switch語句放在同一行(此樣式稱為Kernighan和Ritchie )。 if (i == n) { printf("Account does not exist\\n"); }
if (i == n) { printf("Account does not exist\\n"); }
關於程序的目標,您無法輕松地嘗試更新文本文件。 要么將整個文件讀入內存結構,然后從內存中寫入更新的內容,要么使用具有固定寬度字段的二進制格式。
Unix的哲學是贊成前一種方法,而將后者保留給具有高級API的大型數據庫,以正確解決並發訪問問題。
在寫入文件時還要添加fflush。 在fflush()上查看您的文檔。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.