X: ARRAY[INTEGER] OF INTEGER; Y: ARRAY[REAL] OF INTEGER;
KIỂU DỮ LIỆU CÓ CẤU TRÚC: KIỂU TẬP TIN (FILE)
READ(FI, A,B, B);
Sở dĩ phải đọc cả giá trị của phần tử thứ 2 là vì đây là tập tin có cấu trúc tuần tự, muốn đọc phần tử thứ 3 thì ta buộc phải đọc qua phần tử thứ 2.
Thí dụ tiếp theo minh hoạ việc đọc tất cả các phần tử của một tập tin các số nguyên nào đó và ghi ra màn hình giá trị các số nguyên đó và cuối cùng ghi ra cả số phần tử của tập tin. Tên tập tin sẽ được xác định lúc chạy chương trình chứ không có ngay từ lúc lập trình (‘NGUYEN.DAT’). Do không biết tập tin kết thúc ở đâu nên ta phải dùng phép thử NOT EOF.
Program DOC_TEP_2; Var I: integer
SoPhanTu: integer; FI: File of integer; FileName: String[20]; Begin
Write(‘ Ten tep chua cac so nguyen: ‘); Readln(FileName);
ASSIGN(FI, FileName); RESET(FI);
SoPhanTu := 0;
WHILE NOT EOF(FI) DO Begin
End;
Read(FI,I); (* Đọc một phần tử tập tin ra biến I *) Writeln(I);
SoPhanTu := SoPhanTu + 1; (* Đếm số phần tử *)
End.
CLOSE(FI);
Writeln(‘ So phan tu cua tep ‘,FileName,’ la ‘, SoPhanTu);
Thí dụ tiếp theo minh hoạ việc copy từ một tập tin các số nguyên gọi là tập tin nguồn sang một tập tin khác. Chương trình được cho dưới dạng thủ tục.
TYPE
FI = File Of Integer; VAR
FS, FD: FI; (* FS: File Source, FD: File Destination *) Name1, Name2: String[30];
(*---*)
Procedure Copy_File_Int(Var Source, Destination: FI);
Var I: integer; Begin
Rewrite(Destination); While Not EOF(Source) Do Begin Read(Source, I); Write(Destination, I); End; Close(Source); Close(Destination); End; (*---*) Begin
Write(‘Copy from File: ‘); Readln(Name1); Write(‘ to File: ‘); Readln(Name2); Assign(FS, Name1);
Assign(FD, Name2); Copy_File_Int(FS,FD); Writeln(‘ End of Copy’); End.
T
ẬP TIN VỚI CÁC PHẦN TỬ CỦA TẬP TIN LÀ DỮ LIỆU CÓ CẤU TRÚC:
Các ví dụ trên mới chỉ đơn cử các chương trình xử lý các tập tin có các phần tử là các dữ liệu đơn giản như integer, real, … Tập tin cũng có thể dùng mảng hoặc bản ghi như là các phần tử của tập tin (xem FNS, F6 ở đầu chương).
Vì phần tử của tập tin là cả một bản ghi nên để ghi vào tập tin ta phải dùng
Write(FNS, Nguoi);
Chứ không thể ghi riêng rẽ từng thành phần, từng trường được như:
Write(FNS, Nguoi.Ten);
V./ T ẬP TIN TRUY NHẬP TRỰC TIẾP:
Pascal chuẩn chỉ định nghĩa một kiểu tập tin: tập tin truy nhập tuần tự. Tuy nhiên các bộ nhớ ngoài như đĩa mềm, đĩa cứng, … cho phép có thể tính toán toạ độ của một phần tử bất kỳ của tập tin vì độ dài của các phần tử trong tập tin là như nhau. Điều đó cho phép truy nhập trực tiếp vào tập tin mặc dù cấu tạo logic của tập tin vẫn là dạng tuần tự tức là phần tử nọ xếp sau phần tử kia. Trong một số chương trình Pascal gần đây đã có
một thủ tục để truy nhập trực tiếp: SEEK. Cách v i ết: SEEK(FileVar, No);
Với No là số thứ tự của phần tử trong tập tin. Cầ n lưu ý là phầ n tử đ ầu tiên c ủ a tập tin đư ợ c đ ánh số là 0 . Theo thủ tục này, máy sẽ đặt cửa sổ của tập tin vào phần tử thứ No. Sau đó ta chỉ việc dùng các thủ tục Read để đọc phần tử đó ra hoặc Write để đặt giá trị mới vào. Như vậy ta có thể cập nhật (update) một tập tin một cách dễ dàng.
Thí d ụ:
Giả sử một tập tin đã chứa 100 số nguyên từ 1 đến 100. Ta phải kiểm tra xem phần tử thứ 2 (đếm từ 0) của tập tin có giá trị bằng 3 không, nếu không bằng 3 thì phải sửa lại:
Var Begin … F: File of Integer; Ch: char; I: integer;
Assign(F, ‘SONGUYEN.DAT’); Reset(F);
SEEK(F, 2); (* Đặt cửa sổ vào vị trí thứ 3 *);
Writeln(‘ I = ‘,I);
Write(‘ Co sua lai khong ? (C/K)’); Readln(Ch); If Ch in [‘C’,’c’] then
Begin
End; …
SEEK(F, 2); (* Đặt lại cửa sổ vào vị trí thứ 3 *)
Write(‘ I = ‘); Readln(I);
Write(F, I); (* Thay đổi giá trị của tập tin *)
End. CLOSE(F);
Bạn có thể áp dụng kỹ thuật cập nhật này cho một ứng dụng phức tạp hơn. Ví dụ cập nhật một tủ hồ sơ cán bộ hay một kho tàng nào đó.
VI./ CÁC T H Ủ T ỤC VÀ HÀM XỬ LÝ TẬP TIN CỦA TURBO PASCAL.
FileSize(FileVar) Hàm cho số phần tử của tập tin FileVar. Hàm nhận giá trị 0 nếu
tập tin rỗng, không có phần tử nào
FilePos(FileVar) Hàm cho vị trí tức thời của con trỏ tập tin (cửa sổ) của tập
tin
Erase(FileVar) Thủ tục xóa file trên đĩa có tên đã được ấn định với FileVar.
Rename(FileVar, Str); Thủ tục cho phép thay đổi tên tập tin với tên kiểu String
chứa trong xâu Str. Bạn càn lưu ý phát hiện tên mới phải không trùnh với một tên tập tin nào có sẵn trên danh mục đĩa đang làm việc.
VII./ TẬP TIN VĂN BẢN: (TEXT FILES)
Trong Pascal có một kiểu tập tin đã được định nghĩa trước, đó là tập tin văn bản được định nghĩa với từ chuẩn
TEXT.
Thí d ụ: khai báo các biến tập tin F1, F2 có kiểu TEXT VAR
F1, F2: TEXT;
Các phần tử của tập tin kiểu TEXT là các kí tự (các chữ viết) song Text File khác với File of Char ở chỗ tập tin văn bản được tổ chức thành từng dòng với độ dài mỗi dòng khác nhau nhờ có thêm các dấu hết
dòng (End Of Line) hay dấu chấm xuống dòng. Đó là cặp kí tự điều khiển: CR (Carriage Return: nhảy về
đầu dòng, mã số ASCII = 13) và LF (Line Feed: nhảy thẳng xuống dòng tiếp theo, mã số ASCII = 10). Chúng được nhận dạng để ngăn cách giữa hai dãy kí tự tương ứng với hai dòng khác nhau. Dấu CR và LF được màn hình cũng như máy in dùng làm kí tự điều khiển việc xuống đầu dòng tiếp theo. Trong chừng mực nào đó không chính xác lắm, tập tin văn bản có thể được coi là tập tin các Record (là các dòng kí tự) có độ dài thay đổi.
Thí dụ đ oạn vă n bản sau: VI DU VAN BAN 1234
HET
Được hiểu là máy sẽ chứa trong tập tin văn bản thành một dãy như sau:
VI DU VAN BAN CR LF 1234 CR LF HET EOF
Bạn cũng cần biết rằng các file có tên *.PAS, *.BAS, *.C … là các tập tin thuộc loại văn bản, được dùng để ghi các văn bản là các chương trình PASCAL, BASIC hay C.
Do tập tin văn bản được tổ chức thành từng dòng nên việc ghi (write) và đọc (read) tập tin văn bản cũng có thêm thủ tục ghi và đọc theo dòng là Readln(Read Line) và Writeln (Write Line). Chúng ta sẽ nghiên cứu kĩ thêm dưới đây.
Mặc dù tập tin văn bản chứa các kí tự nhưng các thủ tục Read(ln), Write(ln) có những khả năng đặc biệt để ghi và đọc được cả các số nguyên (integer), số thực (real), boolean hoặc string nhờ sự chuyển đổi thích hợp giữa các giá trị này với các dãy kí tự.
VIII./ GHI VÀO TẬP TIN VĂN BẢN:
Chúng ta có thể ghi các giá trị kiểu integer, real, boolean, string vào tập tin văn bản bằng lệnh write hoặc writeln. Cách ghi này cho phép chuyển các giá trị bằng số sang dạng kí tự, tức là dưới dạng đọc được một cách tường minh như trên trang giấy viết bình thường, cho phép viết các biểu bảng dữ liệu,… với qui cách mong muốn.
Các cách viết
Có 3 dạng viết thủ tục
Write(FileVar, Item1, Item2, … ItemN); Writeln(FileVar, Item1, Item2, … ItemN); Writeln(FileVar);
Thủ tục Write(FileVar, Item1, Item2, …, ItemN); sẽ viết các giá trị của các Item1, Item2, …, ItemN, là các biến, các hằng hoặc biểu thức có kiểu đơn giản như Integer, Real, Char, String, Boolean vào biến tập tin FileVar. Các Item1, Item2, …, ItemN không nhất thiết phải là cùng kiểu.
Thí d ụ: Var I, J: integer; X: real; B: Boolean; S5: String[5]; Ta có thể viết:
Write(FileVar, ‘Thi du: ‘, I, X, J, S5, 6, X + I);
Trong đó Item là: Xâu kí tự, các biến, hằng, biểu thức
Thủ tục Write để ghi vào tập tin văn bản sẽ không chấp nhận Item là các biến có cấu trúc (Array, Set, Record và File). Ví dụ không thể viết:
Write(FileVar, Nguoi);
Vì Nguoi là biến có cấu trúc. Cách viết này chỉ được chấp nhận khi FileVar không phải là tập tin văn bản mà là tập tin chứa các bản ghi NhanSu như ta đã thấy ở phần trước.
Thủ tục Writeln(FileVar, Item1, Item2, …, ItemN); sẽ thực hiện việc đưa thêm dấu hiệu hết dòng vào tập tin sau khi đã viết hết các giá trị các biến.
Thủ tục Writeln(FileVar); sẽ chỉ thực hiện việc đưa thêm dấu hiệu hết dòng (cặp kí tự điều khiển CR và LF) vào tập tin, tức là đưa dấu cách dòng vào tập tin.
Như vậy thủ tục Writeln(FileVar, Item1, Item2, …, ItemN); có thể được thực hiện bằng nhiều thủ tục Write với Writeln ở cuối cùng như sau (dạng khối lệnh)
BEGIN END; Write(FileVar, Item1); Write(FileVar, Item2); … Write(FileVar, ItemN); Writeln(FileVar);
Cách viết có qui cách (format): tùy vào từng kiểu dữ liệu mà cách viết có khác nhau đôi chút. N
ếu VI là kí h i ệu b i ểu thức ng u yên: Write(FileVar, VI);
Sẽ viết vào tập tin FileVar giá trị nguyên VI với đúng số chữ số cần thiết:Write(FileVar, VI:n);
Giả sử VI có giá trị bằng 12345
Write(FileVar, VI, VI); cho ra 1234512345 Write(FileVar, VI:8, VI:8); cho ra ___12345___12345 N
ếu VR là b i ểu t h ức thực: Write(FileVar, VR:n);
Cho ra cách biểu diễn số thực dạng có số mũ E tức là dạng viết khoa học của dấu phẩy động, với n chỗ được căn lề bên phải. Trong cách biểu diễn này các chữ số chiếm chỗ như sau:
#.#######E%##
n-6 4
1 chữ số chữ số với # kí hiệu một chữ số bất kì. % kí hiệu hoặc dấu + hoặc dấu –
Như vậy số chữ số chiếm từ chữ E trở đi luôn luôn là 4 (kí tự E cùng với hai chữ số nguyên có dấu). Bên cạnh đó là một chỗ cho dấu chấm và một chữ số trước dấu chấm. Tổng số chỗ bắt buộc phải có là 6. Số chỗ còn lại trong qui cách viết này là n-6 được giành cho các chữ số sau dấu chấm, còn gọi là các chữ số có nghĩa.
Thí d ụ: VR := 123.123456;
Write(FileVar, VR:8); cho ra 1.23E+02
Write(FileVar, VR:n:m);
Máy sẽ bố trí n chỗ cho số thực VR trong đó có m chỗ giành cho phần thập phân (m chữ số sau dấu chấm) và căn lề bên phải. Nếu m = 0, máy sẽ chỉ đưa ra phần nguyên của VR.
Thí
du: VR = 123.123456;
Write(FileVar, VR:10:2); cho ra ____123.12 10 chỗ với 2 chỗ thập phân
Write(FileVar, VR:15:9); cho ra __123.123456000
N