logo

Tìm hiểu về Lập Trình C

VII - Tệp và xử lý tệp trong C

VII - Tệp và xử lý tệp trong C

I. Khái niệm về tệp

A. Tệp và các loại tệp

Trong ngôn ngữ lập trình C, tệp (File) là một cấu trúc dữ liệu được sử dụng để lưu trữ và truy cập dữ liệu từ và đến các nguồn ngoại tuyến như tệp tin trên đĩa cứng. Có hai loại tệp chính trong C:

Tệp văn bản: Lưu trữ dữ liệu dưới dạng văn bản thông thường. Dữ liệu trong tệp văn bản có thể được đọc và chỉnh sửa bằng các trình soạn thảo văn bản.

Tệp nhị phân: Lưu trữ dữ liệu dưới dạng nhị phân, không thể đọc hoặc chỉnh sửa trực tiếp bằng các trình soạn thảo văn bản. Dữ liệu trong tệp nhị phân được lưu trữ theo định dạng cụ thể và thường được sử dụng để lưu trữ cấu trúc dữ liệu phức tạp.

B. Các hoạt động cơ bản trên tệp

Trên tệp, chúng ta có thể thực hiện các hoạt động cơ bản sau:

Đọc tệp: Truy cập dữ liệu từ tệp và đưa vào trong chương trình để xử lý.

Ghi tệp: Ghi dữ liệu từ chương trình vào tệp để lưu trữ hoặc chia sẻ.

Đóng tệp: Kết thúc quá trình truy cập và ghi dữ liệu vào tệp, giải phóng tài nguyên hệ thống được sử dụng cho tệp đó.

C. Định dạng tệp

Trên mỗi tệp, dữ liệu được tổ chức theo các kiểu dữ liệu và cấu trúc cụ thể. Định dạng tệp xác định cách dữ liệu được lưu trữ, đọc và ghi trong tệp. Các kiểu dữ liệu phổ biến trong tệp bao gồm: ký tự, số nguyên, số thực, chuỗi ký tự và cấu trúc.

Để đọc và ghi dữ liệu từ và vào tệp, chúng ta cần sử dụng các phương thức đọc và ghi tương ứng với kiểu dữ liệu và định dạng của tệp.

Trên đây là phần giới thiệu về khái niệm cơ bản về tệp trong ngôn ngữ C. Tiếp theo, chúng ta sẽ tìm hiểu về cách mở tệp, đọc và ghi dữ liệu vào tệp, cũng như các phương pháp xử lý lỗi và đóng tệp trong ngôn ngữ C.

II. Xử lý tệp trong C

A. Mở tệp

Để làm việc với tệp, chúng ta cần mở tệp trước bằng cách sử dụng hàm fopen(). Hàm này cho phép chúng ta mở tệp trong các chế độ khác nhau như đọc, ghi, hoặc cả đọc và ghi.

Để minh họa cách mở tệp trong ngôn ngữ C, dưới đây là một ví dụ đơn giản:

#include <stdio.h>

int main() {

    FILE *file;

    char *filename = "example.txt";

    // Mở tệp trong chế độ đọc

    file = fopen(filename, "r");    

    // Kiểm tra xem tệp đã mở thành công hay chưa

    if (file == NULL) {

        printf("Không thể mở tệp!\n");

        return 1;

    }

    printf("Tệp '%s' đã được mở.\n", filename);

    // Tiếp tục thao tác với tệp...

    // Đóng tệp

    fclose(file);

    return 0;

}

Trong ví dụ trên, chúng ta sử dụng hàm fopen() để mở tệp với đường dẫn và tên tệp cần mở. Chúng ta cũng chỉ định chế độ mở tệp là "r" để đọc nội dung của tệp. Sau đó, chúng ta kiểm tra giá trị trả về của hàm fopen() để xác định xem tệp đã được mở thành công hay không. Nếu giá trị trả về là NULL, tức là không thể mở tệp, chúng ta hiển thị một thông báo lỗi và kết thúc chương trình. Ngược lại, nếu giá trị trả về không phải là NULL, tức là tệp đã được mở thành công, chúng ta có thể tiếp tục thực hiện các thao tác khác trên tệp. Cuối cùng, chúng ta sử dụng hàm fclose() để đóng tệp sau khi hoàn thành công việc với tệp.

