Thứ Ba, 7 tháng 12, 2021
Hàm feof()
Khi một tập tin được mở để đọc ở dạng nhị phân, một số
nguyên có giá trị tương đương với EOF có thể được đọc. Trong trường hợp này,
quá trình đọc sẽ cho rằng đã đến cuối tập tin, mặc dù chưa đến cuối tập tin thực
sự. Một hàm feof() có thể được dùng những trong trường hợp này.
Nguyên mẫu của hàm là:
```
int feof(FILE *fp );
```
Nó trả về true nếu đã đến cuối tập tin, nếu không nó trả về
false (0). Hàm này được dùng trong khi đọc dữ liệu nhị phân.
Đoạn lệnh sau đây đọc một tập tin nhị phân cho đến cuối tập
tin.
```
while (!feof(fp) )
ch = fgetc(fp);
```
Hàm rewind()
Hàm rewind() đặt lại con trỏ định vị trí bên trong tập tin về
đầu tập tin. Nó lấy con trỏ tập tin làm đối số. Cú pháp của rewind() là:
```
rewind(fp);
```
Chương trình sau mở một tập tin ở chế độ đọc/ghi, sử dụng
hàm fputs() với đầu vào là các chuỗi, đưa con trỏ quay về đầu tập tin và sau đó
hiển thị các chuỗi giống như vậy bằng hàm fgets().
Ví dụ 1:
```
#include <stdio.h>
main() {
FILE *fp;
char str [80];
/* Writing to File JAK */
if ((fp = fopen("jak", "w+")) == NULL) {
printf ("Cannot open file \n\n");
exit(1);
}
do {
printf ("Enter a string (CR to quit): \n");
gets (str);
if(*str != '\n') {
strcat (str, "\n"); /* thêm một dòng mới */
fputs (str, fp);
}
} while (*str != '\n');
/* Reading from File JAK */
printf ("\n\n Displaying Contents of File
JAK\n\n");
rewind (fp);
while (!feof(fp)) {
fgets (str, 81, fp);
printf ("\n%s", str);
}
fclose(fp);
}
```
Một mẫu chạy chương trình trên như sau:
-
Enter a string (CR to quit):
This is input line 1
-
Enter a string (CR to quit) :
This is input line 2
-
Enter a string (CR to quit):
This is input line 3
-
Enter a string (CR to quit):
This is input line 1
This is input line 2
This is input line 3
Hàm ferror()
Hàm ferror() xác định liệu một thao tác trên tập tin có sinh
ra lỗi hay không. Nguyên mẫu của hàm là:
```
int ferror(FILE * fp) ;
```
Trong đó fp là một con trỏ tập tin hợp lệ. Nó trả về true nếu
có xảy ra một lỗi trong thao tác cuối cùng trên tập tin; ngược lại, nó trả về
false. Vì mỗi thao tác thiết lập lại tình trạng lỗi, nên hàm ferror() phải được
gọi ngay sau mỗi thao tác; nếu không, lỗi sẽ bị mất.
Chương trình trước có thể được sửa đổi để kiểm tra và cảnh
báo về bất kỳ lỗi nào trong khi ghi như sau:
```
do {
printf(“ Enter a
string (CR to quit): \n");
gets(str);
if(*str != '\n') {
strcat (str,
"\n"); /* thêm một dòng mới */
fputs (str, fp);
}
if(ferror(fp))
printf("\nERROR
in writing\n");
} while(*str!='\n');
```
Xóa tập tin
Hàm remove() xóa một tập tin đã định. Nguyên mẫu của hàm là:
```
int remove (char *filename);
```
Nó trả về 0 nếu thành công ngược lại trả về một giá trị khác
0.
Ví dụ, xét đoạn mã lệnh sau đây:
```
printf ("\nErase file %s (Y/N) ? ", file1);
ans = getchar ();
…
if(remove(file1)) {
printf ("\nFile cannot be erased");
exit(1);
}
```
Làm sạch các stream
Thông thường, các tập tin xuất chuẩn được trang bị vùng đệm.
Điều này có nghĩa là kết xuất cho tập tin được thu thập trong bộ nhớ và không
thật sự hiển thị cho đến khi vùng đệm đầy. Nếu một chương trình bị treo hay kết
thúc bất thường, một số ký tự vẫn còn nằm trong vùng đệm. Kết quả là chương
trình có vẻ như kết thúc sớm hơn là nó thật sự đã làm. Hàm fflush() sẽ giải quyết
vấn đề này. Như tên gọi của nó, nó sẽ làm sạch vùng đệm và chép những gì có
trong vùng đệm ra ngoài. Hành động làm sạch tùy theo kiểu tập tin. Một tập tin
được mở để đọc sẽ có vùng đệm nhập trống, trong khi một tập tin được mở để ghi
thì vùng đệm xuất của nó sẽ được ghi vào tập tin.
Nguyên mẫu của hàm này là:
```
int fflush(FILE * fp);
```
Hàm fflush() sẽ ghi nội dung của bất kỳ vùng đệm dữ liệu nào
vào tập tin kết hợp với fp. Hàm fflush(), không có đối số, sẽ làm sạch tất cả
các tập tin đang mở để xuất. Nó trả về 0 nếu thành công, ngược lại, nó trả về
EOF.
Các stream chuẩn
Mỗi khi một chương trình C bắt đầu thực thi dưới DOS, hệ điều
hành sẽ tự động mở 5 stream đặc biệt bao gồm:
1. Nhập chuẩn (stdin)
2. Xuất chuẩn (stdout)
3. Lỗi chuẩn (stderr)
4. Máy in chuẩn (stdprn)
5. Thiết bị hỗ trợ chuẩn (stdaux)
Trong đó, stdin, stdout
và stderr được gán mặc định cho các thiết bị nhập/xuất
chuẩn của hệ thống trong khi stdprn được gán cho cổng in song
song đầu tiên và stdaux được gán cho cổng nối tiếp đầu tiên. Chúng được định
nghĩa như là các con trỏ cố định kiểu FILE, vì vậy chúng có thể được sử dụng ở
bất kỳ nơi nào mà việc sử dụng con trỏ FILE là hợp lệ. Chúng cũng có thể được
chuyển một cách hiệu quả cho các stream hay thiết bị khác mỗi khi cần định hướng
lại.
Chương trình sau đây in nội dung của tập tin vào máy in.
Ví dụ 2:
```
#include <stdio.h>
main() {
FILE *in;
char buff[81],
fname[13];
printf("Enter
the Source File Name:");
gets(fname);
if((in=fopen(fname,
"r")) == NULL) {
fputs("\nFile
not found", stderr);
/* display error
message on standard error rather
than standard output
*/
exit(1);
}
while(!feof(in)) {
if(fgets(buff, 81,
in)) {
fputs(buff, stdprn);
/* Send line to
printer */
}
}
fclose(in);
}
```
Lưu ý cách sử dụng của stream stderr với hàm fputs() trong
chương trình trên. Nó được sử dụng thay
cho hàm
printf vì kết xuất của hàm printf là ở stdout, nơi mà có thể
định hướng lại. Nếu kết xuất củamột chương trình được định hướng lại và một lỗi
xảy ra trong quá trình thực thi, thì tất cả các thông báo lỗi đưa ra cho stream
stdout cũng phải được định hướng lại. Để tránh điều này, stream stderr được
dùng để hiển thị thông báo lỗi lên màn hình vì kết xuất của stderr cũng là thiết
bị xuất chuẩn, nhưng stream stderr không thể định hướng lại. Nó luôn luôn hiển
thị thông báo lên màn hình.
Con trỏ kích hoạt hiện hành
Để lần theo vị trí nơi mà các thao tác nhập/xuất đang diễn
ra, một con trỏ được duy trì trong cấu trúc FILE. Mỗi khi một ký tự được đọc ra
hay ghi vào một stream, con trỏ kích hoạt hiện hành (current active pointer) (gọi
là curp) được tăng lên. Hầu hết các hàm nhập xuất đều tham chiếu đến curp, và cập
nhật nó sau các thủ tục nhập hoặc xuất trên stream. Vị trí hiện hành của con trỏ
này có thể được tìm thấy bằng sự trợ giúp của hàm ftell(). Hàm ftell() trả về một
giá trị kiểu long int biểu diễn vị trí của curp tính từ đầu tập tin trong stream đã cho.
Nguyên mẫu của hàm ftell() là:
```
long int ftell(FILE *fp);
```
Câu lệnh trích từ một chương trình sẽ hiển thị vị trí của
con trỏ hiện hành trong stream fp.
```
printf("The current location of the file pointer is :
%1d ", ftell (fp));
```
Đặt lại vị trí hiện hành
Ngay sau khi mở stream, con trỏ kích hoạt hiện hành được đặt
là 0 và trỏ đến byte đầu tiên của stream. Như đã thấy trước đây, mỗi khi có một
ký tự được đọc hay ghi vào stream, con trỏ kích hoạt hiện hành sẽ tăng lên. Bên
trong một chương trình, con trỏ có thể được đặt đến một vị trí bất kỳ khác với
vị trí hiện hành vào bất kỳ lúc nào.
Hàm rewind() đặt vị trí con trỏ này về đầu. Một hàm khác được
sử dụng để đặt lại vị trí con trỏ này là fseek().
Hàm fseek() định lại vị trí của curp dời đi một số byte tính
từ đầu, từ vị trí hiện hành hay từ cuối stream là tùy vào vị trí được qui định
khi gọi hàm fseek(). Nguyên mẫu của hàm fseek() là:
```
int fseek(FILE *fp, long int offset, int origin);
```
Trong đó offset là số byte cần di chuyển vượt qua vị trí tập
tin được cho bởi tham số origin. Tham số origin chỉ định vị trí bắt đầu tìm kiếm
và phải có giá trị là 0, 1 hoặc 2, biễu diễn cho 3 hằng ký hiệu (được định
nghĩa trong stdio.h) như thể hiện dưới đây:
1. SEEK_SET hoặc 0 : Đầu tập tin
2. SEEK_CUR hoặc 1 : Vị trí con trỏ của tập tin hiện hành
3. SEEK_END hoặc 2 : Cuối tập tin
Hàm fseek() trả về giá trị 0 nếu đã thành công và giá trị
khác 0 nếu thất bại.
Đoạn lệnh sau tìm mẫu tin thứ 6 trong tập tin:
```
struct addr {
char name[40];
char street[40];
char city[40];
char state[3];
char pin[7];
} FILE *fp;
…
fseek(fp, 5L*sizeof(struct addr), SEEK_SET);
```
Hàm sizeof() được dùng để tìm độ dài của mỗi mẩu tin theo
đơn vị byte. Giá trị trả về được dùng để xác định số byte cần thiết để nhảy qua
5 mẩu tin đầu tiên.
Hàm fprintf() và fscanf()
Ngoài các hàm nhập xuất đã được thảo luận, hệ thống nhập/xuất
có vùng đệm còn bao gồm các hàm
fprintf() và fscanf(). Các hàm này tương tự như hàm printf() và scanf() ngoại
trừ rằng chúng thao tác trên tập tin. Nguyên mẫu của hàm fprintf() và fscanf()
là:
..
int fprintf(FILE * fp, const char *control_string,..);
int fscanf(FILE *fp, const char *control_string,...);
```
Trong đó fp là con trỏ tập tin trả về bởi lời gọi hàm
fopen(). Hàm fprintf() và fscanf() định hướng các thao tác nhập xuất của chúng
đến tập tin được trỏ bởi fp. Đoạn chương trình sau đây đọc một chuỗi và một số
nguyên từ bàn phím, ghi chúng vào một tập tin trên đĩa, và sau đó đọc thông tin
và hiển thị trên màn hình.
```
printf("Enter a string and a number: ");
fscanf(stdin, "%s %d", str, &no);
/* đọc từ bàn phím */
fprintf(fp, "%s %d", str, no);
/* ghi ra tập tin */
fclose (fp);
. . fscanf(fp, "%s %d", str, &no)
/* đọc từ tập tin */
fprintf(stdout, "%s %d", str, no)
/* ghi ra màn hình */
```
Nên nhớ rằng, mặc dù fprintf() và fscanf() thường là cách dễ
nhất để ghi vào và đọc dữ liệu hỗn hợp ra các tập tin trên đĩa, nhưng chúng
không phải luôn luôn là hiệu quả nhất. Nguyên nhân là mỗi lời gọi phải mất thêm một khoảng thời gian, vì dữ liệu
được ghi theo dạng ASCII có định dạng (như nó sẽ xuất hiện trên màn hình) chứ
không phải theo định dạng nhị phân. Vì vậy, nếu tốc độ và độ lớn của tập tin là
đáng ngại, fread() và fwrite() sẽ là lựa chọn tốt hơn.
0 bình luận:
Đăng nhận xét