Bài 13. Tệp tin (FILE)

Khái niệm tệp tin (file)

Trong các chương trình trước thì các dữ liệu đưa vào chương trình chỉ được tồn tại trong RAM, khi thoát chương trình thì tất cả dữ liệu đều bị mất. Để khắc phục tình trạng này Borland C cung cấp cho ta các hàm để lưu trữ và truy xuất tệp tin (cũng gọi là tập tin), đó là kiểu FILE.

Có 2 loại tệp tin thường dùng:

- Tệp tin văn bản: là tệp tin dùng để ghi các ký tự lên đĩa theo các dòng.

- Tệp tin nhị phân: là tệp tin dùng để ghi các cấu trúc dạng nhị phân (được mã hoá).


Các thao tác cơ bản với tệp tin

Quá trình thao tác trên tệp tin gồm 4 bước:

   Bước 1: Khai báo con trỏ trỏ đến tệp tin.

   Bước 2: Mở tệp tin.

   Bước 3: Các xử lý trên tệp tin.

   Bước 4: Đóng tệp tin.

- Cụ thể từng bước:

B1: Khai báo  

FILE *< tên biến >;

  Ví dụ:

//  Khai bao bien con tro file f
    FILE *f;  

B2. Mở tệp tin

fopen (< đường dẫn tên tệp tin> , < kiểu truy nhập >);

  Ví dụ:

 //Khai bao bien con tro f
   FILE *f;

 // Mo tep tin VD1.txt trong C:\
   f = fopen ("C:\\VD1.txt","rt") ;

Các kiểu truy nhập tệp tin thông dụng: 

  t: kiểu truy nhập tệp tin đối với dạng tệp tin văn bản (text).

  b: kiểu truy nhập tệp tin đối với dạng tệp tin nhị phân (binary).

  r: mở ra để đọc ( ready only).

  w: mở ra để ghi (create / write).

  a: mở ra để thêm vào (append).

  r+:  mở ra để đọc và ghi (modify).

B3.  Các hàm đọc ghi nội dung tệp tin

  1. Tệp tin văn bản

  a. Đọc tệp tin  

  + Đọc dữ liệu từ một tệp tin theo định dạng.  

fscanf(<FILE *>, <định dạng>, <các tham biến>);

Ví dụ:

fscanf(f, "%d", &x);

 + Đọc một chuỗi ký tự từ một tệp tin với kích thước tối đa cho phép, hoặc gặp ký tự xuống dòng.

fgets(<vùng nhớ>, <kích thước tối đa>, <FILE *>);

Ví dụ:

   char s[80];
   fgets(s, 80, f);

+ Đọc một ký tự từ tệp tin đang mở:

getc(< FILE * >);

Ví dụ:

char c=getc(f);

  b. Ghi tệp tin

  + Ghi dữ liệu theo một định dạng nào đó vào tệp tin.

fprintf(<FILE *>, <định dạng>[, <các tham biến>]);

  Ví dụ:

   fprintf(f,“%d”,x);

  + Ghi một chuỗi ký tự vào tệp tin đang mở.

fputs(<chuỗi ký tự>, <FILE*>);

  Ví dụ:

   fputs("Giao trinh BT", f);

  2. Tệp tin nhị phân

  a. Đọc tệp tin

fread(<&ptr>, <size>, <len>, <FILE *>);

   Trong đó:

    ptr: vùng nhớ để lưu dữ liệu đọc.

    size: kích thước mỗi ô nhớ (tính bằng byte).

    len: độ dài dữ liệu cần đọc.

    FILE: đọc từ tệp tin nhị

  Ví dụ:

   int a[30], b, n;
   fread(a,sizeof(int), n , f);
   fread(&b, sizeof(int), 1 , f);

  b. Ghi tệp tin

fwrite(<&prt>, <size>, <len>,<FILE *> );

   Trong đó:

    ptr: vùng nhớ để lưu dữ liệu ghi.

    size: kích thước mỗi ô nhớ (tính bằng byte).

    len: độ dài dữ liệu cần ghi.

    FILE: ghi vào tệp tin nhị

  Ví dụ:

   fwrite(a, sizeof(int), n , f);

B4.  Đóng tệp tin