Lưu ý rằng trong ví dụ trên, chúng ta cần đảm bảo tệp "example.txt" đã tồn tại trong thư mục hiện tại để mở thành công.

B. Đọc dữ liệu từ tệp

Để đọc dữ liệu từ tệp, chúng ta sử dụng hàm fread() hoặc fscanf(). Hàm fread() cho phép chúng ta đọc một khối dữ liệu với kích thước cố định từ tệp, trong khi hàm fscanf() cho phép chúng ta đọc dữ liệu theo định dạng đã cho từ tệp.

Để minh họa cách đọc dữ liệu từ tệp trong ngôn ngữ C, dưới đây là một ví dụ đơn giản:

#include <stdio.h>

int main() {

    FILE *file;

    char *filename = "example.txt";

    char buffer[100];    

    // Mở tệp trong chế độ đọc

    file = fopen(filename, "r");

    // Kiểm tra xem tệp đã mở thành công hay chưa

    if (file == NULL) {

        printf("Không thể mở tệp!\n");

        return 1;

    }

    printf("Nội dung của tệp '%s':\n", filename);

    // Đọc dữ liệu từ tệp và hiển thị ra màn hình

    while (fgets(buffer, sizeof(buffer), file) != NULL) {

        printf("%s", buffer);

    }

    // Đóng tệp

    fclose(file);

    return 0;

}

Trong ví dụ trên, chúng ta sử dụng hàm fopen() để mở tệp với chế độ đọc. Sau đó, chúng ta kiểm tra xem tệp đã mở thành công hay không. Nếu không thể mở tệp, chúng ta hiển thị một thông báo lỗi và kết thúc chương trình. Nếu tệp đã mở thành công, chúng ta sử dụng vòng lặp while và hàm fgets() để đọc từng dòng dữ liệu từ tệp và hiển thị nó ra màn hình. Hàm fgets() đọc dữ liệu từ tệp và lưu vào mảng buffer. Chúng ta sử dụng sizeof(buffer) để chỉ định kích thước của buffer, đảm bảo rằng việc đọc không vượt quá kích thước đã định trước. Cuối cùng, chúng ta sử dụng hàm fclose() để đóng tệp sau khi hoàn thành việc đọc.

Lưu ý rằng trong ví dụ trên, chúng ta cần đảm bảo tệp "example.txt" đã tồn tại trong thư mục hiện tại và chứa dữ liệu để đọc thành công.

C. Ghi dữ liệu vào tệp

Để ghi dữ liệu vào tệp, chúng ta sử dụng hàm fwrite() hoặc fprintf(). Hàm fwrite() cho phép chúng ta ghi một khối dữ liệu vào tệp, trong khi hàm fprintf() cho phép chúng ta ghi dữ liệu theo định dạng đã cho vào tệp.

1.Ghi dữ liệu text vào tệp:

Để ghi dữ liệu text vào tệp trong ngôn ngữ C, chúng ta sử dụng hàm fprintf(). Dưới đây là một ví dụ đơn giản:

#include <stdio.h>

int main() {

    FILE *file;

    char *filename = "example.txt";

    char *content = "Hello, world!";

    

    // Mở tệp trong chế độ ghi

    file = fopen(filename, "w");

    

    // Kiểm tra xem tệp đã mở thành công hay chưa

    if (file == NULL) {

        printf("Không thể mở tệp!\n");

        return 1;

    }

    

    // Ghi dữ liệu vào tệp

    fprintf(file, "%s", content);

    

    // Đóng tệp

    fclose(file);

    

    printf("Đã ghi dữ liệu vào tệp '%s'.\n", filename);

    

    return 0;

}

