Tải bản đầy đủ (.doc) (28 trang)

Tài liệu DỮ LIỆU DẠNG FILE pdf

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (186.38 KB, 28 trang )

DỮ LIỆU KIỂU FILE
1. CÁC KIỂU NHẬP XUẤT ĐĨA
a. Nhập/xuất chuẩn với nhập/xuất hệ thống
Có thể phân chia nhập/xuất tập tin của C/C++ thành 2 loại: nhập/xuất chuẩn (hay còn gọi là
nhập/xuất dòng) và nhập/xuất hệ thống (hay nhập/xuất mức thấp). Mỗi loại là 1 hệ thống hoàn chỉnh
để truy xuất đĩa.
 Nhập/xuất hệ thống: thực hiện việc đọc/ghi như DOS. Không có dịch vụ nhập xuất riêng cho
từng kiểu dữ liệu mà chỉ có dịch vụ đọc ghi một dãy các byte. Như vậy để ghi 1 số thực lên đĩa ta
phải dùng dịch vụ ghi 4 byte, để ghi 4 số nguyên ta dùng dịch vụ ghi 8 byte. Mỗi tệp có 1 số hiệu
(handle), làm việc với tệp thông qua số hiệu tệp.
 Nhập/xuất chuẩn: thường được sử dụng hơn vì có nhiều lệnh và sử dụng dễ dàng
- Có dịch vụ truy xuất cho từng kiểu dữ liệu, có hàm nhập xuất ký tự, chuỗi, số nguyên, số
thực, cấu trúc....
- C/C++ tự động cung cấp một vùng đệm, mỗi lần đọc ghi thì thường tiến hành trên vùng đệm
chứ không trên tệp (tức là ghi nào đầy vùng đệm mới được đẩy lên đĩa, đọc thông tin lấy trên
vùng đệm khi nào vùng đệm trống mới lấy dữ liệu từ tệp lên vùng đệm). Việc sử dụng vùng
đệm giảm số lần nhập xuất trên đĩa và nâng cao tốc độ làm việc.
 Đối tệp của hàm là biến con trỏ tệp
b. Nhập/xuất nhị phân và văn bản
Lý do tồn tại 2 kiểu này là do trước đây hệ điều hành UNIX (giai đoạn đầu tiên của ngôn ngữ C) làm
theo 1 cách còn hệ điều hành MS-DOS lại làm theo cách khác.
 Kiểu nhị phân:
- Bảo toàn dữ liệu: trong quá trình nhập xuất dữ liệu không bị biến đổi, dữ liệu ghi trên tệp theo
các byte nhị phân như trong bộ nhớ.
- Mã kết kết thúc tệp: trong khi đọc nếu gặp cuối tệp thì ta nhận được mã kết thúc tệp EOF (định
nghĩa trong stdio.h là -1) và hàm feof cho giá trị khác không. Ta chọn số -1 làm mã kết htúc tệp
bởi vì nếu chưa gặp cuối tệp thì sẽ đọc 1 byte có giá trị từ 0 đến 255. Như vậy giá trị -1 sẽ không
trùng với bất kỳ byte nào đọc được từ tệp.
 Kiểu văn bản:
- kiểu nhập/xuất văn bản chỉ khác kiểu nhị phân khi xử lý ký tự chuyển dòng LF (Line Feed - mã
10) và ký tự mã 26.


- Mã chuyển dòng: khi ghi 1 ký tự LF (mã 10) được chuyển thành 2 ký tự CR (carriage Return -
mã 13) và LF. Khi đọc 2 ký tự liên tiếp CR và LF trên tệp chỉ cho 1 ký tự LF. Còn tệp nhị phân
chỉ ghi lên tệp 1 ký tự mã 10. (để phù hợp với DOS kết thúc bởi 2 mã 13 và 10)
- Mã kết thúc tệp: EOF (số -1) và hàm feof(fp) cho giá trị khác 0 (số 1)
2. NHẬP/XUẤT CHUẨN
Các hàm sử dụng cấu trúc FILE và mã kết thúc EOF, tất cả đều được khai báo và định nghĩa trong
tệp <stdio.h>. Mã EOF bằng (-1) và cấu trúc FILE gồm các thành phần dùng để quản lý tập tin:
- level : cho biết có còn dữ liệu trong vùng đệm không
- bsize: độ lớn vùng đệm (mặc định 512 byte)
- flags : các cờ trạng thái file như tệp chỉ đọc, tệp nhị phân,...
a. Đóng mở tệp
 Hàm fopen: mở tệp