Sau khi không còn làm việc với tệp tin, để đảm bảo an toàn cho dữ liệu thì nhất thiết ta phải đóng tệp tin lại.

fclose (<biến con trỏ tệp tin>);

hoặc

fcloseall ();

Ví dụ : 

  fclose (f)  ;

Các thao tác khác trên tệp tin

* Xoá tệp tin:

remove ( < đường dẫn tệp tin> );

* Đổi tên tệp tin:

rename ( < tên tệp tin cũ >, < tên tệp tin mới > );

* Di chuyển con trỏ tệp tin :

fseek ( < FILE * >, < độ dời >, < mốc > );

Các mốc :

  SEEK_SET dời dến đầu tệp tin  (giá trị 0).

  SEEK_END dời đến cuới tệp tin  (giá trị 2).

  SEEK_CUR dời vị trí hiện hành  (giá trị 1).

Ví dụ : 

  // dời vị trí hiện hành về cuối 5 bytes
  feek ( f , +5 , SEEK_CUR ); 

  // dời vị trí hiện hành về trước 4 bytes
  feek ( f, -4 , SEEK_CUR );

* Cho biết vị trí con trỏ file:

ftell ( < FILE *  > );

  Ví dụ :

  int size = ftell ( f );
   /*size: khoảng cách từ đầu tệp tin đến vị trí hiện hành (tính bằng byte)*/

Ví dụ 1:

+ Yêu cầu: Viết chương trình

   - Nhập vào 2 số nguyên từ bàn phím, ghi 2 số vừa nhập vào tệp tin D:\test.txt

   - Đọc 2 số nguyên trong tệp tin D:\test.txt , tính tổng của chúng.

+ Code:

#include<conio.h>
#include<stdio.h>
#include<iostream>

using namespace std;

int n, m;

// ghi 2 so nguyen vao file
void GhiFile()
{
   FILE *f;
   // mo file
   f = fopen ("D:\\test.txt" ,"wt");    
   // Nhap n,M tu ban phim
   cout<<"\n n = "; cin>>n;
   cout<<"\n m = "; cin>>m;
   // ghi n, m vao file
   fprintf (f, "%d %d",n,m);
   // dong file
   fclose (f);
}

// Doc du lieu tu file test, tinh tong 2 so
void DocFile()
{
   FILE *f;
   // mo file
   f = fopen ("D:\\test.txt" , "rt" );
   // doc du lieu
   fscanf(f, "%d %d", &n, &m );
   // Tinh tong
   int s=n+m;
   // In tong
   cout<<"\n Tong: "<<s;
   // dong file 
   fclose (f);
}

// ham main
int main ()
{
   GhiFile();
   DocFile();

return 0;
}

Ví dụ 2:

+ Yêu cầu: Viết chương trình

  - Đọc file input.txt (dữ liệu đồ thị)

  Ví dụ:

  Đơn đồ thị vô hướng 3 đỉnh, có ma trận kề được lưu thành tệp tin có nội dung như sau:

  3

  0 1 1

  1 0 1

  1 1 0

  - Tìm số thành phần liên thông.

+ Code:

#include<conio.h>
#include<stdio.h>
#include<iostream>

using namespace std;

//doc du lieu tu tap tin
void Doc_File(int **A,int &n) {
  FILE*f = fopen("input.txt","rb");
  fscanf(f,"%d",&n);
  *A = new int [n];
  cout<<"Ma Tran Lien Ket Cua Do Thi";
  for(int i =0;i<n;i++) { 
  A[i] = new int [n];
  cout<<endl;
  for(int j =0;j<n;j++) { 
  fscanf(f,"%d",&A[i][j]);
  cout<<" "<<A[i][j];
  }
  }
  fclose(f);
}

