Bài giảng Kỹ thuật lập trình - Chương 7: Tệp
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Kỹ thuật lập trình - Chương 7: Tệp", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên
Tài liệu đính kèm:
- bai_giang_ky_thuat_lap_trinh_chuong_7_tep.pdf
Nội dung text: Bài giảng Kỹ thuật lập trình - Chương 7: Tệp
- BÀI GIẢNG HỌC PHẦN KỸ THUẬT LẬP TRÌNH CHƯƠNG 7: TỆP
- Nội dung 7.1. Khái niệm tệp 7.2. Tệp văn bản 7.3. Tệp nhị phân 2
- 7.1. Khái niệm tệp • Tệp: là một tập hợp các dữ liệu cùng kiểu, có liên quan với nhau, được nhóm lại với nhau thành một dãy và thường được lưu trữ trên các thiết bị nhớ ngoài dưới một tên gọi nào đó. Tệp tồn tại ngay cả khi chương trình đã kết thúc hoặc tắt máy, thường được lưu trữ để sử dụng lâu dài • Khi khai báo biến tệp không cần xác định số phần tử của tệp • Khi lưu trữ, các phần tử của tệp được sắp xếp thành một dãy các byte liên tiếp nhau, sau phần tử dữ liệu cuối cùng là phần tử EOF (mã kết thúc tệp) • 2 loại tệp: tệp văn bản, tệp nhị phân 3
- 7.2. Tệp văn bản • Khai báo tệp văn bản • Mở tệp văn bản • Đóng tệp văn bản • Đọc/ghi một ký tự với tệp văn bản • Đọc/ghi theo kiểu văn bản • Đọc/ghi một xâu ký tự 4
- Khai báo tệp văn bản • Tệp văn bản: - Lưu trữ dữ liệu dưới dạng ký tự - Có 2 cách truy xuất theo kiểu ký tự: + Truy xuất theo từng ký tự + Truy xuất theo từng dòng • Cú pháp khai báo biến tệp: FILE *con_trỏ_tệp; Ví dụ: FILE *fp; 5
- Mở tệp văn bản (1) • Cú pháp: con_trỏ_tệp = fopen("tên_tệp", "kiểu_truy_nhập"); - Hàm fopen nếu mở tệp thành công sẽ trả về con trỏ tệp cho tệp được mở, nếu tệp cần mở không tồn tại trên ổ đĩa thì hàm fopen trả về giá trị NULL - "tên_tệp" có thể bao gồm cả đường dẫn đầy đủ tới tệp Ví dụ: "C:\SV\tepvanban.txt" 6
- Mở tệp văn bản (2) • Cú pháp: (tiếp) - "kiểu_truy_nhập" có thể nhận các giá trị sau: "r" mở tệp để đọc, nếu tệp chưa tồn tại thì báo lỗi "w" mở tệp mới để ghi, nếu tệp đã tồn tại sẽ bị xóa "a" mở tệp để ghi bổ sung vào cuối tệp, nếu tệp chưa tồn tại thì tạo tệp mới "r+" mở tệp để cập nhật (đọc/ghi), nếu tệp chưa tồn tại thì báo lỗi "w+" mở tệp mới để đọc/ghi, nếu tệp đã tồn tại sẽ bị xóa "a+" mở tệp để đọc/ghi bổ sung vào cuối tệp, nếu tệp chưa tồn tại thì tạo tệp mới - Ví dụ: fp = fopen("C:\SV\tepvanban.txt", "w"); 7
- Đóng tệp văn bản • Cú pháp: fclose(con_trỏ_tệp); - Các thao tác thực hiện: + Đẩy dữ liệu còn trong vùng đệm lên đĩa (khi đang ghi) + Xóa vùng đệm (khi đang đọc) + Giải phóng biến con trỏ để nó có thể dùng cho tệp khác. Nếu thành công hàm cho giá trị 0, trái lại hàm cho EOF • Ví dụ: fclose(fp); 8
- Đọc/ghi một ký tự với tệp văn bản (1) • Ghi ký tự vào tệp: Có thể sử dụng 1 trong 2 hàm: putc(ch, fp); fputc(ch, fp); trong đó: ch là một giá trị nguyên (coi là không dấu), fp là con trỏ tệp Hàm ghi lên tệp ký tự có mã bằng m = ch % 256 Nếu thành công hàm cho mã ký tự được ghi, nếu không hàm cho EOF Nếu m=10, hàm sẽ ghi lên tệp 2 mã 13 và 10 9
- Đọc/ghi một ký tự với tệp văn bản (2) • Đọc ký tự từ tệp: Có thể sử dụng 1 trong 2 hàm: getc(fp); fgetc(fp); trong đó: fp là con trỏ tệp Hàm đọc một ký tự từ tệp Nếu thành công hàm cho mã ký tự đọc được ( [0,255], nếu gặp cuối tệp hoặc có lỗi thì hàm cho EOF Hàm đọc một lượt cả 2 mã 13 và 10 rồi trả về giá trị 10 Khi gặp mã 26 thì hàm trả về EOF 10
- Đọc/ghi theo kiểu văn bản (1) • Ghi dữ liệu theo định dạng: fprintf(fp,xâu_định_dạng, danh_sách_tham_số); trong đó: fp là con trỏ tệp Giá trị các tham số được ghi lên tệp theo định dạng trong xâu_định_dạng Nếu thành công hàm trả về giá trị nguyên bằng số byte dữ liệu được ghi lên tệp, khi có lỗi thì hàm cho EOF 11
- Đọc/ghi theo kiểu văn bản (2) • Đọc dữ liệu theo định dạng: fscanf(fp,xâu_định_dạng, danh_sách_tham_số); trong đó: fp là con trỏ tệp Đọc dữ liệu từ tệp, biến đổi theo định dạng và lưu kết quả vào các tham số Hàm trả về giá trị bằng số trường được đọc 12
- Đọc/ghi một xâu ký tự (1) • Ghi một xâu ký tự vào tệp: fputs(s,fp); trong đó: - s là con trỏ trỏ tới địa chỉ đầu của một xâu ký tự kết thúc bằng ký tự '\0' - fp là con trỏ tệp Ghi xâu s lên tệp fp (không ghi ký tự '\0' vào tệp) Nếu thành công hàm trả về ký tự cuối cùng được ghi vào tệp, khi có lỗi thì hàm cho EOF 13
- Đọc/ghi một xâu ký tự (2) • Đọc một xâu ký tự từ tệp: fgets(s,n,fp); trong đó: - s là con trỏ (kiểu char) trỏ tới một vùng nhớ đủ lớn để lưu xâu ký tự đọc được từ tệp - n là số nguyên xác định độ dài cực đại của xâu cần đọc - fp là con trỏ tệp Đọc một xâu ký tự từ tệp fp lưu vào vùng nhớ s 14
- Đọc/ghi một xâu ký tự (3) • Đọc một xâu ký tự từ tệp: (tiếp) Quá trình đọc kết thúc khi: + Hoặc đã đọc n-1 ký tự + Hoặc gặp dấu xuống dòng (cặp mã 13 10), khi đó mã 10 được đưa vào xâu kết quả + Hoặc kết thúc tệp Xâu kết quả được bổ sung thêm ký tự '\0' Khi đọc thành công, hàm trả về địa chỉ vùng nhận kết quả, nếu có lỗi hoặc đọc hết tệp thì hàm trả về giá trị NULL 15
- Ví dụ (1) • Chương trình đọc/ghi từng dòng văn bản: #include int main(void) { FILE *fp; int i; char s[256]; fp = fopen("vanban.txt","w"); 16
- Ví dụ (2) i=0; while(1) { i++; printf("Nhap dong thu %d (nhan Enter de ket thuc):",i); fflush(stdin); gets(s); if (s[0]=='\0') break; if (i>1) fputc(10,fp); fputs(s,fp); } fclose(fp); 17
- Ví dụ (3) printf("Van ban da nhap la:\n"); fp = fopen("vanban.txt","r"); while (!feof(fp)) { fgets(s,256,fp); printf("%s",s); } fclose(fp); return 0; } 18
- 7.3. Tệp nhị phân • Khai báo tệp nhị phân • Mở tệp nhị phân • Đóng tệp nhị phân • Đọc/ghi một ký tự với tệp nhị phân • Đọc/ghi một số nguyên • Đọc/ghi một mẫu tin • Truy cập ngẫu nhiên 19
- Khai báo tệp nhị phân • Tệp nhị phân: - Dùng để lưu trữ dữ liệu theo dạng “nhị phân” • Cú pháp khai báo biến tệp: tương tự như tệp văn bản FILE *con_trỏ_tệp; Ví dụ: FILE *fp; 20
- Mở tệp nhị phân • Cú pháp: tương tự như tệp văn bản con_trỏ_tệp = fopen("tên_tệp", "kiểu_truy_nhập"); Tuy nhiên "kiểu_truy_nhập" có thể nhận các giá trị: "rb" mở tệp để đọc, nếu tệp chưa tồn tại thì báo lỗi "wb" mở tệp mới để ghi, nếu tệp đã tồn tại sẽ bị xóa "ab" mở tệp để ghi bổ sung vào cuối tệp, nếu tệp chưa tồn tại thì tạo tệp mới "r+b" mở tệp để cập nhật (đọc/ghi), nếu tệp chưa tồn tại thì báo lỗi "w+b" mở tệp mới để đọc/ghi, nếu tệp đã tồn tại sẽ bị xóa "a+b" mở tệp để đọc/ghi bổ sung vào cuối tệp, nếu tệp chưa tồn tại thì tạo tệp mới • Ví dụ: fp = fopen("C:\SV\songuyen.dat", "wb"); 21
- Đóng tệp nhị phân • Cú pháp: tương tự như tệp văn bản fclose(con_trỏ_tệp); • Ví dụ: fclose(fp); 22
- Đọc/ghi một ký tự với tệp nhị phân Tương tự như tệp văn bản • Ghi một ký tự vào tệp: Có thể sử dụng 1 trong 2 hàm: putc(ch, fp); fputc(ch, fp); • Đọc ký tự từ tệp: Có thể sử dụng 1 trong 2 hàm: getc(fp); fgetc(fp); trong đó: ch là một giá trị nguyên (coi là không dấu) fp là con trỏ tệp • Lưu ý: khác với tệp văn bản, việc đọc/ghi các ký tự có mã bằng 10, 13, 26 với tệp nhị phân được thực hiện bình thường 23
- Đọc/ghi một số nguyên (1) • Ghi một số nguyên vào tệp: putw(n,fp); trong đó: n là giá trị nguyên cần ghi vào tệp, fp là con trỏ tệp Ghi giá trị n vào tệp fp dưới dạng 2 byte Khi ghi thành công, hàm trả về giá trị n, khi có lỗi hàm trả về EOF 24
- Đọc/ghi một số nguyên (2) • Đọc một số nguyên từ tệp: getw(fp); trong đó: fp là con trỏ tệp Đọc một số nguyên từ tệp fp Khi đọc 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 25
- Đọc/ghi một mẫu tin (1) • Thường áp dụng với dữ liệu kiểu thực, kiểu cấu trúc • Ghi một mẫu tin vào tệp: fwrite(p,a,n,fp); trong đó: - p là con trỏ kiểu void trỏ tới vùng nhớ chứa dữ liệu cần ghi - a là kích thước của mẫu tin (tính bằng byte) - n là số mẫu tin cần ghi - fp là con trỏ tệp Ghi n mẫu tin kích thước a byte từ vùng nhớ p vào tệp fp Hàm trả về một giá trị bằng số mẫu tin thực sự ghi được 26
- Đọc/ghi một mẫu tin (2) • Đọc một mẫu tin từ tệp: fread(p,a,n,fp); trong đó: - p là con trỏ kiểu void trỏ tới vùng nhớ chứa dữ liệu đọc được - a là kích thước của mẫu tin (tính bằng byte) - n là số mẫu tin cần đọc - fp là con trỏ tệp Đọc n mẫu tin kích thước a byte từ tệp fp và lưu vào vùng nhớ p Hàm trả về một giá trị bằng số mẫu tin thực sự đọc được 27
- Truy cập ngẫu nhiên (1) • Con trỏ tệp: Mỗi tệp có một con trỏ xác định vị trí đọc/ghi trên tệp (con trỏ chỉ vị - file position locator). Khi mở tệp để đọc/ghi, con trỏ luôn trỏ vào đầu tệp (trừ trường hợp tệp được mở theo chế độ đọc/ghi bổ sung thì con trỏ ở cuối tệp) • Đọc/ghi dữ liệu tuần tự: (theo hướng từ đầu đến cuối tệp) đọc/ghi tại vị trí hiện tại của con trỏ, sau khi hoàn thành, con trỏ dịch chuyển một số byte bằng số byte đã đọc/ghi Hạn chế 28
- Truy cập ngẫu nhiên (2) • Truy cập ngẫu nhiên: (tiếp) - Hàm chuyển con trỏ chỉ vị về đầu tệp: rewind(fp); trong đó fp là con trỏ tệp 29
- Truy cập ngẫu nhiên (3) • Hàm chuyển con trỏ đến vị trí bất kỳ: fseek(fp,m,n); trong đó: + fp là con trỏ tệp + m (kiểu long) là số byte cần di chuyển, m>0 di chuyển về cuối tệp, m<0 di chuyển về đầu tệp + n (kiểu int) là vị trí xuất phát, có thể nhận giá trị: n = SEEK_SET hoặc 0: Xuất phát từ đầu tệp n = SEEK_CUR hoặc 1: Xuất phát từ vị trí con trỏ hiện tại n = SEEK_END hoặc 2: Xuất phát từ cuối tệp Hàm trả về giá trị 0 khi di chuyển thành công, khác 0 trong trường hợp có lỗi 30
- Truy cập ngẫu nhiên (4) • Hàm trả về vị trí hiện tại của con trỏ: ftell(fp); trong đó: fp là con trỏ tệp Hàm trả về vị trí hiện tại của con trỏ (byte thứ mấy trên tệp fp). Số thứ tự của byte được tính từ 0 Khi có lỗi hàm trả về -1L 31
- Truy cập ngẫu nhiên (5) • Ví dụ: Xét tệp fp có 3 ký tự 'A' , 'B', 'C' Lệnh 1: fseek(fp,0,SEEK_END); Con trỏ ở cuối tệp và ftell(fp) = 3 Lệnh 2: fseek(fp,-1,SEEK_END); Con trỏ đặt ở ký tự 'C' và ftell(fp) = 2 Lệnh 3: fseek(fp,0,SEEK_SET); Con trỏ đặt ở ký tự 'A' và ftell(fp) = 0 32
- Ví dụ (1) • Chương trình đọc/ghi danh sách n cán bộ: #include typedef struct { char macb[6]; char hoten[30]; char mapb[6]; }canbo; int main(void) { canbo cb; FILE *fp; int i,n; 33
- Ví dụ (2) fp = fopen("canbo.dat","wb"); printf("Nhap so can bo n = ");scanf("%d",&n); for(i=1;i<=n;i++) { printf("Nhap can bo thu %d\n",i); fflush(stdin); printf("Ma can bo: ");gets(cb.macb); printf("Ho ten: ");gets(cb.hoten); printf("Ma pb: ");gets(cb.mapb); fwrite(&cb,sizeof(canbo),1,fp); } fclose(fp); 34
- Ví dụ (3) printf("Danh sach can bo vua nhap la:\n"); fp = fopen("canbo.dat","rb"); while (fread(&cb,sizeof(canbo),1,fp)>0) printf("%-6s %-30s %-6s\n", cb.macb,cb.hoten,cb.mapb); fclose(fp); return 0; } 35
- Một số hàm xử lý tệp (1) Áp dụng cho cả tệp văn bản và tệp nhị phân • Đóng tất cả các tệp đang mở: fcloseall(void); Nếu thành công hàm trả về số tệp đóng được, ngược lại cho EOF • Làm sạch vùng đệm của tệp fp: fflush(fp); //fp là con trỏ tệp Nếu thành công hàm trả về giá trị 0, ngược lại cho EOF • Làm sạch vùng đệm của tất cả các tệp đang mở: fflushall(void); Nếu thành công hàm trả về số tệp đang mở, ngược lại cho EOF 36
- Một số hàm xử lý tệp (2) • Kiểm tra lỗi: ferror(fp);//kiểm tra lỗi thao tác trên tệp fp Hàm cho giá trị 0 nếu không có lỗi, ngược lại cho giá trị khác 0 • Thông báo lỗi hệ thống: perror(s); //s là con trỏ trỏ tới 1 xâu ký tự Hàm in xâu s và thông báo lỗi • Kiểm tra cuối tệp: feof(fp); //fp là con trỏ tệp Hàm cho giá trị bằng 0 khi đọc đến cuối tệp, khác 0 trong trường hợp ngược lại 37
- Một số hàm xử lý tệp (3) • Xóa tệp: unlink(s); //s là tên tệp cần xóa Hàm cho giá trị 0 khi xóa thành công, ngược lại cho EOF Cũng có thể sử dụng hàm sau để xóa tệp: remove(s); //s là tên tệp cần xóa • Ví dụ về kiểm tra lỗi khi mở tệp: FILE *fp; fp = fopen("dulieu","rb"); if(fp==NULL) perror("Loi khi mo tep du lieu!"); 38