Bài tập

Bài 70. Đọc ghi file trong ngôn ngữ lập trình C

Huy Erick

Trong ngôn ngữ lập trình C, việc đọc ghi file là một công việc phổ biến và quan trọng. Trong bài viết này, chúng ta sẽ hướng dẫn cách làm việc với file trong ngôn...

Trong ngôn ngữ lập trình C, việc đọc ghi file là một công việc phổ biến và quan trọng. Trong bài viết này, chúng ta sẽ hướng dẫn cách làm việc với file trong ngôn ngữ lập trình C. Có rất nhiều hàm hỗ trợ cho việc đọc ghi file, như fprintf(), fscanf(), fread(), fwrite(), fseek và nhiều hàm khác.

Tại sao chúng ta cần đến file?

  • Dữ liệu được lưu ở biến của chương trình, và nó sẽ biến mất khi chương trình kết thúc. Sử dụng file để lưu trữ dữ liệu cần thiết để đảm bảo dữ liệu không bị mất ngay cả khi chương trình ngừng chạy.
  • Nếu chương trình có đầu vào lớn, việc phải nhập mỗi khi chạy sẽ rất bất tiện. Thay vào đó, hãy lưu vào file và chương trình sẽ tự động đọc mỗi khi khởi chạy.
  • Dễ dàng sao chép, di chuyển dữ liệu giữa các thiết bị với nhau.

Các kiểu file

Trước khi làm việc với file, chúng ta cần biết về hai kiểu file khác nhau:

  1. File văn bản - text files
  2. File nhị phân - binary file

1. File văn bản - text files

File văn bản là file có đuôi .txt. Bạn có thể dễ dàng tạo ra các file này bằng cách sử dụng các trình soạn thảo văn bản phổ biến như Notepad, Notepad++, Sublime Text, ...

Khi mở các file này bằng các trình soạn thảo văn bản trên, bạn sẽ thấy nội dung được hiển thị và có thể dễ dàng chỉnh sửa, xóa, thêm nội dung vào file.

Kiểu file này thuận tiện cho việc sử dụng hàng ngày, nhưng nó có thể kém bảo mật và yêu cầu nhiều dung lượng lưu trữ hơn.

2. File nhị phân - Binary files

File nhị phân thường có đuôi .bin.

Thay vì lưu trữ dưới dạng văn bản, các file này được lưu dưới dạng nhị phân, chỉ gồm các số 0 và 1. Nếu bạn cố gắng mở file nhị phân này bằng trình soạn thảo văn bản, bạn sẽ thấy các số này.

Loại file này cho phép lưu trữ dữ liệu lớn hơn, không thể đọc bằng các trình soạn thảo văn bản thông thường và thông tin lưu trữ trong file này được bảo mật hơn so với file văn bản.

Các thao tác với file

Trong ngôn ngữ lập trình C, chúng ta có một số thao tác chính khi làm việc với file, bao gồm cả file văn bản và file nhị phân:

  1. Tạo mới một file
  2. Mở một file đã có
  3. Đóng file đang mở
  4. Đọc thông tin từ file / Ghi thông tin ra file

Thao tác với file trên ngôn ngữ C

Khi làm việc với file, bạn cần khai báo một con trỏ kiểu FILE. Việc khai báo này là cần thiết để có sự kết nối giữa chương trình của bạn và tập tin bạn muốn thao tác.

FILE *fptr;

Thao tác mở file

Để đọc ghi file trong C, việc đầu tiên bạn cần làm là mở file bạn muốn làm việc với. Trong ngôn ngữ lập trình C, chúng ta có thể mở file bằng cách sử dụng hàm fopen() trong thư viện stdio.h như sau:

fptr = fopen("tên_file", "chế_độ")

Trong đó, chế độ là một tham số chúng ta cần chỉ định.

Ví dụ:

fptr = fopen("E:\cprogram\newprogram.txt", "w"); // hoặc fptr = fopen("E:\cprogram\oldprogram.bin", "rb");
  • Giả sử tập tin newprogram.txt chưa có trong thư mục E:cprogram. Ví dụ đầu tiên với chế độ "w" sẽ cho phép chương trình tự động tạo ra file newprogram.txt nếu nó chưa có và sau đó mở file này. Tuy nhiên, chương trình chỉ có thể ghi dữ liệu vào file mà không thể đọc.
  • Chế độ "w" chỉ cho phép chương trình ghi (nếu đã có dữ liệu thì ghi đè) nội dung của file.
  • Với ví dụ thứ hai, chế độ là "rb" cho phép chương trình mở một file nhị phân đã có sẵn oldprogram.bin. Trong trường hợp này, chương trình của bạn chỉ có thể đọc file và không thể ghi nội dung vào file.