//ham tra ve so thanh phan lien thong cua do thi
int TPLien_Thong(int **A, int n) {
  char*DanhDau = new char [n];
  char ThanhCong;
  int Dem=0, i,j, MLT=0;
  //khoi tao cac dinh chua danh dau
  for( i = 0; i<n; i++)
  DanhDau[i] = 0;
  do { 
  j = 0;
  //tim 1 dinh chua duoc danh dau
  while(DanhDau[j]==1)
      j++;
      //danh dau dinh tim duoc       
  DanhDau[j] = 1;
  //tang so dinh danh dau len 1
  Dem++;
  //tang so thanh phan lien thong len 1
  MLT++;
  do {
      ThanhCong =0;
      for(i = 0; i<n; i++)
      if(DanhDau[i]==1)
      for(j = 0; j<n; j++)
      if (DanhDau[j] == 0 && A[i][j] > 0) {
        DanhDau[j] = 1;
        ThanhCong =1;
      Dem++;
      if(Dem == n) return MLT;
      }
      }while (ThanhCong == 1);   
       //lap lai khi con dinh chua duoc danh dau
      }  while(Dem<n);
   return MLT;
}

//ham main
int main() {
  int **A,n;
  Doc_File(A,n);
  cout<<"\nTHANH PHAN LIEN THONG: "<<TPLien_Thong(A,n);
  delete *A;

return 0;
}

Ví dụ 3:

+ Yêu cầu: Viết một chương trình để quản lý các sản phẩm máy tính xách tay bao gồm các chức năng sau

Chức năng 1 : Sản phẩm nhập khẩu.

Chức năng 2 : Sắp xếp sản phẩm.

Chức năng 3 : Tìm kiếm sản phẩm.

Trong đó:

* Chức năng 1:

  – Yêu cầu người sử dụng bao nhiêu sản phẩm cần nhập khẩu , sau đó cho phép người dùng nhập thông tin cho các sản phẩm bao gồm:

    Mã sản phẩm

    Tên sản phẩm

    Số lượng sản phẩm

    Giá sản phẩm

  - Chúng được lưu trong một file văn bản có tên là "Products.txt".

  Ví dụ: "Products.txt" tệp tin

  Mã Tên Số lượng Giá ( triệu )

  01 Asus Vivo 3 12

  02 Vaio E 2 10

  03 Acer X 4 11.5

* Chức năng 2:

  Cho phép người dùng đọc tệp tin "Products.txt" ; sắp xếp sản phẩm theo giá sản phẩm, và sau đó lưu các tệp tin.

* Chức năng 3:

  Người dùng có thể tìm kiếm sản phẩm từ tệp tin ” Products.txt” theo mã sản phẩm hoặc tên sản phẩm và thông tin sản phẩm phù hợp .

+ Code:

#include<conio.h>
#include<stdio.h>
#include<iostream>
#include <stdlib.h>
#include <string.h>

#define fio "Products.txt"

#define fbin "Products.dat"

using namespace std;

typedef struct products{ 
  char Id[50], name[50];
  int quantity; // so luong 
  double cost; // gia 
} product;

void input(product prd[], int *n);
void writeBin(product prd[], int n);
void write(product prd[], int n);
void sort_cost(product prd[], int n);
void readBin(product prd[], int *n);
void output(product prd[], int n);
void search_id(product prd[], int n, char id[]);
void search_name(product prd[], int n, char name[]);
void search(product prd[], int n);

// ham main
int main() {
  product prd[50];
  int n, i;
  FILE *f = fopen(fio, "r"); 
  int select;
  do {
  printf("Products:\n-----------------\n");
  printf("1: input\n2: read and sort by cost\n3: Search\n4: exit\n");
  printf("Enter the number to work: ");
  scanf("%d", &select);
  switch(select){
  case 1: {
     printf("1: INPUT\n");
     input(prd, &n);
     write(prd, n);
     break;

  }
  case 2: {
     printf("2: READ AND SORT BY COST\n");
     printf("Befor sort:\n--------------\n");
     readBin(prd, &n);
     output(prd, n);
     sort_cost(prd, n);
     write(prd, n);
     printf("After sort:\n--------------\n");
     readBin(prd, &n);
     output(prd, n);
     break;
  }
  case 3: {
     printf("SEARCH\n");
     search(prd, n);
     break;
  }
  case 4: return 0;
  default : printf("Error select !"); break;
  }
  }
  while (select != 4);
  return 0;
}

// ham input
void input(product prd[], int *n){
  int i;
  char s[50];
  printf("Enter the number of products: ");
  scanf("%d", n);
  gets(s);
  printf("\n");
  for (i = 0; i < (*n); i++){
  printf("Enter the Id of products %d : ", i+1);
  gets(prd[i].Id);
  printf("\tEnter the nam of products %d : ", i+1);
  gets(prd[i].name);
  printf("\tEnter the quantity of products %d : ", i+1);
  scanf("%d", &prd[i].quantity);
  printf("\tEnter the cost of products %d : ", i+1);
  scanf("%lf", &prd[i].cost);
  gets(s);
  }
}