FILE *fopen(const char *tên_tệp, const char *kiểu);
Hàm dùng để mở tệp, nếu thành công hàm cho con trỏ kiểu FILE ứng với tệp vừa mở, nếu có lỗi hàm
Trịnh Vân Anh 86
cho giá trị kiểu NULL.
Đối thứ nhất của fopen là tên của tệp, có dạng một xâu kí tự. Đối thứ hai là mode, cũng là xâu kí tự
chỉ ra cách ta định sử dụng tệp. Các mode sử dụng trong khi mở tệp là:
MODE Ý NGHĨA
“r” “rt”
“w” “wt”
“a” “at”
“r+” “r+t”
“w+”
“w+t”
“a+” “a+t”
“rb”
“wb”
“ab”
“r + b”

“w+b”
“a + b”
Mở file đã tồn tại để đọc theo kiểu văn bản (read only), nếu không tồn tại có lỗi
Mở file mới để ghi theo kiểu văn bản. Nếu file đã tồn tại, nội dung của nó sẽ bị loại
bỏ để thay vào đó nội dung mới
Mở 1 tệp để ghi bổ sung theo kiểu văn bản, nếu tệp chưa tồn tại thì tạo tệp mới
Mở 1 tệp để đọc/ghi theo kiểu văn bản, nếu không tồn tại sẽ báo lỗi
Mở file mới để đọc/ghi theo kiểu văn bản. Nếu file đang tồn tại nội dung của nó sẽ bị
huỷ để thay vào nội dung mới
Mở file để đọc/ghi bổ xung theo kiểu văn bản, nếu tệp chưa tồn tại thì tạo mới
Mở file để đọc theo kiểu nhị phân, nếu tệp không tồn tại sẽ có lỗi
Mở file mới để ghi theo kiểu nhị phân. Nếu file đang tồn tại, nội dung của file bị xoá
bỏ để ghi vào thông tin mới
Mở file nhị phân đang tồn tại để ghi thêm dữ liệu vào cuối file. Nếu file chưa tồn tại,
một file mới sẽ được tạo ra
Mở file nhị phân mới cho đọc/ghi. Nếu file không tồn tại thì báo lỗi
mở 1 tệp mới để đọc/ghi theo kiểu nhị phân, nếu tệp đã tồn tại thì bị xoá
Mở file nhị phân đang tồn tại và ghi thêm dữ liệu vào cuối file. Nếu file chưa tồn tại
thì một file mới sẽ được tạo ra
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 từ ghi
sang đọc. Có thể tên tệp có định đường dẫn, “w” chuỗi chứ không phải là ký tự.
Ví dụ:
FILE *fp;
fp=fopen(“tep_mo.txt”,”w”);
Hàm fclose: đóng tệp
int fclose(FILE *fp);
Hàm dùng để đóng tệp,fd là con trỏ tương ứng với tệp cần đóng.
Nội dung đóng tệp:Đẩy dữ liệu còn trong vùng đệm lên đĩa (khi đang ghi),xoá vùng đệm (khi đang
đọc)
Giải phóng biến fp để dùng cho tệp khác. Nếu thành công hàm cho giá trị 0, ngược lại hàm cho EOF.

