實現多個帳號windows
#include <stdio.h> #include <string.h> int main(void) { // 定義變量,用來表示用戶名和密碼 char name[32]; char password[16]; FILE *file; //定義了一個檔指針變量,變量名是file char line[128]; char name_tmp[32]; char password_tmp[16]; char *ret; //打開檔 file = fopen("users.txt", "r"); if (!file) { //等效於 file == NULL printf("檔打開失敗"); return 1; } //輸入用戶名和密碼 while (1) { // 輸入用戶名和密碼 printf("請輸入用戶名:"); scanf("%s", name); printf("請輸入密碼:"); scanf("%s", password); /* if (strcmp(name, "admin") == 0 && strcmp(password, "123456") == 0) { break; } else { printf("用戶名或密碼錯誤!\n"); system("pause"); system("cls"); } */ //從檔中讀取帳號,並進行判斷! while (1) { //讀一行 ret = fgets(line, sizeof(line), file); //line: "admin 123456\n" if (!ret) { break; } sscanf(line, "%s %s", name_tmp, password_tmp); if (!strcmp(name, name_tmp) && !strcmp(password, password_tmp)) { break; } } if (ret) { //用戶名和密碼匹配成功 break; } else { printf("用戶名或密碼錯誤!\n"); system("pause"); system("cls"); fseek(file, 0, SEEK_SET); //把檔內部的位置指針設置到檔頭 } } system("cls"); // 打印功能菜單 printf("---交換機後臺管理---\n"); printf("1. 建立帳號\n"); printf("2. IP管理\n"); printf("3. 退出\n"); printf("請選擇..."); return 0; }
1.fopen檔的打開操做
函數原型
#include <stdio.h>
FILE fopen( const char fname, const char mode );
參數1:fname 表示文件名(能夠含有路徑信息)
參數2:打開方式
返回值:FILE 檔指針,
若是打開失敗,就返回NULL(就是0)ide
mode 打開方式
"r" 以「讀」的方式打開一個文本檔(只能讀)
"r+" 與"r" 的區別在於,增長了「寫」
"rb" 以「讀」的方式打開一個二進制檔(只能讀)
"rb+" 與"rb"的區別在於,增長了「寫」函數
"w" 以「寫」的方式建立一個文本檔,若是這個檔已經存在,就會覆蓋原來的檔
"w+" 與"w"的區別在於,增長了「讀」
"wb" 以「寫「的方式建立一個二進制檔
"wb+" 與"wb"的區別在於,增長了「讀」學習
"a" 以「尾部追加」的方式打開一個文本檔, (只能寫)
"a+" 以"a"的區別在於,增長了"讀"
"ab" 以「尾部追加」的方式打開一個二進制檔, (只能寫)
"ab+" 與"ab"的區別在於,增長了「讀」3d
小結:
打開方式,共1到3個字符。
第一個字符是 r、w或a
r 表示「讀」,用於打開已經存在的檔
w 表示「建立」, 用於建立一個新檔,並可以「寫」
a 表示「尾部追加」,並可以"寫"指針
b, 只能寫在第二位,表示打開的是二進制檔
+,只能寫在最後,表示增長一個讀或寫的功能code
實例orm
#include <stdio.h> int main(void) { FILE *file; //file = fopen("users.txt", "r"); file = fopen("users1.txt", "r"); if (file != NULL) { //NULL就是0 printf("檔users.txt打開成功!\n"); } else { printf("檔users.txt打開失敗!\n"); } return 0; }
清理緩衝區,並釋放檔指針。blog
Demo字符串
#include <stdio.h> int main(void) { FILE *file; file = fopen("users.txt", "a"); fputs("\nxiaoxiao 123456", file); fclose(file); return 0; }
特別注意:
對檔執行寫操做之後,並不會立刻寫入檔,而只是寫入到了這個檔的輸出緩衝區中!
只有當這個輸出緩衝區滿了,或者執行了fflush,或者執行了fclose函數之後,或者程序結束,
纔會把輸出緩衝區中的內容正真寫入檔!
函數原型:
#include <stdio.h>
int fgetc( FILE *stream );
返回值:成功時,返回讀到的字符,返回的是int類型(實際值是字符)
失敗或讀到檔尾,返回EOF (就是-1)
做用:
從檔中讀取一個字符
實例:
#include <stdio.h> int main(void) { FILE *file; char c; file = fopen("users.txt", "r"); while ((c = fgetc(file)) != EOF) { //EOF就是 -1 printf("%c", c); } return 0; }
函數原型:
#include <stdio.h>
int fputc( int ch, FILE *stream );
實例:
test.c
#include <stdio.h> int main(void) { FILE *file1; FILE *file2; char c; file1 = fopen("test.c", "r"); file2 = fopen("test2.c", "w"); while ((c = fgetc(file1)) != EOF) { //EOF就是 -1 fputc(c, file2); } fclose(file1); fclose(file2); return 0; }
複習:
在項目4的「字符串輸入」中學習過。
函數原型:
#include <stdio.h>
char fgets( char str, int num, FILE *stream );
參數:
num: 最多讀取num-1個字符,或者遇到檔結束符EOF爲止(即「檔讀完了」)
返回值; 讀取失敗時, 返回NULL,
讀取成功時,返回str
實例:
#include <stdio.h> int main(void) { FILE *file1; char tmp[64]; char c; file1 = fopen("test.c", "r"); while (fgets(tmp, sizeof(tmp), file1) != NULL) { printf("%s", tmp); } fclose(file1); return 0; }
函數原型:
#include <stdio.h>
int fputs( const char str, FILE stream );
實例
#include <stdio.h> int main(void) { FILE *file1; FILE *file2; char tmp[64]; char c; file1 = fopen("test.c", "r"); file2 = fopen("test2.c", "w"); while (fgets(tmp, sizeof(tmp), file1) != NULL) { fputs(tmp, file2); } fclose(file1); fclose(file2); return 0; }
函數原型:
#include <stdio.h>
int fprintf( FILE stream, const char format, ... );
Demo:
#include <stdio.h> int main(void) { FILE *file1; char name[32]; int age; char c; file1 = fopen("info.txt", "w"); while (1) { printf("請輸入學員姓名:"); scanf("%s", name); printf("請輸入%s的成績: ", name); scanf("%d", &age); fprintf(file1, "姓名:%s\t\t年齡:%d\n", name, age); printf("還須要繼續輸入嗎? Y/N\n"); //fflush(stdin); while((c=getchar()) != '\n'); //直到讀到回車符爲止! scanf("%c", &c); if (c == 'Y' || c == 'y') { continue; } else { break; } } fclose(file1); return 0; }
函數原型:
#include <stdio.h>
int fscanf( FILE stream, const char format, ... );
返回值:成功時,返回實際讀取的數據個數
失敗時,返回 EOF (-1)
匹配失敗時,返回0
Demo
#include <stdio.h> int main(void) { FILE *file1; char name[32]; int age; int ret; file1 = fopen("info.txt", "r"); while (1) { ret = fscanf(file1, "姓名:%s 年齡:%d\n", &name, &age); if (ret == EOF) { break; } printf("%s,%d\n", name, age); } fclose(file1); return 0; }
#include <stdio.h>
int fwrite( const void buffer, //要寫入的數據的其實地址,也就是變量的地址
size_t size, //每「塊」數據的大小
size_t count, //寫入幾塊數據
FILE stream );
Demo
#include <stdio.h> #include <string.h> int main(void) { FILE *file1; char name[32]; int age; int ret; file1 = fopen("info.txt", "wb"); printf("請輸入您的姓名: "); gets(name); printf("請輸入您的年齡: "); scanf("%d", &age); fwrite(name, sizeof(name), sizeof(char), file1); fwrite(&age, 1, sizeof(int), file1); fclose(file1); return 0; }
補充:
w和wb的區別
wb的demo
#include <stdio.h> #include <string.h> int main(void) { FILE *file1; char info[] = "Hello\nWorld"; int age; int ret; file1 = fopen("test.txt", "wb"); fwrite(info, sizeof(char), strlen(info), file1); fclose(file1); return 0; }
w的demo
#include <stdio.h> #include <string.h> int main(void) { FILE *file1; char info[] = "Hello\nWorld"; // \n 保存位 \r\n int age; int ret; file1 = fopen("test.txt", "w"); fwrite(info, strlen(info), sizeof(char), file1); fclose(file1); return 0; }
小結:
在windows平臺下,
當使用w方式打開檔時,
若是使用fwrite寫入數據時,會把’\n’寫入爲 ‘\r’’\n’
即把10保存爲 13 10
由於,在windows平臺下,文本檔中的回車符\n,會保存爲 \r\n
( \n的ASCII碼爲10, \r的ASCII碼爲13)
當使用wb方式打開檔時,
若是使用fwrite寫入數據時,遇到’\n’仍只寫入爲 ‘\n’
函數原型:
#include <stdio.h>
int fread( void buffer, size_t size, size_t num, FILE stream );
Demo
#include <stdio.h> #include <string.h> int main(void) { FILE *file1; char name[32]; int age; int ret; file1 = fopen("student.txt", "rb"); fread(name, sizeof(name), sizeof(char), file1); fread(&age, 1, sizeof(int), file1); printf("%s, %d\n", name, age); fclose(file1); return 0; }
demo
#include <stdio.h> #include <string.h> int main(void) { FILE *file1; int data[] = {1,2,3,4,5}; int i; file1 = fopen("test.txt", "w"); for (i=0; i<5; i++) { putw(data[i], file1); } fclose(file1); return 0; }
函數原型:
int getw(FILE *fp)
返回值:成功時返回讀取到的值
失敗時返回-1。
Demo
#include <stdio.h> int main(void) { FILE *file; int value; file = fopen("test.data", "rb"); if (!file) { printf("檔打開失敗!\n"); return 1; } while (1) { value = getw(file); if (value == -1 && feof(file)) { break; } printf("%d ", value); } fclose(file); return 0; }
函數原型:
#include <stdio.h>
int feof( FILE *stream );
返回值:若是指定的程序,已經到達檔末尾位置,就返回非零值(真)。
#include <stdio.h> int main(void) { FILE *file; char c; file = fopen("test.c", "r"); //while ((c = fgetc(file)) != EOF) { //EOF就是 -1 while (!feof(file)) { c = fgetc(file); printf("%c", c); } return 0; }
#include <stdio.h> int main(void) { FILE *file; char c; int ret; file = fopen("test.c", "r"); fputc('A', file); if (ferror(file)) { perror("檔file發生錯誤"); } return 0; }
執行結果:
把 「r」 改成 「r+」 就不會發生錯誤了。
函數原型:
#include <stdio.h>
void clearerr( FILE *stream );
Demo
#include <stdio.h> int main(void) { FILE *file; char c; int ret; file = fopen("test.c", "r"); fputc('A', file); if (ferror(file)) { perror("檔file發生錯誤"); } //若是不清除檔錯誤,之後讀寫檔時, 即便沒有發生錯誤,ferror仍將返回非零值(認爲還有錯) clearerr(file); c = fgetc(file); printf("c=%c\n", c); if (ferror(file)) { perror("檔file發生錯誤"); } return 0; }
函數原型:
#include <stdio.h>
long ftell( FILE *stream );
Demo
#include <stdio.h> int main(void) { FILE *file; char c; int ret; long offset; file = fopen("test.c", "r"); offset = ftell(file); printf("當前位置是: %ld\n", offset); fgetc(file); offset = ftell(file); printf("當前位置是: %ld\n", offset); fclose(file); return 0; }
注意:檔始終只能從當前的位置向檔尾方向讀寫!
函數原型:
#include <stdio.h>
int fseek( FILE *stream, long offset, int origin );
參數2:
偏移量,可正可負。
<0 向檔頭方向偏移 <>
<0 向檔尾方向偏移 <>
參數3:
SEEK_SET 從檔的開始位置定位, 此時參數2必須大於0
SEEK_CUR 從檔的當前位置定位
SEEK_END 從檔的結束位置定位, 此時參數2必須小與0
Demo
#include <stdio.h> int main(void) { FILE *file; char c; char buff[256]; int i; file = fopen("test.c", "r"); //讀取檔最後10個字符 fseek(file, -10, SEEK_END); while (!feof(file)) { c = fgetc(file); printf("%c", c); } //讀取檔的第一行 fseek(file, 0, SEEK_SET); fgets(buff, sizeof(buff), file); printf("\n第一行:%s\n", buff); //讀取當前位置的前10個字符 fseek(file, -10, SEEK_CUR); printf("\n這10個字符是:"); for (i=0; i<10; i++) { c = fgetc(file); printf("%c", c); } close(file); return 0; }
把檔的位置指針定位到開始位置。
rewind(file)
等效於:
fseek(file, 0, SEEK_SET)
1.練習1
獨立實現項目7.
編寫一個程序,統計該程序自己一共有多少個字符,有多少行,並列印輸出
#include <stdio.h> // 統計這個程序自己,有多少個字符,有多少行代碼 int main(void) { FILE *file ; char c; int count_char = 0; //字符總數 int count_line = 0; //行數 file = fopen("test.c", "r"); if (!file ) { printf("檔打開失敗!\n"); return 1; } while ((c=fgetc(file)) != EOF) { count_char++; if (c == '\n') { count_line++; } } count_line++; printf("一共有 %d 個字符\n", count_char); printf("一共有 %d 行代碼\n", count_line); return 0; }
3.已有一個檔,用來保存通信錄,假設已有內容以下:
note.txt 張三丰 Tel:13507318888 Addr:武當 劉備 Tel:13802289999 Addr:成都 馬雲 Tel:13904256666 Addr:杭州 馬化騰 Tel:13107551111 Addr:深圳
編寫一個程序,執行效果以下:
參考:
#include <stdio.h> #include <string.h> int main(void) { FILE *file; char name_search[64]; char line[256]; char name[64]; char tel[32]; char addr[32]; int found = 0; file = fopen("note.txt", "r"); if (!file) { printf("檔打開失敗\n"); return 1; } printf("請輸入要查詢的用戶名:"); scanf("%s", name_search); while (!feof(file)) { fscanf(file, "%s Tel:%s Addr:%s\n", name, tel, addr); if (!strcmp(name, name_search)) { printf("%s的電話是:%s\n", name_search, tel); found = 1; break; } } if (found == 0) { printf("沒有%s的信息\n", name_search); } return 0; }
須要特別注意fscanf的格式字符串中最後的\n,否者只能匹配第一行!
補充說明:
對於以下文本: 張三丰 Tel:13507318888 Addr:武當 劉備 Tel:13802289999 Addr:成都 馬雲 Tel:13904256666 Addr:杭州 馬化騰 Tel:13107551111 Addr:深圳 能夠循環使用以下代碼讀取: fscanf(file, "%s Tel:%s Addr:%s\n", name, tel, addr); 可是不加回車符,使用以下語句也能讀取: fscanf(file, "%s Tel:%s Addr:%s", name, tel, addr); 這是是由於: 使用fscanf(file,"%s Tel:%s Addr:%s",name_tmp,tel,addr),匹配到第一行的第2個%s時,恰好把第一個行中,除了最後的回車符之外,匹配完。此時第一行還剩下一個回車符。接着進入第2輪循環,又開始使用scanf匹配,可是注意,是從檔的上一次匹配結束的位置繼續匹配,也就是第一行行尾的回車符爲止,在這個格式字符串中,第一個是%s,因此會跳過第一行行尾的回車符,從而匹配成功。 若是檔的內容是這樣的格式,就必須在格式字符串的最後加上\n了 姓名:張三丰 電話:13243879188 姓名:張四風 電話:13243879199 總結:須要特別注意fscanf的格式字符串中最後的\n的做用。