// ghi
void writeBin(product prd[], int n){
  FILE *f = fopen(fbin,"wb");;
  int i;
  if(f==NULL) printf("Error load file");
  else fwrite(prd,sizeof(product),n,f);
  fclose(f);
}

void write(product prd[], int n){
  int i;
  FILE *f = fopen(fio, "w");
  if(f==NULL) printf("Error load file");
  fprintf(f, "%-10s %-15s %-10s %-10s\n", "Id", "Name", "Quantity", "Cost");
  for (i = 0; i < n; i++)
  fprintf(f, "%-10s %-15s %-10d %-10.2lf\n", prd[i].Id, prd[i].name, prd[i].quantity, prd[i].cost);
  fclose(f);
  writeBin(prd, n);
  printf("input and write success to file!\n");
}

void sort_cost(product prd[], int n){
  int i, j;
  for (i = 0; i < n - 1; i++){
  for (j = i + 1; j < n; j++){
  if (prd[i].cost > prd[j].cost){
  product temp = prd[i];
  prd[i] = prd[j];
  prd[j] = temp;
  }
  }
  }
}

void output(product prd[], int n){
  int i;
  printf("%-10s %-10s %-15s %-10s %-10s\n", "Order", "Id", "Name", "Quantity", "Cost");
  for (i = 0; i < n; i++)
  printf("%-10d %-10s %-15s %-10d %-10.2lf\n", i + 1, prd[i].Id, prd[i].name, prd[i].quantity, prd[i].cost);
}

void readBin(product prd[], int *n){
  FILE *f = fopen(fbin,"rb");
  fseek(f,0,SEEK_END); //Nhay ve cuoi file, di chuyen di 0 vi tri
  (*n) = (ftell(f)+1)/sizeof(product); //ftell(); tra ve vi tri hien tai cua con tro
  // SEEK_CUR: di chuyen bat dau tu vi tri hien tai cua con tro, chi dung trong fseek()
  fseek(f,0,SEEK_SET); //Nhay ve dau file, di chuyen di 0 vi tri
  fread(prd,sizeof(product),(*n),f);
  fclose(f);
}

void search_id(product prd[], int n, char id[]){
  int i, check = 0;
  for (i = 0; i < n; i++){
  if (strcmp(id, prd[i].Id) == 0){
  check = 1;
  printf("%-10s %-10s %-15s %-10s %-10s\n", "Order", "Id", "Name", "Quantity", "Cost");
  printf("%-10d %-10s %-15s %-10d %-10.2lf\n", i + 1, prd[i].Id, prd[i].name, prd[i].quantity, prd[i].cost);
  break;
  }
  if (check == 0 && i == n - 1)
  printf("Not found product have Id is %s !\n", id);
  }
}

void search_name(product prd[], int n, char name[]){
  int i, check = 0;
  for (i = 0; i < n; i++){
  if (strcmp(name, prd[i].name) == 0){
  check = 1;
  printf("%-10s %-10s %-15s %-10s %-10s\n", "Order", "Id", "Name", "Quantity", "Cost");
  printf("%-10d %-10s %-15s %-10d %-10.2lf\n", i + 1, prd[i].Id, prd[i].name, prd[i].quantity, prd[i].cost);
  break;
  }
  if (check == 0 && i == n - 1)
  printf("Not found product have name is %s !\n", name);
  }
}

void search(product prd[], int n){
  int select;
  char s[50];
  do{
  printf("\t1: Id\n\t2: Name\n\t3: exit search\nEnter the type you want search: ");
  scanf("%d", &select);
  gets(s);
  switch(select){
  case 1: {
  printf("Enter Id want search: ");
  char id[50];
  gets(id);
  search_id(prd, n, id);
  break;
  }
  case 2: {
  printf("Enter name want search: ");
  char name[50];
  gets(name);
  search_name(prd, n, name); break;
  }
  case 3: return;
  default : printf("Error select !"); break;
  }
  }while (select != 3);
}