Ví dụ: fclose(fp);
Hàm fcloseall: đóng các tệp đang mở
int fcloseall(void);
Đóng tất cả tệp đang mở, thành công hàm cho giá trị nguyên bằng số tệp đóng được, trái lại hàm cho
EOF
Hàm fflush: làm sạch vùng đệm
int fflush(FILE *fp);
Hàm dùng làm sạch vùng đệm của tệp fp, nếu thành công hàm cho giá trị 0, ngược lại hàm cho EOF
Hàm fflushall: làm sạch vùng đệm
int fflushall(void);
Hàm dùng làm sạch vùng đệm của các tệp đang mở, nếu thành công hàm cho giá trị nguyên bằng số
tệp đang mở, ngược lại hàm cho EOF.
Hàm ferror: kiểm tra lỗi
int ferror(FILE *fp);
Hàm kiểm tra lỗi thao tác trên tệp fp, Hàm cho giá trị 0 nếu không lỗi, ngược lại hàm cho giá trị khác
Trịnh Vân Anh 87
0.
 Hàm perror: thông báo lỗi hệ thống
void perror(const char *s);
Hàm đưa ra chuỗi s và thông báo lỗi.
Ví dụ: lỗi vào ra
#include <stdio.h>
#include <string.h>
void main(void)
{
FILE *fp;
char name[30];
if(fp=fopen(“ten_tep.txt”,”w”)==NULL)
{ printf(“\n khong the mo duoc tep ten_tep.txt”); exit();}
do {

fprintf(fp,”%s”,name);
if(ferror(fp))
{ perror(“loi ghi tep:”);
fclose(fp);
exit(); }
} while (strlen(name)>1);
fclose(fp);
}
Kết quả in ra dòng thông báo: Loi ghi tep: Bad data
 Hàm feof: Kiểm tra cuối tệp
int feof(FILE *fp);
Dùng để kiểm tra cuối tệp, hàm cho giá trị khác không gặp cuối tệp khi đọc, ngược lại cho giá trị 0
 Hàm unlink: xoá tệp