Các tham số của "chế_độ"

Dưới đây là các giá trị có thể của tham số chế độ nói trên:

  • "r": Mở file chỉ cho phép đọc. Nếu file không tồn tại, fopen() sẽ trả về NULL.
  • "rb": Mở file chỉ cho phép đọc dưới dạng nhị phân. Nếu file không tồn tại, fopen() sẽ trả về NULL.
  • "w": Mở file chỉ cho phép ghi. Nếu file đã tồn tại, nội dung sẽ bị ghi đè. Nếu file không tồn tại, nó sẽ được tạo tự động.
  • "wb": Mở file cho phép ghi ở dạng nhị phân. Nếu file đã tồn tại, nội dung sẽ bị ghi đè. Nếu file không tồn tại, nó sẽ được tạo tự động.
  • "a": Mở file ở chế độ ghi "append". Tức là sẽ ghi vào cuối của nội dung đã có. Nếu file không tồn tại, nó sẽ được tạo tự động.
  • "ab": Mở file ở chế độ ghi nhị phân "append". Tức là sẽ ghi vào cuối của nội dung đã có. Nếu file không tồn tại, nó sẽ được tạo tự động.
  • "r+": Mở file cho phép cả đọc và ghi. Nếu file không tồn tại, fopen() sẽ trả về NULL.
  • "rb+": Mở file cho phép cả đọc và ghi ở dạng nhị phân. Nếu file không tồn tại, fopen() sẽ trả về NULL.
  • "w+": Mở file cho phép cả đọc và ghi. Nếu file đã tồn tại, nội dung sẽ bị ghi đè. Nếu file không tồn tại, nó sẽ được tạo tự động.
  • "wb+": Mở file cho phép cả đọc và ghi ở dạng nhị phân. Nếu file đã tồn tại, nội dung sẽ bị ghi đè. Nếu file không tồn tại, nó sẽ được tạo tự động.
  • "a+": Mở file cho phép cả đọc và ghi "append". Nếu file không tồn tại, nó sẽ được tạo tự động.
  • "ab+": Mở file cho phép cả đọc và ghi "append" ở dạng nhị phân. Nếu file không tồn tại, nó sẽ được tạo tự động.

Thao tác đóng file

Khi hoàn tất công việc với tệp tin, bạn cần đóng file đã mở. Điều này có thể được thực hiện bằng cách sử dụng hàm fclose().

fclose(fptr); // Con trỏ FILE trỏ tới file cần được đóng.

Đọc/Ghi file văn bản trong C

Chúng ta sẽ học cách đọc và ghi file văn bản trong C. Đối với file nhị phân, bạn có thể kéo xuống phần tiếp theo.

Để làm việc với file văn bản, chúng ta sẽ sử dụng các hàm fprintf() và fscanf().

Ví dụ 1. Ghi file sử dụng fprintf()

#include 
#include 

int main() {
    int num;
    FILE *fptr;

    fptr = fopen("program.txt", "w");

    if (fptr == NULL) {
        printf("Lỗi!");
        exit(1);
    }

    printf("Nhập số: ");
    scanf("%d", &num);

    fprintf(fptr, "%d", num);
    fclose(fptr);

    return 0;
}

Chương trình này nhận một số từ người dùng và ghi vào file văn bản program.txt.

Sau khi bạn chạy chương trình này, bạn sẽ thấy file văn bản program.txt được tạo mới trong ổ C của máy tính. Mở file này lên, bạn sẽ thấy số mà bạn vừa nhập cho biến num.

Ví dụ 2. Đọc file sử dụng fscanf()

#include 
#include 

int main() {
    int num;
    FILE *fptr;

    if ((fptr = fopen("program.txt", "r")) == NULL) {
        printf("Lỗi! Không thể mở file");
        exit(1);
    }

    fscanf(fptr, "%d", &num);
    printf("Giá trị của n = %d", num);

    fclose(fptr);

    return 0;
}

