Công dụng: dùng để mở tập tin, nếu thành công sẽ trả về con trỏ kiểu FILE ứng với tập tin vừa mở, nếu có lỗi trả về NULL.. Công dụng : dùng để đóng tập tin, bao gồm các công việc : - Đẩy
Trang 1Ch−¬ng VIII DỮ LIỆU KIỂU TẬP TIN (FILE)
I Khái niệm:
Để lưu trữ vĩnh viễn dữ liệu ta phải lưu trữ lên thiết bị nhớ ngoài của máy tính như đĩa, băng từ, Khi lưu như vậy thì nhóm dữ liệu đó gọi là tập tin (file)
File là một kiểu dữ liệu có cấu trúc, bao gồm tập hợp các phần tử dữ liệu có cùng kiểu được nhóm lại với nhau tạo thành một dãy Một file gồm các byte được ghi trong các bộ nhớ ngoài (đĩa từ, băng từ ) File có tên và độ dài của nó chính bằng số byte của dãy
Một tập tin bất kỳ có thể được ấn định là tập tin văn bản, cũng có thể là tập tin nhị phân Việc ấn định như vậy phụ thuộc vào mục đích sử dụng tập tin và phụ thuộc vào cách khai báo kiểu truy cập khi mở tập tin
- Tập tin dữ liệu nhị phân : Dữ liệu trên file nhị phân giống như ở trong bộ nhớ
- Tập tin dữ liệu văn bản : Khác với file nhị phân khi xử lí mã chuyển dòng :
+ Khi ghi giá trị LF thì chuyển thành 2 giá trị là CR và LF
+ Khi đọc 2 giá trị CR và LF thì chuyển thành LF
Trong đó CR (mã 13) : về đầu dòng; LF (mã 10) : xuống dòng
Các bước xử lí file :
- Khai báo biến file FILE *con_trỏ_file;
- Mở để ghi hoặc đọc con_trỏ_file=fopen(tên_file, kiểu_xử_lí );
- Ghi hoặc đọc file
- Đóng file fclose(con_trỏ_file);
Có 5 tệp chuẩn : stdin, stdout, stdprn, stderr, stdlog
II Các hàm xử lí tập tin trong C :
II.1 Các hàm dùng chung cho cả 2 kiểu nhị phân và văn bản
• Hàm fopen:
Mẫu : FILE *fopen(const char *tên_file,const char *kiểu_xử_lí);
Trong đó : tên_file: là đường dẫn tới file trên đĩa
kiểu_xử_lí : là xâu với các ý nghĩa sau : Kiểu
Đối với tập
tin văn bản
Đối với tập
“r” “rt” “rb” Mở file đã tồn tại để đọc, nếu không trả về lỗi
“w” “wt” “wb” Mở file mới để ghi, nếu file đã tồn tại nó sẽ bị xóa
“a” “at” “ab” Mở file để ghi bổ sung, nếu chưa tồn tại thì tạo file mới
“r+” “r+t” “r+b” Mở file để đọc/ghi, nếu file không tồn tại sẽ báo lỗi
“w+” “w+t” “w+b” Mở file mới để đọc/ghi, nếu đã tồn tại nó sẽ bị xóa
“a+” “a+t” “a+b” Mở file để đọc/ghi bổ sung, nếu chưa tồn tại thì tạo file mới
Trang 2Công dụng: dùng để mở tập tin, nếu thành công sẽ trả về con trỏ kiểu FILE ứng với tập tin vừa mở, nếu có lỗi trả về NULL
Chú ý : Trong các kiểu đọc ghi, cần làm sạch vùng đệm trước khi chuyển từ đọc sang ghi hoặc ghi sang đọc nhờ hàm fflush hoặc hàm dịch chuyển vị trí con trỏ
• Hàm fclose:
Mẫu : int fclose(FILE *tên_trỏ_file);
Trong đó : tên_trỏ_file là con trỏ tương ứng với tập tin cần đóng
Công dụng : dùng để đóng tập tin, bao gồm các công việc :
- Đẩy dữ liệu còn trong vùng đệm lên đĩa (khi ghi)
- Xóa vùng đệm (khi đọc)
- Giải phóng biến tên_trỏ_file, nếu thành công trả về giá trị 0, nếu không : EOF
• Hàm fcloseall:
Mẫu : int fcloseall(void);
Công dụng : đóng tất cả các tập tin đang mở, nếu thành công trả về giá trị bằng số tập tin đóng được, nếu không trả về giá trị EOF
• Hàm fflush:
Mẫu : int fflush(FILE * tên_trỏ_file);
Trong đó : tên_trỏ_file là con trỏ tương ứng với tập tin đang xử lí
Công dụng : làm sạch vùng đệm của tập tin, nếu thành công trả về giá trị 0, nếu không trả về EOF
• Hàm fflushall:
Mẫu : int fflushall(void);
Công dụng : làm sạch tất cả vùng đệm của các tập tin đang mở, nếu thành công trả về giá trị bằng số tập tin được làm sạch, nếu không trả về giá trị EOF
• Hàm ferror
Mẫu : int ferror(FILE * tên_trỏ_file);
Trong đó : tên_trỏ_file là con trỏ tương ứng với tập tin đang xử lí
Công dụng : kiểm tra lỗi thao tác trên tập tin, nếu không có lỗi trả về giá trị 0, nếu có lỗi trả về giá trị khác 0
• Hàm perror:
Mẫu : void perror(const char *s);
Trong đó s là con trỏ trỏ tới chuỗi kí tự
Công dụng : in chuỗi s và thông báo lỗi
• Hàm feof:
Mẫu : int feof(FILE * tên_trỏ_file);
Trong đó : tên_trỏ_file là con trỏ tương ứng với tập tin đang xử lí
Công dụng : kiểm tra kết thúc tập tin, trả về giá trị khác 0 nếu gặp cuối tập tin khi đọc, nếu không trả về giá trị 0
• Hàm unlink:
Mẫu : int unlink(FILE * tên_trỏ_file);
Trong đó : tên_trỏ_file là con trỏ tương ứng với tập tin cần xóa
Công dụng : xóa tập tin trên đĩa, nếu thành công trả về giá trị 0, nếu không : EOF
Trang 3• Hàm remove:
Mẫu : remove(const char * tên_trỏ_file);
Trong đó : tên_trỏ_file là con trỏ tương ứng với tập tin cần xóa
Công dụng : xóa tập tin trên đĩa, hàm này là một macro gọi tới hàm unlink
Các hàm này dùng cho cả 2 kiểu nhị phân và văn bản nhưng có vài điểm khác nhau
• Hàm rename:
Mẫu : rename(const char *f1,const char *f2);
Công dụng : Đổi tên tệp f1 thành tệp f2
• Hàm putc và fputc:
Mẫu : int putc(int ch, FILE *con_trỏ_file);
int fputc(int ch, FILE *con_trỏ_file);
trong đó ch là một số nguyên, con_trỏ_file là con trỏ tương ứng với tập tin đang xử lí Công dụng : ghi lên tập tin kí tự có mã bằng m=ch%256 (ch được xem như không dấu) Nếu thành công trả về giá trị mã kí tự được ghi, nếu không trả về giá trị EOF
• Hàm getc và fgetc:
Mẫu : int getc(FILE *con_trỏ_file);
int fgetc(FILE *con_trỏ_file);
trong đó con_trỏ_tập tin là con trỏ tương ứng với tập tin đang xử lí
Công dụng : đọc kí tự từ tập tin, nếu hết tập tin thì trả về EOF
II.2 Các hàm di chuyển con trỏ chỉ vị trí:
Các file đang mở có 1 con trỏ chỉ vị trí (File Position Locator) dùng để xác định vị trí đọc ghi trên file
• Hàm rewind:
Mẫu : rewind(FILE f);
Công dụng : Trở về đầu tệp đang mở
• Hàm ftell:
Mẫu : long ftell(FILE f);
Công dụng : Cho biết vị trí hiện tại của con trỏ tệp (vị trí tính theo byte, bắt đầu từ 0, cho -1L nếu có lỗi)
• Hàm fseek:
Mẫu : int fseek(f, long n, int xuatphat);
Công dụng : Dịch chuyển n byte kể từ vị trí xuất phát (cho khác 0 nếu có lỗi)
+ fseek(f,0,SEEK_SET); trở về đầu tệp + fseek(f,0,SEEK_END); trở về cuối tệp + fseek(f,k,SEEK_CUR); dịch chuyển k byte kể từ vị trí con trỏ hiện thời
II.3 Các hàm nhập xuất kiểu văn bản:
• Hàm fprintf:
int frintf(FILE *f, const char *đk,dsđs);
Công dụng : Ghi giá trị danh sách các đối số (dsđs) lên tệp f theo khuôn dạng được chỉ định trong chuỗi điều khiển (đk)
Trang 4• Hàm fscanf:
int fscanf(FILE *f, const char *đk, dsđs);
Công dụng : Đọc dữ liệu từ tệp f theo khuôn dạng được xác định trong chuỗi điều khiển đk và kết quả được lưu vào trong danh sách các đối số (dsđs)
• Hàm fputs:
int fputs(const char *s, FILE *f);
Trong đó : s là con trỏ trỏ đến địa chỉ đầu của một chuỗi ký tự
f là con trỏ tệp
Công dụng : Ghi chuỗi s lên tệp f (dấu ‘\0’ không ghi lên tệp) Khi thành công hàm trả về ký tự cuối cùng được ghi lên tệp Khi có lỗi hàm cho EOF
• Hàm fgets:
char *fgets(char *s, int n, FILE *f);
Trong đó : s là con trỏ trỏ đến vùng nhớ đủ lớn để chứa chuỗi ký tự đọc từ tệp
n là độ dài cực đại của dãy cần đọc
f là con trỏ tệp
Công dụng : Đọc dãy ký tự từ tệp f và chứa vào vùng nhớ s Khi thành công, hàm trả lại địa chỉ vùng nhận kết quả Khi có lỗi hoặc gặp cuối tệp, hàm cho giá trị NULL
Ví dụ : #include <stdio.h>
#include <ctype.h>
void main()
{ FILE *f;
char ch;
f=fopen("a.txt","w");
do
putc(toupper(ch=getchar()),f);
while(ch!='\n');
fclose(f);
}
Ví dụ: #include <stdio.h>
#include <ctype.h>
void main()
{ FILE *f;
char ch;
if((f=fopen("a.txt","r"))==NULL)
printf("\nKhong mo duoc file");
else
do
putchar(ch=getc(f));
while(ch!='\n');
fclose(f);
}
Trang 5Ví dụ : Viết chương trình nhập theo kiểu văn bản
#include <stdio.h>
#include <conio.h>
void main()
{ FILE *f;
int i,n;
float a;
f=fopen("a.txt","w");
printf("Nhap n :");scanf("%d",&n);
fprintf(f,"%d\n",n);
for(i=0;i<n;i++)
{ scanf("%f",&a);
fprintf(f,"%f\n",a);
}
fclose(f);
getch();
}
Ví du:Viết chương trình xuất theo kiểu văn bản
#include <stdio.h>
#include <conio.h>
void main()
{ FILE *f;
int i,n;
float a;
f=fopen("a.txt","r");
fscanf(f,"%d",&n);
for(i=0;i<n;i++)
{ fscanf(f,"%f",&a);
printf("\n%f",a);
}
fclose(f);
getch();
}
Ví dụ 3: Mở một tệp văn bản và in ra tần suất xuất hiện của bảng chữ cái
#include <stdio.h>
#include <conio.h>
#include <alloc.h>
#include <string.h>
#define N 256
void main()
Trang 6{ int i;
FILE *f;
static unsigned tso[26];
char *s;
clrscr();
f=fopen("a.txt","rt");
s=(char *)malloc(N);
while (!feof(f))
{ fgets(s,N,f);
strupr(s);
for(i=0;i<strlen(s);i++)
if ((s[i]>'A') && (s[i]<='Z'))
tso[s[i]-'A']++;
}
free(s);
printf("\n Cac chu cai trong tap tin :");
for(i=0;i<26;i++)
if (tso[i])
printf("\n %d chu %c",tso[i],i+'A');
getch();
}
II.4 Các hàm nhập xuất kiểu nhị phân:
• Hàm putw:
int putw(int n, FILE *f);
Công dụng : Ghi giá trị n lên tệp f dưới dạng 2 byte Nếu thành công hàm trả về số nguyên cần ghi Khi có lỗi hàm trả về EOF
• Hàm getw:
int getw(FILE *f);
Công dụng : Đọc một số nguyên 2 byte từ tệp f Nếu thành công hàm trả về số nguyên được đọc Khi có lỗi hoặc gặp cuối tệp hàm trả về EOF
• Hàm fwrite:
int fwrite(void *ptr, int size, int n, FILE *f);
Công dụng : Ghi n mẫu tin, mỗi mẫu tin cóï kích thước size byte từ vùng nhớ ptr lên tệp f
• Hàm fread:
int fread(void *ptr, int size,int n, FILE *f);
Công dụng : Đọc n mẫu tin, mỗi mẫu tin có kích thước size byte từ tệp f và chứa vào vùng nhớ ptr
Trang 7Ví dụ: Copy tệp từ tệp nguồn sang tệp đích
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#define N 1
void main()
{ int i;
char t1[20],t2[20],a[N];
FILE *f1,*f2;
printf("Nhap ten tep nguon:"); scanf("%s",t1);
printf("Nhap ten tep dich:"); scanf("%s",t2);
f1=fopen(t1,"rb");
if (f1==NULL)
{ printf("Tep %s khong ton tai",t1);
getch();
exit(1);
}
f2=fopen(t2,"wb");
while ((fread(a,1,N,f1)) >0)
fwrite(a,1,N,f2);
fclose(f1);fclose(f2);
getch();
}
Ví dụ2: Viết chương trình ghi cấu trúc lên đĩa
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
#include <stdlib.h>
void main()
{ char so[20];
FILE *f;
struct person
{ char ten[25];
int maso;
int diem;
} sv;
clrscr();
if ((f=fopen("a.txt","wb"))==NULL)
{ printf("Khong mo duoc tep");
getch();
exit(1);
Trang 8}
do
{ fflush(stdin);
printf("Nhap ho ten :");gets(sv.ten);
printf("Ma so :");scanf("%d",&sv.maso);
printf("Diem :");scanf("%d",&sv.diem);
fwrite(&sv,sizeof(sv),1,f);
printf("Tiep tuc khong (C/K)?");
}
while(toupper(getch())=='C');
fclose(f);
}
Ví dụ3: Viết chương trình đọc cấu trúc từ đĩa
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
void main()
{ char so[20];
FILE *f;
struct person
{ char ten[25];
int maso;
int diem;
} sv;
clrscr();
if ((f=fopen("a.txt","rb"))==NULL)
{ printf("Khong mo duoc tep");
getch();
exit(1);
}
while(fread(&sv,sizeof(sv),1,f)==1)
{ printf("\n Ten %s",sv.ten);
printf(" Ma so %d",sv.maso);
printf(" Diem %d",sv.diem);
}
fclose(f);
getch();
}
Trang 9Ví dụ : Đọc số liệu vào 2 ma trận(n*n) từ hai tệp “a.txt” và “b.txt” Tính C=A*B và ghi vào tệp “c.txt”
#include <stdio.h>
FILE *f;
int n, a[10][10], b[10][10], c[10][10];
void main()
{ int i, j, k;
printf("Nhap n"); scanf("%d",&n);
f=fopen("a.txt","rb");
for(i=0; i<n;i++)
for(j=0;j<n;j++)
fscanf(f,"%d",&a[i][j]);
fclose(f);
f=fopen("b.txt","rb");
for(i=0; i<n;i++)
for(j=0;j<n;j++)
fscanf(f,"%d",&b[i][j]);
fclose(f);
for(i=0; i<n;i++)
for(j=0;j<n;j++)
{ c[i][j]=0;
for(k=0;k<n;k++)
c[i][j]+=a[i][k]*b[k][j];
}
f=fopen("c.txt", "wb");
for(i=0; i<n;i++)
for(j=0;j<n;j++)
fprintf(f," %d",c[i][j]);
fclose(f);
}
III Bài tập:
1 Kiểm tra hai tệp có nội dung như nhau không
2 Nối hai tệp thành một tệp tin mới
3 Loại bỏ các câu chú thích trong chương trình C
4 Kiểm tra lỗi cú pháp như các dấu ngoặc (), [], {}, ‘ ’, “ ”, các chú thích