int unlink(const char *ten_tep);
Hàm dùng để xoá tệp tin trên đĩa, nếu thành công hàm cho giá trị = 0, ngược lại cho EOF
b. Nhập/xuất ký tự
Các hàm putc và fputc
int putc(int ch,FILE *fp);
int fputc(int ch,FILE *fp);
Ghi ký tự lên tệp, thành công cho mã ký tự được ghi, ngược lại cho EOF.Hai hàm có ý nghĩa như
nhau.
Ví dụ: ghi từng ký tự vào tập tin
#include “stdio.h”
void main(void)
{
FILE *fp; char ch;
fp=fopen(“tep.txt”,”w”);
while ((ch=getche()) != ‘\r’)
putc(ch,fp);
fclose(fp);

}
Các hàm getc fgetc
int getc(FILE *fp);
Trịnh Vân Anh 88
int fgetc(FILE *fp);
Hàm đọc 1 ký tự từ tệp fp, nếu thành công hàm cho mã đọc được (có giá trị từ 0 đến 255). Nếu gặp
cuối tệp hay có lỗi hàm cho EOF.
Chú ý: hai hàm trên có ý nghĩa như nhau, trong kiểu văn bản hàm đọc cả 2 mã 13,10 một lúc và trả
về giá trị 10, khi gặp mã 26 thì không trả về 26 mà trả về EOF.
Ví dụ 1: đọc mỗi lần 1 ký tự từ tập tin
#include “stdio.h”
void main(void)
{
FILE *fp; int ch;
fp=fopen(“tep.txt”,”r”);
while ((ch=getc(fp)) != EOF)
printf(“%c”,ch);
fclose(fp);
}
ví dụ 2: Sao chép tệp nhị phân
#include “stdio.h”
void main(void)
{
FILE f1,f2;
char tep1[12],tep2[12]; int ch;
printf(“\n tep nguon:”); gets(tep1);
printf(“\n tep dich:”); gets(tep2);
f1=fopen(tep1,”rb”);
if (f1==NULL)
{

printf(“\n tep %s chua co”,tep1);
getch();
return;
}
f2=fopen(tep2,”wb”);
while ((ch=fgetc(f1)) != EOF)
fputc(ch,f2);
fclose(f1);
fclose(f2);
}
c. Các hàm nhập/xuất theo kiểu văn bản
Hàm fprintf: ghi dữ liệu theo khuôn dạng
int fprintf(FILE *fp, const char *dk,....);
Giá trị các đối được ghi lên tệp fp theo khuôn dạng xác định trong chuỗi điều khiển dk. Nếu thành
công hàm trả về giá trị nguyên bằng số byte ghi lên tệp, khi có lỗi trả về EOF. Hàm làm việc giống
như printf.
Ví dụ: đưa dữ liệu và tệp
#include <stdio.h>
int main(void)
{
FILE *fp;
Trịnh Vân Anh 89
int i = 100; char c = 'C'; float f = 1.234;
/* open a file for update */
fp = fopen("dl.dat", "w+");
/* write some data to the file */
fprintf(fp, "%d %c %f", i, c, f);
/* close the file */
fclose(fp);
return 0;

}
Ví dụ : đưa dữ liệu nhập từ bàn phím vào tệp
#include “stdio.h”
void main(void)
{
FILE *fp; int i;
fp=fopen(“tep.txt”,”wt”);
fprintf(fp,”Hoc vien cong nghe BCVT 1”);
for(i=1;i<=2;++i)
fprintf(fp,”\n Lop D99 VT %2d”,i);
fclose(fp);
}
Hàm fscanf: đọc dữ liệu từ tệp theo khuôn dạng
fscanf(fp, formats, available_list);
Ví dụ: giả sử có 1 dãy số nguyên ghi trên tệp slieu.dat, giữa 2 số nguyên có ít nhất 1 khoảng trống
hay các dấu xuống dòng. Đọc và in ra màn hình dãy số nguyên đó.
Xét 2 trường hợp:
- Sau chữ số cuối cùng là mã 26 hay cuối tệp
- Sau chữ số cuối cùng có ít nhất 1 khoảng trống hay các dấu xuống dòng
Cách 1:
#include “stdio.h”
void main(void)
{
FILE *fp; int c;
fp=fopen(“slieu.dat”,”r”);
while( !feof(fp))
{
fscanf(fp,”%d”,&c);
printf(“\n %d”,c);
}

fclose(fp);
getch();
}
Cách 2:
#include “stdio.h”
void main(void)
{
FILE *fp; int c;
fp=fopen(“slieu.dat”,”r”);
while(1)
Trịnh Vân Anh 90
{
fscanf(fp,”%d”,&c);
if(feof(fp)) break;
printf(“\n %d”,c);
}
fclose(fp);
getch();
}
Ví dụ: ma trận nghịch đảo
Cho tệp : mtndao.dat có dạng:
- Dòng đầu tiên là số tự nhiên n (cấp của ma trận vuông A)
- n dòng tiếp theo mỗi dòng ghi n số thực phân biệt nhau bởi dấu cách là A[i][j]
Hãy viết chương trình tính ma trận nghịch đảo của ma trận A và viết tiếp vào file trên.
#include <stdio.h>
#include <conio.h>
#include <alloc.h>
FILE *f;
int Chuyen(float **, int ,int);
void Mtdao(float **,int );

