Hầu hết các chương trình đều yêu cầu đọc và ghi dữ liệu vào các hệ thống lưu trữ đên đĩa. Các chương trình xử lý văn bản cần lưu các tập tin văn bản, chương trình xử lý bảng tính cầ lưu nội dung của các ô, chương trình cơ sở dữ liệu cần lưu các mẫu tin. Bài này sẽ khám phá các tiện ích trong C dành cho các thao tác nhập/xuất (I/O) đĩa hệ thống.
Bài 21 Quản lý tập tin Mục tiêu: Kết thúc học này, bạn có thể: Giải thích khái niệm luồng (streams) tập tin (files) Thảo luận luồng văn luồng nhị phân Giải thích hàm xử lý tập tin Giải thích trỏ tập tin Thảo luận trỏ kích hoạt hành Giải thích đối số từ dòng nhắc lệnh (command-line) Giới thiệu Hầu hết chương trình yêu cầu đọc ghi liệu vào hệ thống lưu trữ đĩa Các chương trình xử lý văn cần lưu tập tin văn bản, chương trình xử lý bảng tính cần lưu nội dung ơ, chương trình sỡ liệu cần lưu mẫu tin Bài khám phá tiện ích C dành cho thao tác nhập/xuất (I/O) đĩa hệ thống Ngôn ngữ C không chứa câu lệnh nhập/xuất cách tường minh Tất thao tác nhập/xuất thực thông qua hàm thư viện chuẩn C Tiếp cận làm cho hệ thống quản lý tập tin C mạnh uyển chuyển Nhập/xuất C tuyệt vời liệu truyền dạng nhị phân hay dạng văn mà người đọc Điều làm cho việc tạo tập tin để đáp ứng nhu cầu cách dễ dàng Việc hiểu rõ khác biệt stream tập tin quan trọng Hệ thống nhập/xuất C cung cấp cho người dùng giao diện độc lập với thiết bị thật truy cập Giao diện tập tin thật mà biễu diễn trừu tượng thiết bị Giao diện trừu tượng gọi stream thiết bị thật gọi tập tin 21.1 File Streams Hệ thống tập tin C làm việc với nhiều thiết bị khác bao gồm máy in, ổ đĩa, ổ băng từ thiết bị đầu cuối Mặc dù tất thiết bị khác nhau, hệ thống tập tin có vùng đệm chuyển thiết bị thiết bị logic gọi stream Vì streams hoạt động tương tự, nên việc quản lý thiết bị dễ dàng Có hai loại streams – văn (text) nhị phân (binary) 21.1.1 Streams văn Một streams văn chuỗi ký tự Các streams văn tổ chức thành dòng, dòng kết thúc ký tự sang dòng Tuy nhiên, ký tự sang dòng tùy chọn dòng cuối định cài đặt Hầu hết trình biên dịch C không kết thúc stream văn với ký tự sang dòng Trong stream văn bản, xảy vài chuyển đổi ký tự môi trường yêu cầu Chẳng hạn như, ký tự sang dịng chuyển thành cặp ký tự đầu dịng/nhảy đến dịng kế Vì vậy, mối quan hệ ký tự ghi (hay đọc) ký tự thiết bị ngoại vi khơng phải mối quan hệ một-một Và chuyển đổi xảy này, số lượng ký tự ghi (hay đọc) khơng giống số lượng ký tự nhìn thấy thiết bị ngoại vi Quản lý tập tin 29 21.1.2 Streams nhị phân Một streams nhị phân chuỗi byte với tương ứng một-một với thiết bị ngoại vi, nghĩa là, khơng có chuyển đổi ký tự Cũng vậy, số lượng byte đọc (hay ghi) giống số lượng byte thiết bị ngoại vi Các stream nhị phân chuỗi byte túy, mà khơng có ký hiệu dùng để điểm kết thúc tập tin hay kết thúc record Kết thúc tập tin xác định độ lớn tập tin 21.2 Các hàm tập tin structure FILE Một tập tin tham chiếu đến gì: từ tập tin đĩa đến thiết bị đầu cuối hay máy in Tuy nhiên, tất tập tin khơng có khả Ví dụ như, tập tin đĩa hổ trợ truy cập ngẩu nhiên bàn phím khơng Một tập tin kết hợp với stream cách thực thao tác mở Tương tự, thơi kết hợp với stream thao tác đóng Khi chương trình kết thúc bình thường, tất tập tin tự động đóng Tuy nhiên, chương trình bị treo kết thúc bất thường, tập tin mở 21.2.1 Các hàm tập tin Một hệ thống quản lý tập tin theo chuẩn ANSI bao gồm số hàm liên quan với Các hàm thông dụng liệt kê bảng 21.1 Name fopen() fclose() fputc() fgetc() fread() fwrite() fseek() fprintf() fscanf() feof() ferror() rewind() remove() fflush() Function Mở tập tin Đóng tập tin Ghi ký tự vào tập tin Đọc ký tự từ tập tin Đọc từ tập tin vào vùng đệm Ghi từ vùng đệm vào tập tin Tìm vị trí tập tin Hoạt động giống printf(), tập tin Hoạt động giống scanf(), tập tin Trả true đến cuối tập tin (end-of-file) Trả true xảy lỗi Đặt lại trỏ định vị trí (position locator) bên tập tin đầu tập tin Xóa tập tin Ghi liệu từ vùng đệm bên vào tập tin xác định Bảng 21.1: Các hàm tập tin Các hàm chứa tập tin header stdio.h Tập tin header phải bao gồm vào chương trình có sử dụng hàm Hầu hết hàm tương tự hàm nhập/xuất từ thiết bị nhập xuất chuẩn Tập tin header stdio.h định nghĩa số macro sử dụng q trình xử lý tập tin Ví dụ như, macro EOF định nghĩa -1, chứa giá trị trả hàm cố đọc tiếp đến cuối tập tin 21.2.2 Con trỏ tập tin Một trỏ tập tin (file pointer) cần thiết cho việc đọc ghi tập tin Nó trỏ đến structure chứa thông tin tập tin Thông tin bao gồm: tên tập tin, vị trí tập tin, tập tin đọc hay ghi, có lỗi xuất hay đến cuối tập tin Người dùng không cần 30 Lập trình C thiết phải biết chi tiết, định nghĩa lấy từ studio.h có bao gồm khai báo structure tên FILE Câu lệnh khai báo cần thiết cho trỏ tập tin là: FILE *fp; Khai báo cho biết fp trỏ trỏ đến FILE 21.3 Các tập tin văn Có nhiều hàm khác để quản lý tập tin văn Chúng ta thảo luận đoạn bên dưới: 21.3.1 Mở tập tin văn Hàm fopen() mở stream để sử dụng liên kết tập tin với stream Con trỏ kết hợp với tập tin trả từ hàm fopen() Trong hầu hết trường hợp, tập tin mở tập tin đĩa Nguyên mẫu hàm fopen() là: FILE *fopen(const char *filename, const char *mode); filename trỏ trỏ đến chuỗi ký tự chứa tên tập tin hợp lệ chứa phần mô tả đường dẫn Chuỗi trỏ đến trỏ mode xác định cách thức tập tin mở Bảng 21.2 liệt kê chế độ hợp lệ mà tập tin mở Chế độ r w a r+ w+ a+f Ý nghĩa Mở tập tin văn để đọc Tạo tập tin văn để ghi Nối vào tập tin văn Mở tập tin văn để đọc/ghi Tạo tập tin văn để đọc/ghi Nối tạo tập tin văn để đọc/ghi Bảng 21.2: Các chế độ mở tập tin văn Bảng 21.2 cho thấy tập tin mở nhiều chế độ khác Một trỏ null trả xảy lỗi hàm fopen() mở tập tin Lưu ý chuỗi “a+f” biễu diễn “af+” Nếu phải mở tập tin xyz để ghi, câu lệnh là: FILE *fp; fp = fopen ("xyz", "w"); Tuy nhiên, tập tin nói chung mở cách sử dụng tập hợp câu lệnh tương tự sau: FILE *fp; if ((fp = fopen ("xyz", "w")) == NULL) { printf("Cannot open file"); exit (1); } Macro NULL định nghĩa stdio.h ‘\0’ Nếu sử dụng phương pháp để mở tập tin, hàm fopen() phát lỗi có, chẳng hạn đĩa chế độ cấm ghi (write-protected) hay đĩa đầy, trước bắt đầu ghi đĩa Quản lý tập tin 31 Nếu tập tin mở để ghi, tập tin có tên mở bị viết chồng lên Vì tập tin mở chế độ ghi, tập tin tạo Nếu muốn nối thêm mẫu tin vào tập tin có, phải mở với chế độ “a” Nếu tập tin mở chế độ đọc khơng tồn tại, hàm trả lỗi Nếu tập tin mở để đọc/ghi, khơng bị xóa tồn Tuy nhiên, khơng tồn tại, tạo Theo chuẩn ANSI, tám tập tin mở thời điểm Tuy vậy, hầu hết trình biên dịch C mơi trường cho phép mở nhiều tám tập tin 21.3.2 Đóng tập tin văn Vì số lượng tập tin mở thời điểm bị giới hạn, việc đóng tập tin khơng cịn sử dụng điều quan trọng Thao tác giải phóng tài nguyên làm giảm nguy vượt giới hạn định Đóng stream làm chép vùng đệm kết hợp (một thao tác quan trọng để tránh liệu) ghi đĩa Hàm fclose() đóng stream mở hàm fopen() Nó ghi liệu lại vùng đệm đĩa vào tập tin Nguyên mẫu hàm fclose() là: int fclose(FILE *fp); fp trỏ tập tin Hàm fclose() trả đóng thành cơng Bất kỳ giá trị trả khác cho thấy có lỗi xảy Hàm fclose() thất bại đĩa sớm gỡ khỏi ổ đĩa đĩa bị đầy Một hàm khác dùng để đóng stream hàm fcloseall() Hàm hữu dụng phải đóng lúc nhiều stream mở Nó đóng tất stream trả số stream đóng EOF có phát lỗi Nó sử dụng theo cách sau: fcl = fcloseall(); if (fcl == EOF) printf("Error closing files"); else printf("%d file(s) closed", fcl); 21.3.3 Ghi ký tự Streams ghi vào tập tin theo ký tự theo chuỗi Trước hết thảo luận cách ghi ký tự vào tập tin Hàm fputc() sử dụng để ghi ký tự vào tập tin mở trước hàm fopen() Nguyên mẫu hàm sau: int fputc(int ch, FILE *fp); fp trỏ tập tin trả hàm fopen() ch ký tự cần ghi Mặc dù ch khai báo kiểu int, hàm fputc() chuyển đổi thành kiểu unsigned char Hàm fputc() ghi ký tự vào stream định vị trí hành trỏ định vị trí bên tập tin sau tăng trỏ lên Nếu fputc() thành cơng, trả ký tự ghi, ngược lại trả EOF 21.3.4 Đọc ký tự Hàm fgetc() dùng để đọc ký tự từ tập tin mở chế độ đọc, sử dụng hàm fopen() Nguyên mẫu hàm là: int fgetc (FILE *fp); fp trỏ tập tin kiểu FILE trả hàm fopen() Hàm fgetc() trả ký tự vị trí hành stream input, tăng trỏ định vị trí bên tập tin lên Ký tự đọc 32 Lập trình C ký tự kiểu unsigned char chuyển thành kiểu int Nếu đến cuối tập tin, fgetc() trả EOF Để đọc tập tin văn từ đầu cuối, câu lệnh là: { } ch = fgetc(fp); while (ch != EOF); Chương trình sau nhận ký tự từ bàn phím ghi chúng vào tập tin người dùng nhập ký tự ‘@’ Sau người dùng nhập thơng tin vào, chương trình hiển thị nội dung hình Ví dụ 1: #include main() { FILE *fp; char ch= ' '; /* Writing to file JAK */ if ((fp=fopen("jak", "w"))==NULL) { printf("Cannot open file \n\n"); exit(1); } clrscr(); printf("Enter characters (type @ to terminate): \n"); ch = getche(); while (ch !='@') { fputc(ch, fp) ; ch = getche(); } fclose(fp); /* Reading from file JAK */ printf("\n\nDisplaying contents of file JAK\n\n"); if((fp=fopen("jak", "r"))==NULL) { printf("Cannot open file\n\n"); exit(1); } { } ch = fgetc (fp); putchar(ch) ; while (ch!=EOF); getch(); fclose(fp); } Quản lý tập tin 33 Một mẫu chạy cho chương trình là: Enter Characters (type @ to terminate): This is the first input to the File JAK@ Displaying Contents of File JAK This is the first input to the File JAK 21.3.5 Nhập xuất chuỗi Ngồi fgetc() fputc(), C cịn hổ trợ hàm fputs() fgets() để ghi vào đọc chuỗi ký tự từ tập tin đĩa Nguyên mẫu cho hai hàm sau: int fputs(const char *str, FILE *fp); char *fgets(char *str, int length, FILE *fp); Hàm fputs() làm việc giống hàm fputc(), ngoại trừ viết tồn chuỗi vào stream Nó trả EOF xảy lỗi Hàm fgets() đọc chuỗi từ stream cho đọc ký tự sang dòng sau đọc length-1 ký tự Nếu đọc ký tự sang dòng mới, ký tự xem phần chuỗi (không giống hàm gets()) Chuỗi kết kết thúc ký tự null Hàm trả trỏ trỏ đến chuỗi thành công null xảy lỗi 21.4 Các tập tin nhị phân Các hàm dùng để xử lý tập tin nhị phân giống hàm sử dụng để quản lý tập tin văn Tuy nhiên, chế độ mở tập tin hàm fopen() khác trường hợp tập tin nhị phân 21.4.1 Mở tập tin nhị phân Bảng sau liệt kê chế độ khác hàm fopen() trường hợp mở tập tin nhị phân Chế độ rb wb ab r+b w+b a+b Ý nghĩa Mở tập tin nhị phân để đọc Tạo tập tin nhị phân để ghi Nối vào tập tin nhị phân Mở tập tin nhị phân để đọc/ghi Tạo tập tin nhị phân để đọc/ghi Nối vào tập tin nhị phân để đọc/ghi Bảng 21.3: Các chế độ mở tập tin nhị phân Nếu tập tin xyz mở để ghi, câu lệnh là: FILE *fp; fp = fopen ("xyz", "wb"); 21.4.2 Đóng tập tin nhị phân 34 Lập trình C Ngoài tập tin văn bản, hàm fclose() dùng để đóng tập tin nhị phân Nguyên mẫu fclose sau: int fclose(FILE *fp); fp trỏ tập tin trỏ đến tập tin mở 21.4.3 Ghi tập tin nhị phân Một số ứng dụng liên quan đến việc sử dụng tập tin liệu để lưu trữ khối liệu, khối bao gồm byte liên tục Mỗi khối nói chung biểu diễn cấu trúc liệu phức tạp mảng Chẳng hạn như, tập tin liệu bao gồm nhiều cấu trúc có thành phần cấu tạo, chứa nhiều mảng có kiểu kích thước Và với ứng dụng thường địi hỏi đọc tồn khối liệu từ tập tin liệu ghi toàn khối vào tập tin liệu đọc hay ghi thành phần độc lập (nghĩa thành viên cấu trúc hay phần tử mảng) khối riêng biệt Hàm fwrite() dùng để ghi liệu vào tập tin liệu tình Hàm dùng để ghi kiểu liệu Nguyên mẫu fwrite() là: size_t fwrite(const void *buffer, size_t num_bytes, size_t count, FILE *fp); Kiểu liệu size_t thêm vào C chuẩn để tăng tính tương thích chương trình với nhiều hệ thống Nó định nghĩa trước kiểu số nguyên đủ lớn để lưu giữ kết hàm sizeof() Đối với hầu hết hệ thống, dùng số nguyên dương Buffer trỏ trỏ đến thông tin ghi vào tập tin Số byte phải đọc ghi cho num_bytes Đối số count xác định có mục (mỗi mục dài num_bytes) đọc ghi Cuối cùng, fp trỏ tập tin trỏ đến stream mở trước Các tập tin mở cho thao tác phải mở chế độ nhị phân Hàm trả số lượng đối tượng ghi vào tập tin thao tác ghi thành công Nếu giá trị nhỏ count xảy lỗi Hàm ferror() (sẽ thảo luận phần tới) dùng để xác định lỗi 21.4.4 Đọc tập tin nhị phân Hàm fread() dùng để đọc kiểu liệu Nguyên mẫu hàm là: size_t fread(void *buffer, size_t num_bytes, size_t count FILE *fp); buffer trỏ trỏ đến vùng nhớ nhận liệu từ tập tin Số byte phải đọc ghi cho num_bytes Đối số count xác định có mục (mỗi mục dài num_bytes) đọc ghi Cuối cùng, fp trỏ tập tin trỏ đến stream mở trước Các tập tin mở cho thao tác phải mở chế độ nhị phân Hàm trả số lượng đối tượng đọc thao tác đọc thành cơng Nó trả đọc đến cuối tập tin xảy lỗi Hàm feof() hàm ferror() (sẽ thảo luận phần tới) dùng để xác định nguyên nhân Quản lý tập tin 35 Các hàm fread() fwrite() thường gọi hàm đọc ghi không định dạng Miễn tập tin mở cho thao tác nhị phân, hàm fread() fwrite() đọc ghi kiểu thơng tin Ví dụ, chương trình sau ghi vào sau đọc ngược số kiểu double, số kiểu int số kiểu long từ tập tin đĩa Lưu ý sử dụng hàm sizeof() để xác định độ dài kiểu liệu Ví dụ 2: #include main () { FILE *fp; double d = 23.31 ; int i = 13; long li = 1234567L; clrscr(); if ((fp = fopen ("jak", "wb+")) == NULL ) { printf("Cannot open file "); exit(1); } fwrite fwrite fwrite fclose (&d, sizeof(double), 1, fp); (&i, sizeof(int), 1, fp); (&li, sizeof(long), 1,fp); (fp); if ((fp = fopen ("jak", "rb+")) == NULL ) { printf("Cannot open file"); exit(1); } fread (&d, sizeof(double), 1, fp); fread(&i, sizeof(int), 1, fp); fread (&li, sizeof(long), 1, fp); printf ("%f %d %ld", d, i, li); fclose (fp); } Như chương trình minh họa, đọc buffer thường vùng nhớ để giữ biến Trong chương trình đơn giản trên, giá trị trả hàm fread() fwrite() bỏ qua Tuy nhiên, để lập trình hiệu quả, giá trị nên kiểm tra xem có lỗi xảy khơng Một ứng dụng hữu dụng fread() fwrite() liên quan đến việc đọc ghi kiểu liệu người dùng định nghĩa, đặc biệt cấu trúc Ví dụ ta có cấu trúc sau: struct struct_type { float balance; char name[80]; } cust; 36 Lập trình C Câu lệnh sau ghi nội dung cust vào tập tin trỏ đến fp fwrite(&cust, sizeof(struct struct_type), 1, fp); 21.5 Các hàm xử lý tập tin Các hàm xử lý tập tin khác thảo luận phần 21.5.1 Hàm feof() Khi tập tin mở để đọc dạng nhị phân, số nguyên có giá trị tương đương với EOF đọc Trong trường hợp này, trình đọc cho đến cuối tập tin, chưa đến cuối tập tin thực Một hàm feof() dùng trường hợp Nguyên mẫu hàm là: int feof(FILE *fp ); Nó trả true đến cuối tập tin, khơng trả false (0) Hàm dùng đọc liệu nhị phân Đoạn lệnh sau đọc tập tin nhị phân cuối tập tin while (!feof(fp) ) ch = fgetc(fp); 21.5.2 Hàm rewind() Hàm rewind() đặt lại trỏ định vị trí bên tập tin đầu tập tin Nó lấy trỏ tập tin làm đối số Cú pháp rewind() là: rewind(fp); Chương trình sau mở tập tin chế độ đọc/ghi, sử dụng hàm fputs() với đầu vào chuỗi, đưa trỏ quay đầu tập tin sau hiển thị chuỗi giống hàm fgets() Ví dụ 3: #include main() { FILE *fp; char str [80]; /* Writing to File JAK */ if ((fp = fopen("jak", "w+")) == NULL) { printf ("Cannot open file \n\n"); exit(1); } clrscr (); Quản lý tập tin 37 { printf ("Enter a string (CR to quit): \n"); gets (str); if(*str != '\n') { strcat (str, "\n"); /* add a new line */ 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 sau: Enter a string (CR to quit): This is input line Enter a string (CR to quit) : This is input line Enter a string (CR to quit): This is input line Enter a string (CR to quit): Displaying Contents of File JAK This is input line This is input line This is input line 21.5.3 Hàm ferror() Hàm ferror() xác định liệu thao tác tập tin có sinh lỗi hay khơng Nguyên mẫu hàm là: int ferror(FILE * fp) ; fp trỏ tập tin hợp lệ Nó trả true có xảy lỗi thao tác cuối tập tin ; ngược lại, trả false Vì thao tác thiết lập lại tình trạng lỗi, nên hàm ferror() phải gọi sau thao tác; không, lỗi bị Chương trình trước sửa đổi để kiểm tra cảnh báo lỗi ghi sau: 38 Lập trình C { printf(“ Enter a string (CR to quit): \n"); gets(str); if(*str != '\n') { strcat (str, "\n"); /* add a new line */ fputs (str, fp); } if(ferror(fp)) printf("\nERROR in writing\n"); } while(*str!='\n'); 21.5.4 Xóa tập tin Hàm remove() xóa tập tin định Nguyên mẫu hàm là: int remove (char *filename); Nó trả thành cơng ngược lại trả giá trị khác Ví dụ, xét đoạn mã lệnh sau đây: printf ("\nErase file %s (Y/N) ? ", file1); ans = getchar (); 21.5.5 if(remove(file1)) { printf ("\nFile cannot be erased"); exit(1); } Làm stream Thông thường, tập tin xuất chuẩn trang bị vùng đệm Điều có nghĩa kết xuất cho tập tin thu thập nhớ không thật hiển thị vùng đệm đầy Nếu chương trình bị treo hay kết thúc bất thường, số ký tự nằm vùng đệm Kết chương trình kết thúc sớm thật làm Hàm fflush() giải vấn đề Như tên gọi nó, làm vùng đệm chép có vùng đệm Hành động làm tùy theo kiểu tập tin Một tập tin mở để đọc có vùng đệm nhập trống, tập tin mở để ghi vùng đệm xuất ghi vào tập tin Nguyên mẫu hàm là: int fflush(FILE Quản lý tập tin * fp); 39 Hàm fflush() ghi nội dung vùng đệm liệu vào tập tin kết hợp với fp Hàm fflush(), khơng có đối số, làm tất tập tin mở để xuất Nó trả thành cơng, ngược lại, trả EOF 21.5.6 Các stream chuẩn Mỗi chương trình C bắt đầu thực thi DOS, hệ điều hành tự động mở stream đặc biệt stream là: Nhập chuẩn (stdin) Xuất chuẩn (stdout) Lỗi chuẩn (stderr) Máy in chuẩn (stdprn) Thiết bị hỗ trợ chuẩn (stdaux) Trong đó, stdin, stdout stderr gán mặc định cho thiết bị nhập/xuất chuẩn hệ thống stdprn gán cho cổng in song song stdaux gán cho cổng nối tiếp Chúng định nghĩa trỏ cố định kiểu FILE, chúng sử dụng nơi mà việc sử dụng trỏ FILE hợp lệ Chúng chuyển cách hiệu cho stream hay thiết bị khác cần định hướng lại Chương trình sau in nội dung tập tin vào máy in Ví dụ 4: #include main() { FILE *in; char buff[81], fname[13]; clrscr(); 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 */ } 40 exit(1); } while(!feof(in)) { if(fgets(buff, 81, in)) { fputs(buff, stdprn); /* Send line to printer */ } } fclose(in); Lập trình C Lưu ý cách sử dụng stream stderr với hàm fputs() chương trình Nó sử dụng thay cho hàm printf kết xuất hàm printf stdout, nơi mà định hướng lại Nếu kết xuất chương trình định hướng lại lỗi xảy trình thực thi, tất thông báo lỗi đưa cho stream stdout phải định hướng lại Để tránh điều này, stream stderr dùng để hiển thị thông báo lỗi lên hình kết xuất stderr thiết bị xuất chuẩn, stream stderr định hướng lại Nó ln ln hiển thị thơng báo lên hình 21.5.7 Con trỏ kích hoạt hành Để lần theo vị trí nơi mà thao tác nhập/xuất diễn ra, trỏ trì cấu trúc FILE Mỗi ký tự đọc hay ghi vào stream, trỏ kích hoạt hành (current active pointer) (gọi curp) tăng lên Hầu hết hàm nhập xuất tham chiếu đến curp, cập nhật sau thủ tục nhập xuất stream Vị trí hành trỏ tìm thấy trợ giúp hàm ftell() Hàm ftell() trả giá trị kiểu long int biểu diễn vị trí curp tính từ đầu tập tin stream cho Nguyên mẫu hàm ftell() là: long int ftell(FILE *fp); Câu lệnh trích từ chương trình hiển thị vị trí trỏ hành stream fp printf("The current location of the file pointer is : %1d ", ftell (fp)); Đặt lại vị trí hành Ngay sau mở stream, trỏ kích hoạt hành đặt trỏ đến byte stream Như thấy trước đây, có ký tự đọc hay ghi vào stream, trỏ kích hoạt hành tăng lên Bên chương trình, trỏ đặt đến vị trí khác với vị trí hành vào lúc Hàm rewind() đặt vị trí trỏ đầu Một hàm khác sử dụng để đặt lại vị trí trỏ fseek() Hàm fseek() định lại vị trí curp dời số byte tính từ đầu, từ vị trí hành hay từ cuối stream tùy vào vị trí qui định gọi hàm fseek() Nguyên mẫu hàm fseek() là: int fseek(FILE *fp, long int offset, int origin); offset số byte cần di chuyển vượt qua vị trí tập tin cho tham số origin Tham số origin định vị trí bắt đầu tìm kiếm phải có giá trị 0, 2, biễu diễn cho ký hiệu (được định nghĩa stdio.h) bảng 21.4: Origin Vị trí tập tin SEEK_SET or Đầu tập tin SEEK_CUR or Vị trí trỏ tập tin hành SEEK_END or Cuối tập tin Bảng 21.4: Các ký hiệu Hàm fseek() trả giá trị thành công giá trị khác thất bại Đoạn lệnh sau tìm mẫu tin thứ tập tin: struct addr { char name[40]; Quản lý tập tin 41 char char char char street[40]; city[40]; state[3]; pin[7]; } FILE *fp; fseek(fp, 5L*sizeof(struct addr), SEEK_SET); Hàm sizeof() dùng để tìm độ dài mẩu tin theo đơn vị byte Giá trị trả dùng để xác định số byte cần thiết để nhảy qua mẩu tin 21.5.8 Hàm fprintf() fscanf() Ngoài hàm nhập xuất thảo luận, hệ thống nhập/xuất có vùng đệm bao gồm hàm fprintf() fscanf() Các hàm tương tự hàm printf() scanf() ngoại trừ chúng thao tác tập tin Nguyên mẫu hàm fprintf() fscanf() là: int fprintf(FILE * fp, const char *control_string, ); int fscanf(FILE *fp, const char *control_string, ); fp trỏ tập tin trả lời gọi hàm fopen() Hàm fprintf() fscanf() định hướng thao tác nhập xuất chúng đến tập tin trỏ fp Đoạn chương trình sau đọc chuỗi số nguyên từ bàn phím, ghi chúng vào tập tin đĩa, sau đọc thơng tin hiển thị hình printf("Enter a string and a number: "); fscanf(stdin, "%s %d", str, &no); /* read from the keyboard */ fprintf(fp, "%s %d", str, no); /* write to the file*/ fclose (fp); fscanf(fp, "%s %d", str, &no) /* read from file */ fprintf(stdout, "%s %d", str, no) /* print on screen */ Nên nhớ rằng, fprintf() fscanf() thường cách dễ để ghi vào đọc liệu hỗn hợp tập tin đĩa, chúng luôn hiệu Nguyên nhân lời gọi phải thêm khoảng thời gian, liệu ghi theo dạng ASCII có định dạng (như xuất hình) khơng phải theo định dạng nhị phân Vì vậy, tốc độ độ lớn tập tin đáng ngại, fread() fwrite() lựa chọn tốt 42 Lập trình C Tóm tắt Ngơn ngữ C khơng chứa câu lệnh nhập/xuất tường minh Tất thao tác nhập/xuất thực cách sử dụng hàm thư viện chuẩn C Có hai kiểu stream – stream văn stream nhị phân Một stream văn chuỗi ký tự Một stream nhị phân chuỗi byte Một tập tin từ tập tin đĩa đến thiết bị đầu cuối hay máy in Một trỏ tập tin trỏ trỏ đến cấu trúc, chứa thơng tin tập tin, bao gồm tên, vị trí hành tập tin, tập tin đọc ghi, có lỗi xuất hay đến cuối tập tin Hàm fopen() mở stream để dùng liên kết tập tin với stream Hàm fclose() đóng stream mở hàm fopen() Hàm fcloseall() sử dụng cần đóng nhiều stream mở lúc Hàm fputc() dùng để ghi ký tự, hàm fgetc() dùng để đọc ký tự từ tập tin mở Hàm fgets() fputs() thao tác giống hàm fgetc() fputc(), ngoại trừ chúng làm việc chuỗi Hàm feof() dùng để cuối tập tin tập tin mở cho thao tác nhị phân Hàm rewind() đặt lại vị trí trỏ định vị trí đầu tập tin Hàm ferror() xác định liệu thao tác tập tin có sinh lỗi hay khơng Hàm remove() xóa tập tin cho Hàm fflush() làm chép buffer Nếu tập tin mở để đọc, vùng đệm nhập trống, tập tin mở để ghi vùng đệm xuất ghi vào tập tin Hàm fseek() sử dụng để đặt lại vị trí trỏ định vị bên tập tin Các hàm thư viên fread() fwrite() dùng để đọc ghi toàn khối liệu vào tập tin Hệ thống nhập xuất có vùng đệm bao gồm hai hàm fprintf() fscanf(), hai hàm tương tự hàm printf() scanf(), ngoại trừ chúng thao tác tập tin Quản lý tập tin 43 Kiểm tra tiến độ học tập Có hai kiểu stream stream stream _ Các tập tin mở đóng lại chương trình bị treo hay kết thúc bất thường (Đúng /Sai) Hàm _ mở stream để dùng liên kết tập tin với stream Hàm dùng để ghi ký tự vào tập tin Hàm fgets() xem ký tự sang dòng phần chuỗi (Đúng / Sai) Hàm đặt lại vị trí trỏ định vị bên tập tin đầu tập tin Mỗi ký tự đọc hay ghi từ stream, _ tăng lên Các tập tin mà hàm fread() fwrite() thao tác phải mở chế độ Vị trí hành trỏ kích hoạt hành tìm thấy trợ giúp hàm 44 Lập trình C Bài tập tự làm Viết chương trình để nhập liệu vào tập tin in theo thứ tự ngược lại Viết chương trình để truyền liệu từ tập tin sang tập tin khác, loại bỏ tất nguyên âm (a, e, i, o, u) Loại bỏ nguyên âm dạng chữ hoa lẫn chữ thường Hiển thị nội dung tập tin Quản lý tập tin 45 46 Lập trình C ... mà khơng c? ? ký hiệu dùng để điểm kết th? ?c tập tin hay kết th? ?c record Kết th? ?c tập tin x? ?c định độ lớn tập tin 21.2 C? ?c hàm tập tin structure FILE Một tập tin tham chiếu đến gì: từ tập tin đĩa... tập tin (file pointer) c? ??n thiết cho vi? ?c đ? ?c ghi tập tin Nó trỏ đến structure chứa thông tin tập tin Thông tin bao gồm: tên tập tin, vị trí tập tin, tập tin đ? ?c hay ghi, c? ? lỗi xuất hay đến cuối... nghĩa Mở tập tin văn để đ? ?c Tạo tập tin văn để ghi Nối vào tập tin văn Mở tập tin văn để đ? ?c/ ghi Tạo tập tin văn để đ? ?c/ ghi Nối tạo tập tin văn để đ? ?c/ ghi Bảng 21.2: C? ?c chế độ mở tập tin văn