Trong ví dụ trên, chúng ta sử dụng hàm fopen() để mở tệp với chế độ ghi. Nếu tệp không tồn tại, nó sẽ được tạo mới. Sau đó, chúng ta kiểm tra xem tệp đã mở thành công hay không. Nếu không thể mở tệp, chúng ta hiển thị một thông báo lỗi và kết thúc chương trình. Nếu tệp đã mở thành công, chúng ta sử dụng hàm fprintf() để ghi dữ liệu từ biến content vào tệp. Cuối cùng, chúng ta sử dụng hàm fclose() để đóng tệp sau khi hoàn thành việc ghi.

2. Ghi dữ liệu nhị phân vào tệp:

Để ghi dữ liệu nhị phân vào tệp trong ngôn ngữ C, chúng ta sử dụng hàm fwrite(). Dưới đây là một ví dụ đơn giản:

#include <stdio.h>

int main() {

    FILE *file;

    char *filename = "data.bin";

    int data[] = {1, 2, 3, 4, 5};

    int numElements = sizeof(data) / sizeof(data[0]);

    

    // Mở tệp trong chế độ ghi nhị phân

    file = fopen(filename, "wb");

    

    // Kiểm tra xem tệp đã mở thành công hay chưa

    if (file == NULL) {

        printf("Không thể mở tệp!\n");

        return 1;

    }

    

    // Ghi dữ liệu nhị phân vào tệp

    fwrite(data, sizeof(int), numElements, file);

    

    // Đóng tệp

    fclose(file);

    

    printf("Đã ghi dữ liệu nhị phân vào tệp '%s'.\n", filename);

    

    return 0;

}

Trong ví dụ trên, chúng ta sử dụng hàm fopen() để mở tệp với chế độ ghi nhị phân bằng cách sử dụng "wb". Tiếp theo, chúng ta kiểm tra xem tệp đã mở thành công hay không. Nếu không thể mở tệp, chúng ta hiển thị một thông báo lỗi và kết thúc chương trình. Nếu tệp đã mở thành công, chúng ta sử dụng hàm fwrite() để ghi dữ liệu nhị phân từ mảng "data" vào tệp. Đối số đầu tiên của fwrite() là con trỏ tới dữ liệu cần ghi, đối số thứ hai là kích thước của mỗi phần tử dữ liệu (trong trường hợp này là kích thước của kiểu int), đối số thứ ba là số lượng phần tử cần ghi, và đối số cuối cùng là con trỏ tới tệp mà chúng ta muốn ghi dữ liệu vào. Cuối cùng, chúng ta sử dụng hàm fclose() để đóng tệp sau khi hoàn thành việc ghi.

Trong cả hai ví dụ trên, chúng ta cần kiểm tra trạng thái của tệp sau khi thực hiện các hoạt động đọc/ghi. Điều này giúp đảm bảo rằng chúng ta đã thao tác với tệp thành công và tránh xảy ra lỗi không mong muốn.

3. Đọc dữ liệu file nhị phân :

#include <stdio.h>

int main() {

    FILE *file;

    char *filename = "data.bin";

    int data[5];

    

    // Mở tệp trong chế độ đọc nhị phân

    file = fopen(filename, "rb");

    

    // Kiểm tra xem tệp đã mở thành công hay chưa

    if (file == NULL) {

        printf("Không thể mở tệp!\n");

        return 1;

    }

    

    // Đọc dữ liệu nhị phân từ tệp

    fread(data, sizeof(int), 5, file);

    

    // Đóng tệp

    fclose(file);

    

    // In ra dữ liệu đã đọc

    int i;

    for (i = 0; i < 5; i++) {

        printf("%d ", data[i]);

    }

    printf("\n");

    

    return 0;

}

Trong ví dụ trên, chúng ta sử dụng hàm fopen() để mở tệp trong chế độ đọc nhị phân bằng cách sử dụng "rb". Tiếp theo, chúng ta kiểm tra xem tệp đã mở thành công hay không. Nếu không thể mở tệp, chúng ta hiển thị một thông báo lỗi và kết thúc chương trình. Nếu tệp đã mở thành công, chúng ta sử dụng hàm fread() để đọc dữ liệu nhị phân từ tệp vào mảng "data". Đối số đầu tiên của fread() là con trỏ tới mảng dữ liệu để lưu kết quả, đối số thứ hai là kích thước của mỗi phần tử dữ liệu (trong trường hợp này là kích thước của kiểu int), đối số thứ ba là số lượng phần tử cần đọc, và đối số cuối cùng là con trỏ tới tệp mà chúng ta muốn đọc dữ liệu từ. Cuối cùng, chúng ta sử dụng hàm fclose() để đóng tệp sau khi hoàn thành việc đọc.