int Chuyen(float **A, int n,int i)
{
int j,k;
float t;
for(j=i+1;j<n;j++){
if(A[j][i] !=0){
for(k=0;k<n;k++){
t=A[i][k];
A[i][k]=A[j][k];
A[j][k]=t;
}
return(1);
}
}
return(0);
}
void Mtdao(float **A,int n)
{
int i,j,k;
float hs;
for(i=0;i<n-1;i++){
if(A[i][i]==0){
if(Chuyen(A,n,i)==0){
fprintf(f,"khong ton tai ma tran nghich dao");
return;
}
}
for(j=i+1;j<n;j++){
hs=A[j][i]/A[i][i];
Trịnh Vân Anh 91

for(k=0;k<2*n;k++)
A[j][k]=A[j][k]-A[i][k]*hs;
}
}
for(i=0;i<n;i++){
hs=A[i][i];
for(k=0;k<2*n;k++)
A[i][k]=A[i][k]/hs;
}
for(i=n-1;i>0;i--) {
for(j=i-1;j>=0;j--){
hs=A[j][i]/A[i][i];
for(k=0;k<2*n;k++)
A[j][k]=A[j][k]-A[i][k]*hs;
}
}
for(i=0;i<n;i++){
for(j=0;j<n;j++)
fprintf(f,"%6.1f",A[i][j+n]);
fprintf(f,"\n");
}
}
void main() {
float **A,**B,t;
int i,j,k,n;
clrscr();
f=fopen("mtndao.dat","r");
fscanf(f,"%d",&n);
A=(float **)malloc(n*sizeof(float));
for(i=0;i<n;i++)

A[i]=(float *)malloc(n*sizeof(float));
B=(float **)malloc(n*sizeof(float));
for(i=0;i<n;i++)
B[i]=(float *)malloc(2*n*sizeof(float));
for(i=0;i<n;i++)
for(j=0;j<n;j++){
fscanf(f,"%f",&t);
A[i][j]=t;
}
fclose(f);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
B[i][j]=A[i][j];
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(i==j)
B[i][j+n]=1;
else
Trịnh Vân Anh 92
B[i][j+n]=0;
f=fopen("mtndao.dat","a");
Mtdao(B,n);
fclose(f);
free(A);
free(B);
getch();
}
Hàm fputs: ghi một chuỗi ký tự lên tệp
int fputs(const char *s,FILE *fp);
Ghi chuỗi s lên tệp fp (dấu ‘\0’ không ghi lên tệp. thành công hàm trả về ký tự cuối cùng được ghi

lên tệp, có lỗi hàm trả về EOF.
Ví dụ: ghi các dòng lên tệp
#include “stdio.h”
#include “conio.h”
void main(void)
{
FILE *fp;
int i=0;
char d[256];
fp=fopen(“vanban.dat”,”w”);
clrscr();
while(1)
{
++i;
printf(“\n Dong thu %d(go Enter de thoat):”,i);
gets(d);
if(d[0]==’\0’) break;
if(i>1) fputc(10,fd);
fputs(d,fp);
}
fclose(fp);
getch();
}
Hàm fgets: đọc 1 dãy ký tự từ tệp
char fgets( char *s,int n,FILE *fp); (n là độ dài cực đại của xâu đọc)
Đọc 1 dãy ký tự từ tệp fp chứa các vùng nhớ s, 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 (xâu kết quả sẽ được bổ sung thêm dấu hiệu kết thúc
xâu ‘\0’.
Ví dụ: đọc các dòng ký tự từ tệp và viết ra màn hình
#include “stdio.h”

#include “conio.h”
void main(void)
{
FILE *fp;
int i=0;
char d[256];
fp=fopen(“xau.dat”,”r”);
Trịnh Vân Anh 93
clrscr();
while(!feof(fp))
{
++i;
fgets(d,256,fp);
printf(“\n Lop D99 VT %d : %s”,fp,d););
}
fclose(fp);
getch();
}
Ví dụ:
#include <string.h>
#include <stdio.h>
int main(void)
{
FILE *fp;
char string[] = "This is a test";
char msg[20];
/* open a file for update */
fp = fopen("dl.dat", "w+");
/* write a string into the file */
fwrite(string, strlen(string), 1, stream);

/* seek to the start of the file */
fseek(stream, 0, SEEK_SET);
/* read a string from the file */
fgets(msg, strlen(string)+1, stream);
/* display the string */
printf("%s", msg);
fclose(stream);
return 0;
}
Tệp văn bản và các thiết bị chuẩn
Ngôn ngữ C định nghĩa các tệp và con trỏ tệp ứng với các thiết bị chuẩn:
Tệp con trỏ thiết bị
in
out
err
prn
stdin
stdout
stderr
stdprn
thiết bị vào chuẩn (bàn phím)
thiết bị ra chuẩn (màn hình)
thiết bị lỗi chuẩn (màn hình)
thiết bị in chuẩn (máy in)
Khi chương trình C bắt đầu làm việc thì các tệp này tự động mở, vì vậy có thể dùng các con trỏ trên
để nhập/xuất trên các thiết bị chuẩn.
Ví dụ:
#include “stdio.h”
#include “conio.h”
void main(void)

{
char hten[20];
float diem;
int nsinh;
Trịnh Vân Anh 94
printf(“\n ho va ten: “);fgets(hten,20,stdin);
printf(“\n diem: “); fsanf(stdin,”%f”,&diem);
printf(“\n nam sinh :”);fscanf(stdin,”%d”&nsinh);
fputs(hten,stderr);
fprintf(stdout,”Diem %f nam sinh:%d”,diem,nsinh);
fclose(fp);
getch();
}
d. Các hàm nhập/xuất theo kiểu nhị phân
Hàm putw: ghi 1 số nguyên
int putw(int n, FILE *fp);
Ghi gía trị n lên tệp fp dạng 2byte, thành công hàm trả về số nguyên được ghi, có lỗi trả về EOF.
Hàm getw: đọc 1 số nguyên
int getw(FILE *fp);
Đọc 1 số nguyên (2byte) từ tệp fp, thành công hàm trả về số nguyên đọc được, có lỗi trả về EOF.
Ví dụ: ghi và đọc số nguyên
#include “stdio.h”
#include “conio.h”
void main(void)
{
FILE *fp;
int i;
fp=fopen(“nguyen.dat”,”wb”);
for(i=100;i<=120;++i)
putw(i,fp);

fclose(fp);
clrscr();
fp=fopen(“nguyen.dat”,”rb”);
while(i=getw(fp) !=EOF)
printf(“\n %d”,i);
fclose(fp);
getch();
}
Ví dụ:
#include <stdio.h>
#include <stdlib.h>
#define FNAME "vban.txt"
int main(void)
{
FILE *fp;
int word;
/* place the word in a file */
fp = fopen(FNAME, "wb");
if (fp == NULL)
{
printf("Error opening file %s\n", FNAME);
exit(1);
Trịnh Vân Anh 95
}
word = 94;
putw(word,fp);
if (ferror(fp))
printf("Error writing to file\n");
else
printf("Successful write\n");

fclose(fp);
/* reopen the file */
fp = fopen(FNAME, "rb");
if (fp == NULL)
{
printf("Error opening file %s\n", FNAME);
exit(1);
}
/* extract the word */
word = getw(fp);
if (ferror(fp))
printf("Error reading file\n");
else
printf("Successful read: word = %d\n", word);
/* clean up */
fclose(fp);
unlink(FNAME);
return 0;
}
Hàm fwrite: ghi các số nguyên, số thực hay cấu trúc lên tệp
int fwrite (void *ptr, int size, int n, FILE *fp);
Ghi n phần tử trong đó kích cỡ của mỗi phần tử là size byte từ con trỏ ptr vào tệp được trỏ bởi con
trỏ file fp, hàm trả về giá trị là số phần tử được ghi.
Hàm fread: đọc các số nguyên, số thực hay các cấu trúc từ tệp
int fread (void *ptr, int size, int n, FILE *fp);
Đọc vào con trỏ ptr n phần tử mỗi phần tử có kích cỡ n byte từ tệp được trỏ bởi con trỏ file fp, hàm
trả lại số phần tử thực sự được đọc.
Ví dụ:
#include <stdio.h>
struct mystruct

{
int i;
char ch;
};
int main(void)
{
FILE *fp;
struct mystruct s;
if ((fp = fopen("thu.txt", "wb")) == NULL) /* open file thu.txt */
{
fprintf(stderr, "Cannot open output file.\n");
Trịnh Vân Anh 96

×