Chương trình này sẽ đọc giá trị số được lưu trong file program.txt mà chương trình ở ví dụ 1 vừa tạo ra và in lên màn hình.

Đọc/Ghi file nhị phân trong C

Các hàm fread() và fwrite() được sử dụng để đọc và ghi file nhị phân trong C.

Ghi file nhị phân

Để ghi file nhị phân, bạn cần sử dụng hàm fwrite(). Hàm này có 4 tham số: địa chỉ của biến lưu dữ liệu cần ghi, kích thước của biến lưu dữ liệu, số lượng kiểu dữ liệu của biến đó và con trỏ FILE trỏ tới file bạn muốn ghi.

fwrite(address_data, size_data, numbers_data, pointer_to_file);

Ví dụ 3. Ghi file nhị phân sử dụng fwrite()

#include 
#include 

struct threeNum {
    int n1, n2, n3;
};

int main() {
    int n;
    struct threeNum num;
    FILE *fptr;

    if ((fptr = fopen("program.bin", "wb")) == NULL) {
        printf("Lỗi! Không thể mở file");
        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;
}

Trong ví dụ này, chương trình sẽ tạo ra một file program.bin trên ổ đĩa C của bạn. Chương trình này đã khai báo một kiểu dữ liệu cấu trúc lưu ba giá trị số n1, n2, n3; Và nó được sử dụng trong hàm main với tên biến là num.

Trong vòng lặp, các số được ghi vào file sử dụng hàm fwrite(). Các tham số bao gồm:

  • Tham số đầu tiên là địa chỉ của biến num.
  • Tham số thứ 2 là kích thước của biến num.
  • Tham số thứ 3 là số lượng kiểu dữ liệu - ở đây là 1.
  • Tham số thứ 4 là con trỏ FILE trỏ tới tệp tin program.bin.

Cuối cùng, chúng ta đóng file sử dụng fclose().

Đọc file nhị phân

Hàm fread() cũng có 4 tham số tương tự như hàm fwrite() ở trên.

fread(address_data, size_data, numbers_data, pointer_to_file);

Ví dụ đọc file nhị phân sử dụng fread()

#include 
#include 

struct threeNum {
    int n1, n2, n3;
};

int main() {
    int n;
    struct threeNum num;
    FILE *fptr;

    if ((fptr = fopen("program.bin", "rb")) == NULL) {
        printf("Lỗi! Không thể mở file");
        exit(1);
    }

    for (n = 1; n  5; ++n) {
        fread(&num, sizeof(struct threeNum), 1, fptr);
        printf("n1: %d\tn2: %d\tn3: %d\n", num.n1, num.n2, num.n3);
    }

    fclose(fptr);

    return 0;
}

Trong ví dụ này, bạn đọc file program.bin và lặp qua từng dòng. Bạn sẽ nhận được các giá trị tương ứng khi bạn ghi vào trong ví dụ 3.

Một số ví dụ về đọc ghi file trong C

Trong phần này, mình sẽ trình bày hai ví dụ về đọc ghi file trong C, bao gồm các bài tập đọc ghi file sau:

  1. Ghi văn bản vào file trong C
  2. Đọc dữ liệu văn bản từ file trong C

Ghi vào file một câu văn bản

#include 
#include 

int main() {
    char sentence[1000];
    FILE *fptr;

    fptr = fopen("program.txt", "w");

    if (fptr == NULL) {
        printf("Lỗi!");
        exit(1);
    }

    printf("Nhập một câu văn bản: ");
    gets(sentence);

    fprintf(fptr, "%s", sentence);
    fclose(fptr);

    return 0;
}

Đọc dữ liệu văn bản từ file

#include 
#include 

int main() {
    char c[1000];
    FILE *fptr;

    if ((fptr = fopen("program.txt", "r")) == NULL) {
        printf("Lỗi! Không thể mở file");
        exit(1);
    }

    fscanf(fptr, "%[^n]", c);
    printf("Dữ liệu từ file: %s", c);

    fclose(fptr);

    return 0;
}

Giả sử file văn bản program.txt có nội dung như sau:

C programming is awesome. I love C programming. How are you doing?

Chạy thử:

Dữ liệu từ file: C programming is awesome.

Tham khảo

  1. https://www.programiz.com/c-programming/c-file-input-output
1