Trong ví dụ trên, chúng ta đọc và in ra dữ liệu đã được đọc từ tệp. Bạn có thể thay đổi kích thước của mảng "data" và số lượng phần tử cần đọc trong hàm fread() để phù hợp với tệp dữ liệu nhị phân của bạn.

D. Xử lý lỗi trong quá trình làm việc với tệp

Khi làm việc với tệp, có thể xảy ra các lỗi như tệp không tồn tại, không thể mở tệp, hoặc quyền truy cập bị từ chối. Để xử lý các lỗi này, chúng ta cần kiểm tra kết quả trả về của các hàm thao tác tệp và thực hiện các xử lý phù hợp nếu có lỗi xảy ra.

Dưới đây là một ví dụ về cách xử lý lỗi trong quá trình làm việc với tệp trong ngôn ngữ C:

#include <stdio.h>

int main() {

    FILE *file;

    char *filename = "data.txt";

    int data;

    

    // Mở tệp trong chế độ đọc

    file = fopen(filename, "r");

    

    // Kiểm tra xem tệp đã mở thành công hay chưa

    if (file == NULL) {

        printf("Không thể mở tệp!\n");

        return 1;

    }

    

    // Đọc dữ liệu từ tệp

    if (fscanf(file, "%d", &data) != 1) {

        printf("Lỗi đọc dữ liệu từ tệp!\n");

        fclose(file);

        return 1;

    }

    

    // Đóng tệp

    fclose(file);

    

    // In ra dữ liệu đã đọc

    printf("Dữ liệu: %d\n", data);

    

    return 0;

}

Trong ví dụ trên, chúng ta sử dụng hàm fopen() để mở tệp trong chế độ đọc bằng cách sử dụng "r". Tiếp theo, chúng ta kiểm tra xem tệp đã mở thành công hay không. Nếu không thể mở tệp, chúng ta hiển thị một thông báo lỗi và kết thúc chương trình.

Sau đó, chúng ta sử dụng hàm fscanf() để đọc dữ liệu từ tệp. Hàm fscanf() trả về số lượng phần tử đã được đọc thành công. Trong ví dụ này, chúng ta mong đợi đọc một số nguyên từ tệp, nên nếu hàm fscanf() trả về giá trị khác 1, tức là không đọc được số nguyên, chúng ta hiển thị một thông báo lỗi và kết thúc chương trình.

Cuối cùng, chúng ta sử dụng hàm fclose() để đóng tệp sau khi hoàn thành việc đọc.

Trong ví dụ trên, chúng ta chỉ xử lý lỗi khi không thể mở tệp hoặc không thể đọc dữ liệu từ tệp. Tuy nhiên, trong thực tế, bạn có thể xử lý nhiều loại lỗi khác nhau trong quá trình làm việc với tệp, ví dụ như kiểm tra việc ghi dữ liệu vào tệp, kiểm tra xem tệp đã tồn tại hay không, v.v. Tùy thuộc vào yêu cầu cụ thể của ứng dụng, bạn có thể thêm các điều kiện kiểm tra và xử lý lỗi phù hợp.

E. Đóng tệp

Sau khi hoàn thành công việc với tệp, chúng ta cần đóng tệp bằng cách sử dụng hàm fclose(). Điều này giúp giải phóng tài nguyên hệ thống và đảm bảo rằng dữ liệu được lưu trữ được cập nhật đúng cách.

Trên đây là phần giới thiệu về cách xử lý tệp trong ngôn ngữ C. Qua việc mở, đọc, ghi và đóng tệp, chúng ta có thể thao tác với dữ liệu từ và vào tệp một cách linh hoạt và tiện lợi trong quá trình lập trình.