Đọc ghi file trong C - Học lập trình C căn bản & nâng cao
Trong bài này chúng ta sẽ tìm hiểu cách đọc ghi file trong C bằng cách sử dụng các hàm xử lý file: fprintf(), fscanf(), fread(), fwrite(), fseek(). Đa số sinh viên Việt Nam học lập trình C là để luyện tư duy logic, cũng có một số người dùng để xây dựng ứng dụng thực tế nên việc thao tác với file ...
Trong bài này chúng ta sẽ tìm hiểu cách đọc ghi file trong C bằng cách sử dụng các hàm xử lý file: fprintf(), fscanf(), fread(), fwrite(), fseek().
Đa số sinh viên Việt Nam học lập trình C là để luyện tư duy logic, cũng có một số người dùng để xây dựng ứng dụng thực tế nên việc thao tác với file là rất quan trọng khi cần lưu trữ dữ liệu mà không cần hệ quản trị CSDL.
1. Tại sao cần lưu trữ dữ liệu lên file?
Khi chương trình kết thúc thì toàn bộ dữ liệu sẽ bị mất, vì vậy nếu bạn lưu vào file thì sẽ xem lại được thông tin.
Hoặc nếu bạn cần nhập dữ liệu lớn thì sẽ mấ khá nhiều thời gian. Nhưng nếu bạn lưu nó vào một file có cấu trúc nhất quán, và dùng lệnh đọc ghi file trong C thì việc xử lý sẽ nhanh gọn hơn rất nhiều.
Bạn cũng có thể dễ dàng copy dữ liệu từ máy này sang máy khác.
Tuy nhiên việc lưu trữ này là không an toàn, bởi người dùng có thể mở file ra đọc một cách dễ dàng, chứ không giống như lưu trữ vào các hệ quản trị CSDL như SQL Server / MySQL / Oracle.
2. Có những loại file phổ biến nào?
Khi xử lý file trong C thì bạn cần quan tâm đến hai loại file như sau:
- Text files
- Binary files
Text file
Là một file có phần mở rộng là txt, nó là file thông thường nên có thể mở nó bằng những công cụ đọc file text đơn giản như notepad.
Khi bạn mở các file đó, bạn sẽ thấy tất cả nội dung trong tệp dưới dạng văn bản thuần túy. Bạn có thể dễ dàng chỉnh sửa hoặc xóa nội dung.
Chúng cần được tối ưu để giúp dễ đọc, bảo mật, cũng như chiếm ít dung lượng lưu trữ.
Binary files
Là những file có phần đuôi mở rộng là .bin và nó có rất nhiều trong máy tính của bạn đấy.
Thay vì lưu trữ ở dạng văn bản thuần túy thì họ lưu trữ ở dạng nhị phân (0 và 1), vì vậy kích thước file sẽ rất dài, nhưng bù lại dữ liệu sẽ không thể đọc bằng mắt thường được nên an toàn hơn.
3. Các thao tác cơ bản với file trong C
Bây giờ ta sẽ thực hành một vài thao tác với file thông dụng nhất nhé.
Khai báo con trỏ kiểu FILE
Khi làm việc với file thì bạn phải khai báo con trỏ kiểu FILE, nó sẽ trỏ đến file cần đọc trên máy tính và giúp trình biên dịch đọc ghi dữ liệu với file.
FILE *fptr;
Mở một file
Để mở file thì ta sử dụng hàm fopen()
nằm trong thư viện stdio.h
. Cú pháp của nó như sau:
ptr = fopen("fileopen","mode");
Ví dụ:
fopen("E:\cprogram\newprogram.txt","w"); fopen("E:\cprogram\oldprogram.bin","rb");
Đường dẫn mở file rất rõ ràng. Nhưng chế độ đọc file mode thì bạn hãy xem bảng dưới đây.
Đóng kết nối
Sau khi mở file và thực hiện xong thì bạn nên đóng file lại bằng cách sau:
fclose(fptr);
Trong đó fptr
là con trỏ của file đang xử lý.
4. Đọc và ghi vào file text
Để đọc và ghi dữ liệu vào file text thì ta sử dụng hai hàm fprintf()
và fscanf()
.
Ví dụ: Ghi dữ liệu vào file text
#include <stdio.h> #include <stdlib.h> int main() { int num; FILE *fptr; fptr = fopen("C:\program.txt","w"); if(fptr == NULL) { printf("Error!"); exit(1); } printf("Enter num: "); scanf("%d",&num); fprintf(fptr,"%d",num); fclose(fptr); return 0; }
Chương trình này lấy một số từ người dùng và lưu trữ trong file program.txt
.
Sau khi biên dịch và chạy chương trình này, bạn có thể thấy file program.txt
được tạo trong ổ C của máy tính. Khi bạn mở file bạn có thể thấy số nguyên bạn đã nhập.
Ví dụ 2: Đọc dữ liệu từ file text
#include <stdio.h> #include <stdlib.h> int main() { int num; FILE *fptr; if ((fptr = fopen("C:\program.txt","r")) == NULL){ printf("Error! opening file"); exit(1); } fscanf(fptr,"%d", &num); printf("Value of n=%d", num); fclose(fptr); return 0; }
Chương trình này đọc số nguyên có trong file program.txt
và in ra màn hình.
Nếu bạn đã tạo thành công file từ ví dụ 1 thì khi chạy chương trình này sẽ nhận được số nguyên bạn đã nhập.
Các hàm khác như fgetchar (), fputc (), v.v. sử dụng tương tự theo cách này.
4. Đọc và ghi dữ liệu vào file binary
Hai hàm fread() và fwrite() được dùng để đọc và ghi vào file ở định dạng nhị phân binary.
Ghi file nhị phân
Để ghi vào file nhị phân, bạn cần sử dụng hàm fwrite (). Hàm này có bốn tham số:
- Đường dẫn đến file cần ghi
- Kích thước của dữ liệu
- Số loại dữ liệu như vậy
- Con trỏ đến file mà bạn muốn ghi
fwrite(addressData, sizeData, numbersData, pointerToFile);
Ví dụ: Ghi dữ liệu vào file nhị phân sử dụng ham ffwrite()
#include <stdio.h> #include <stdlib.h> struct threeNum { int n1, n2, n3; }; int main() { int n; struct threeNum num; FILE *fptr; if ((fptr = fopen("C:\program.bin","wb")) == NULL){ printf("Error! opening file"); // Dừng chương trình nếu con trỏ đọc file trả về NULL. exit(1); } for(n = 1; n < 5; ++n) { num.n1 = n; num.n2 = 5*n; num.n3 = 5*n + 1; fwrite(&num, sizeof(struct threeNum), 1, fptr); } fclose(fptr); return 0; }
Đọc dữ liệu file nhị phân
Để đọc file nhị phân thì ta sử dụng hàm fread(), hàm này cũng có bốn tham số như hàm fwrite.
fread(addressData, sizeData, numbersData, pointerToFile);
#include <stdio.h> #include <stdlib.h> struct threeNum { int n1, n2, n3; }; int main() { int n; struct threeNum num; FILE *fptr; if ((fptr = fopen("C:\program.bin","rb")) == NULL){ printf("Error! opening file"); // Dừng chương trình nếu con trỏ đọc file trả về NULL. exit(1); } for(n = 1; n < 5; ++n) { fread(&num, sizeof(struct threeNum), 1, fptr); printf("n1: %d n2: %d n3: %d", num.n1, num.n2, num.n3); } fclose(fptr); return 0; }
5. Lấy dữ liệu bằng hàm fseek()
Nếu bạn có nhiều dòng ghi bên trong file và cần truy cập đến vị trí cụ thể thì chỉ cần lặp qua tất cả các dòng và lấy dòng muốn lấy, điều này sẽ lãng phí rất nhiều bộ nhớ và thời gian hoạt động.
Ta có thể sử dụng hàm fseek () để trỏ đến dòng mong muốn một cách nhanh nhất mà không phải duyệt tất cả nội dung của file.
Cú pháp:
fseek(FILE * stream, long int offset, int whence);
Tham số đầu tiên là con trỏ đến file. Tham số thứ hai là kích thước dữ liệu cần ghi vào. Tham số thứ ba chỉ định vị trí bắt đầu tìm.
Tham số whence chính là một trong ba hằng số sau:
#include <stdio.h> #include <stdlib.h> struct threeNum { int n1, n2, n3; }; int main() { int n; struct threeNum num; FILE *fptr; if ((fptr = fopen("C:\program.bin","rb")) == NULL){ printf("Error! opening file"); // Dừng chương trình nếu con trỏ đọc file trả về NULL. exit(1); } // Di chuyển con trỏ về cuối file fseek(fptr, -sizeof(struct threeNum), SEEK_END); for(n = 1; n < 5; ++n) { fread(&num, sizeof(struct threeNum), 1, fptr); printf("n1: %d n2: %d n3: %d ", num.n1, num.n2, num.n3); fseek(fptr, -2*sizeof(struct threeNum), SEEK_CUR); } fclose(fptr); return 0; }
Chương trình này sẽ bắt đầu đọc các bản ghi từ file program.bin
theo thứ tự ngược lại (từ cuối đến trước) và in ra màn hình.