Dữ liệu kiểu tệp trong Pascal

Xin chào các bạn, Hôm nay WIKIPASCAL sẽ hướng dẫn các bạn về Dữ liệu kiểu tệp trong Pascal

Du lieu kieu tep trong Pascal
Dữ liệu kiểu tệp trong Pascal


I – Khái niệm và định nghĩa

Tệp hay tệp dữ liệu là một tập hợp các dữ liệu có liên quan với nhau và có cùng kiểu được nhóm lại với nhau tạo thành một dãy. Chúng thường được chứa trong một thiết bị nhớ ngoài của máy tính (ví dụ như đĩa mềm, đĩa cứng, băng từ...) với một cái tên nào đó.

Tệp dữ liệu với dữ liệu được hiểu theo nghĩa rộng : đó có thể là chương trình, có thể là số liệu, có thể là các dữ liệu khác như kí tự, văn bản...

Tệp còn có tệp có định kiểu, tệp văn bản và tệp không định kiểu (sẽ học kĩ ở cuối chương) .

Để dễ hình dung ra tệp, chúng ta hãy xem tổ chức tủ phiếu của thư viện. Các dữ liệu cho một cuốn sách là tên sách, tên tác giả, giá tiền, số trang, nhà xuất bản... Các dữ liệu này được nhóm lại với nhau để tạo thành các tờ phiếu, mỗi tờ phiếu đóng vai trò là một phần tử của tệp dưới dạng một Record (bản ghi) . Đây cũng là lý do gắn liền khái niệm cấu trúc dữ liệu Record với cấu trúc File.
Các phần tử của tệp (các Record) có cùng một kiểu dữ liệu (Ví dụ các phiếu thư viện đều giống nhau ở chỗ mỗi cái đều có tên sách, tên tác giả, nhà xuất bản...) . Các phiếu này được xếp lại thành một tệp (phiếu) và được để vào một ô ngăn kéo nào đó với một cái tên (tên tệp) . Ví dụ ngăn chữ A (tên tệp là A) là tệp các cuốn sách có tên bắt đầu bằng chữ A. Các ngăn kéo lại được chứa trong một cái tủ. Trong máy tính, một đĩa cứng hoặc một một đĩa mềm đóng vai trò là chiếc tủ.

File còn được gọi là hồ sơ, là tập tin.

Tệp thường được chứa trong một bộ nhớ ngoài như đĩa cứng, đĩa mềm, băng từ. Điều đó cũng có nghĩa là tệp được lưu trữ để dùng nhiều lần và tồn tại ngay cả khi chương trình kết thúc hoặc mất điện. Khác với các cấu trúc dữ liệu khác mà chúng ta đã học như : mảng, tập hợp, bản ghi, là các cấu trúc dữ liệu được tổ chức trên bộ nhớ trong (RAM) của máy tính nên một khi kết thúc chạy chương trình hoặc mất điện thì các dữ liệu này cũng mất luôn. Vì vậy những dữ liệu nào cần lưu trữ (như hồ sơ cán bộ, vật tư hàng hóa của kho, tín hiệu điện...) thì ta bắt buộc phải dùng đến tệp.
Bên cạnh đó một số thiết bị ngoại vi như bàn phím, màn hình, máy in được coi như là một tệp (xem phần tệp văn bản ở sau) . Tệp cũng còn có thể tổ chức trong bộ nhớ trong của máy song đó là những tệp tạm thời, trung gian vì chúng không lưu trữ lại được khi dừng chương trình hoặc mất điện.

Tệp là một kiểu dữ liệu có cấu trúc. Định nghĩa của tệp có phần nào giống mảng ở chỗ chúng đều là tập hợp của các phần tử dữ liệu có cùng kiểu. Song mảng được định nghĩa và khai báo trong chương trình với số phần tử đã xác định còn số phần tử của tệp không được xác định khi định nghĩa.

Định nghĩa một kiểu tệp T với các phần tử có kiểu là KPT (Kiểu phần tử) được viết trong phần mô tả kiểu với từ khóa FILE OF như sau :


Code:
Type

  T = File Of KPT ;


Sau đó khai báo một biến tệp (FileVar) trong phần khai báo biến :

Code:
Var

  Biến_tệp : Kiểu_tệp ;

hoặc khai báo trực tiếp một biến tệp với mô tả kiểu :

Var

  Biến_tệp : File Of Kiểu_phần_tử ;


Ví dụ:

Code:
Type

  FileInteger = File Of Integer ;

  FileReal = File Of Real ;

  FileBoolean = File Of Boolean ;

  NhanSu = Record

  Ten : String[ 30 ] ;

  Tuoi : Byte ;

  Luong : Real ;

  End ;

  FileNhanSu = File Of NhanSu ;

Var (* khai báo các biến tệp *)

  F1, F2 : FileInteger ; (* F1, F2 là hai biến tệp có các phần tử là số nguyên *)

  F3 : FileReal ; (* F3 là tệp các số thực *)

  FNS : FileNhanSu ; (* FNS là tệp các bản ghi nhân sự *)

  F5 : File Of Char ;

  F6 : File Of

  Array[ 1.. 5 ] Of Integer ;



F6 là biến tệp được khai báo trực tiếp trong phần Var với các phần tử là mảng một chiều, độ dài mảng là 5.

FileInteger là kiểu tệp có các phần tử là số nguyên.

FileReal là kiểu tệp có các phần tử là số thực.


Kiểu của phần tử của tệp có thể là bất kỳ kiểu dữ liệu nào (kiểu vô hướng, kiểu có cấu trúc như mảng, tập, bản ghi) , trừ kiểu tệp nghĩa là không có kiểu tệp của tệp.


II – Cấu trúc và phân loại tệp


Các phần tử của một Array hoặc một Record có thể truy nhập được tùy ý (Random Access) thông qua tên biến, chỉ dẫn hoặc tên trường. Các phần tử của tệp không có tên và việc truy nhập không thể tùy tiện được. Các phần tử của tệp được sắp xếp thành một dãy và ở mỗi thời điểm chương trình chỉ có thể truy nhập vào một phần tử của tệp thông qua giá trị của một biến đệm (Tampon Variance). Biến đệm được dùng để đánh dấu vị trí truy nhập hay còn được gọi là cửa sổ (Window) của tệp.

Có những lệnh sẽ làm dịch chuyển cửa sổ sang vị trí tiếp theo hoặc về vị trí đầu của tệp. Ta có thể hình dung ra tệp như là một cuộn phim chụp ảnh. Mỗi một ảnh là một phần tử và ống kính là cửa sổ để nhìn vào nên tại mỗi thời điểm chỉ nhần thấy một ảnh. Sau mỗi lần chụp, cửa sổ sẽ nhìn vào ảnh ở vị trí tiếp theo.

Mỗi tệp đều được kết thúc bằng một dấu hiệu đặc biệt để báo hết tệp, hay gọi là EOF (End Of File). Pascal có một hàm chuẩn (Function) EOF, kiểu Boolean, với tham số là một biến tệp để thử xem cửa sổ đã đặt vào vị trí kết thúc tệp đó chưa. Nếu cửa sổ còn chưa trỏ vào phần tử cuối tệp thì EOF(F) có giá trị là False.

Việc phân loại tệp dựa trên việc bố trí các phần tử của tệp trong bộ nhớ ngoài và cách truy nhập vào tệp : tệp truy nhập tuần tự(Sequential Access), tệp truy nhập trực tiếp(Direct Access).

Thông dụng nhất là tệp có cấu trúc tuần tự : việc đọc một phần tử bất kỳ của tệp bắt buộc phải tuần tự đi qua các phần tử trước đấy. Còn muốn ghi hay thêm một phần tử vào tệp, ta cần phải đặt cửa sổ vào vị trí cuối tệp. Kiểu truy nhập này là đơn giản nhất trong việc xây dựng tệp cũng như xử lý tệp, song nó kém linh hoạt, Bộ nhớ ngoài điển hình tương ứng với cấu trúc này là băng từ.

Tệp truy nhập trực tiếp (direct access) là tệp có thể đặt cửa sổ vào một phần tử bất kỳ của tệp thông qua chỉ số thứ tự của phần tử trong tệp. Không phải loại bộ nhớ ngoài nào cũng có thể xây dựng tệp truy nhập trực tiếp do cấu tạo bộ nhớ.
Ví dụ băng từ là loại chỉ có thể truy nhập tuần tự. Còn đĩa mềm, đĩa cứng là loại bộ nhớ có thể tạo tệp truy nhập trực tiếp do đầu từ ghi đọc có thể được điều khiển đặt vào một chỗ bất kỳ trên đĩa vào mọi thời điểm. Bạn có thể so sánh giữa băng từ ghi nhạc (bắt buộc truy nhập tuần tự) với đĩa hát (có khả năng truy nhập trực tiếp).

Pascal chuẩn chỉ định nghĩa loại tệp tuần tự và dưới đây nếu không nói rõ tệp loại gì thì ta hiểu đó là tệp tuần tự. Sau đó chúng ta sẽ nghiên cứu thêm về tệp truy nhập trực tiếp, được Turbo Pascal cũng như các ngôn ngữ khác đưa vào dùng nhiều.

III – Mở tệp để cất dữ liệu

Chương trình chỉ có thể cất dữ liệu vào một tệp sau khi ta làm thủ tục mở tệp . Việc mở tệp có thể ví như muốn cất các phếu thư viện thì đầu tiên phải đóng ô phiếu mới và gắn tên ô phiếu .


Để mở tệp để ghi, Turbo Pascal dùng 2 cặp thủ tục đi liền nhau theo thứ tự :

Code:
Assign ( Biến_tệp, Tên_tệp ) ;

Rewrite ( Biến_tệp ) ;

hay bằng tiếng Anh ta có :

Assign ( FileVar, FileName ) ;

Rewrite ( FileVar );


Ví dụ:
Code:
Assign ( F,'nguyento.dat' ); (* gán tên tệp nguyento.dat cho biến F *)

Reset ( F ); 



Tên tệp (FileName) là tên của tệp đặt trong thiết bị nhớ ngoài được đưa vào dưới dạng một String. Ta phải đặt tên tệp sao cho nó phản ánh được ý nghĩa hoặc bản chất, nội dung của tệp. Ví dụ biến tệp F chứa các số nguyên tố thì tệp được đặt tên là ‘nguyento.dat’.

Tên tệp theo quy định chung gồm có hai phần cách nhau bằng dấu chấm (.) . Phần thứ nhất là phần tên riêng, có số chữ nhiều nhất là 8 . Phần tên này thể hiện nội dung của tệp đó . Phần thứ hai là phần mở rộng có nhiều nhất là 3 chữ, thông thường nói lên loại tệp .


Ví dụ :

* . Pas: là tệp chứa chương trình viết bằng Pascal .

* . Doc: là tệp chứa văn bản, tài liệu .

* . Txt : chứa tệp văn bản .

* . Com và * . Exe: là các tệp chứa chương trình dưới dạng mã mà máy có thể chạy ngay được trên máy tính .

* . Dat: chứa các dữ liệu cần xử lý ( Data )


Sau khi mở tệp xong, tệp sẽ rỗng vì chưa có phần tử nào, cửa sổ tệp sẽ không có giá trị xác định vì nó trỏ vào cuối tệp (EOF). Đồng thời cần lưu ý khi mở tệp nếu trên bộ nhớ ngoài mà đã có sẵn tệp có tên trùng với tên tệp được mở thì tệp cũ sẽ bị xóa đi .


GHI CÁC GIÁ TRỊ VÀO TỆP VỚI THỦ TỤC WRITE :


Thủ tục WRITE sẽ đặt các giá trị mới vào tệp giống như ta bấm máy chụp ảnh . Mỗi lần chụp xong một ảnh, máy sẽ tự động đưa ống kính sang vị trí tiếp theo .


Cách viết :

Code:
Write ( FileVar, Item1, Item2, . ., ItemN ) ;

hay Write ( Biến_tệp, các giá trị cần đặt vào ) ;



Trong đó Item1, Item2, . . . ItemN có thể là các hằng, các biến, các biểu thức, tất nhiên các Item phải có giá trị cùng với kiểu phần tử của tệp.

Hoặc với I, J, K là các biến Integer thì ta hoàn toàn có thể viết :


Code:
Write ( F, 3, I + 2 * J, K ) ;



Bước cuối cùng của việc đặt dữ liệu vào tệp là đóng tệp lại bằng thủ tục


Code:
Close ( Biến_tệp ) ;



Ví dụ đối với tệp F1: Close ( F1 ) ;


Ví dụ 1: Sau đây chúng ta viết một thí dụ hoàn chỉnh : tạo một tệp chứa các số nguyên từ 1 đến 100 với tên tệp là ‘Nguyen . dat’ .


Code:
Program TAO_TEP_1 ;

Var

  I : Integer ;

  F : File Of Integer ;

BEGIN

  Assign ( F, 'Nguyen.dat' ) ;

  Rewrite ( F ) ;

  For I :=1 To 100 Do Write ( F, I ) ;

  Close ( F ) ;

END .



Một tệp có thể đựoc dùng làm tham số của chương trình con (Procedure hoặc Function) với lời khai báo bắt buộc phải sau chữ Var tức là tệp được dùng làm tham biến .

Ví dụ 2 :

Code:
 Program TAO_TEP_2 ;

Type

  F1 = File Of Integer ;

  St30 = String [ 30 ] ;

Var

  MyFile : F1 ;

  FileName : St30 ;

(* ----------------------------------------------------- *)

Procedure TaoFile ( Var F : F1 ; Ten : St30 ) ;

Var

  I : Integer ;

Begin

  Assign ( F, Ten ) ;

  Rewrite ( F ) ;

  For I := 1 To 100 Do Write ( F, I ) ;

  Close ( F ) ;

End ;

(* ----------------------------------------------------- *)

BEGIN

  Write (' Ten tep : ') ;

  Readln ( FileName ) ;

  TaoFile ( MyFile, FileName ) ;

END .



Ví dụ trên còn gài thủ thuật gài tên rtệp vào khi chương trình chạy thông qua một biến FileName, tương ứng với tham số hình thức là Ten.


IV – Đọc dữ liệu từ tệp


Một tệp tuần tự được dùng như là đầu ra để cất dữ liệu thì cùng một lúc không thể làm đầu vào ( nguồn ) dữ liệu được, nghĩa là đối với tệp tuần tự, ta không thể vừa ghi vừa đọc cùng một lúc. Sau khi ghi dữ liệu vào tệp và đóng lại, bạn có thể đọc lại các giá trị dữ liệu trong tệp.

Một chương trình muốn sử dụng các dữ liệu đã được chứa trong một tệp đầu tiên chương trình phải mở tệp đó ra để đọc. Các thủ tục dùng cho công việc này như sau :


·MỞ TỆP ĐỂ ĐỌC :



Code:
Assign ( Biến_tệp, Tên_tệp ) ;

Reset ( Biến_tệp ) ;

hay Assign ( FileVar, FileName ) ;

Reset ( FileVar ) ;



Khi chạy, chường trình sẽ đọc phần tử dữ liệu tại vị trí cửa sổ đang trỏ. Sau lệnhReset, nếu tệp không rỗng thì cửa sổ bao giờ cũng trỏ vào phần tử đầu tiên của tệp và chương trình sẽ copy phần tử của tệp được trỏ sang biến đệm cửa sổ.


·ĐỌC DỮ LIỆU TỪ TỆP :

Việc đọc các phần tử từ tệp ra sau khi mở tệp đựoc thực hiện bằng thủ tục READ


Cách viết :

Code:
Read ( Biến_tệp, các biến ) ;

hoặc Read ( FileVar, Var1, Var2,... VarN ) ;



Thực hiện : đọc các giá trị tại vị trí cửa sổ đang trỏ (nếu có) gán sang biến tương ứng cùng kiểu. Sau đó cửa sổ dịch chuyển sang vị trí tiếp theo và đọc giá trị cho biến khác. Cứ thế đọc cho đến biến VarN.

Một điều cần lưu ý là trong thủ tục Read ta chỉ có thể đọc giá trị của tệp để gán giá trị cho các biến và chỉ cho các biến mà thôi. Không như trong thủ tục ghi vào tệp, các tham số thực là các Item ( hằng, biến, biêu thức ).

Việc đọc một phần tử của tệp còn cần có một điều kiện : phải thử xem tệp có còn phần tử không tức là cửa sổ chưa trỏ đến EOF. Hàm chuẩnEOFsẽ báo cho biết : nếu cửa sổ trỏ vào cuối tệp thì EOF(Biến_tệp) = True, còn nếu cửa sổ chưa trỏ vào phần tử cuối của tệp thìEOF(Biến_tệp) = False. Do vậy trước khi làm một thao tác gì để đọc tệp gán cho biến X, cần phải thử xem tệp đó đã kết thúc chưa bằng câu lệnh :


Code:
If Not Eof ( Biến_tệp ) Then Read ( Biến_tệp, X ) ;



hoặc nếu muốn đọc các phần tử của tệp :


Code:
 While Not Eof ( Biến_tệp ) Do

  Begin

  Read ( Biến_tệp, X ) ; (* Đọc các phần tử của tệp *)

  ................... (* Xử lý biến X, nếu cần *)

  End ;



Nếu cửa sổ đã trỏ đến phần Eof mà chương trình vẫn cố tình đọc thì sẽ gặp sai và máy sẽ báo lỗi, sau đó chương trình dừng lại.

Công việc cuối cùng kết thúc việc đọc tệp là đóng tệp lại với thủ tục giống như khi tạo tệp mới :


Close ( Biến_tệp ) ;


Bây giờ chúng ta lấy ví dụ cụ thể. Giả sử tồn tại một tệp có tên là ‘Nguyen.dat’ được tạo ra bằng các thủ tục mở tệp cất dữ liệu như ở trên đã mô tả. Ta phải đọc ra giá trị thứ nhất và thứ ba của tệp và gán cho hai biến A, B tương ứng. Giả sử tệp không rỗng và chứa ít nhất 3 phần tử để ta không phải dùng phép thử Eof.


Ví dụ 3 :


Code:
Program DOC_TEP_1 ;

Var

  A, B : Integer ;

  F : File Of Integer ;

BEGIN

  Assign ( F, 'Nguyen.dat' ) ;

  Reset ( F ) ;

  Read ( F, A ) ; (* Đọc phần tử thứ nhất của tệp và chứa vào biến A *)

  Read ( F, B ) ; (* Đọc phần tử thứ hai của tệp và chứa vào biến B *)

  Read ( F, B ) ; (* Đọc phần tử thứ ba của tệp và chứa vào biến B,

lúc này B không giữ giá trị của phần tử thứ hai nữa *)

  Close ( F ) ;

END.



Sở dĩ phải đọc cả phần tử thứ hai là vì đây là tệp có cấu trúc tuần tự, muốn đọc phần tử thứ ba thì phải đọc qua phần tử thứ hai.


Ví dụ tiếp theo minh họa việc đọc tất cả các phần tử của một tệp 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. Tên tệp 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. Do không biết tệp kết thúc ở đâu nên ta phải dùng phép thử Not Eof.


Ví dụ 4 :

Code:
 Program DOC_TEP_2 ;

Var

  I : Integer ;

  SoPhanTu : Integer ;

  F : File Of Integer ;

  FileName : String [ 20 ] ;

BEGIN

  Write ( ' Ten tep chua cac so nguyen : ' ) ;

  Readln ( FileName ) ;

  Assign ( F, FileName ) ;

  Reset ( F ) ;

  SoPhanTu := 0 ;

  While Not Eof ( F ) Do

  Begin

  Read ( F, I ) ; (* Đọc một phần tử tệp ra biến I *)

  Writeln ( I ) ;

  SoPhanTu := SoPhanTu + 1 ; (* Đếm số phần tử *)

  End ;

  Close ( F ) ;

  Writeln ( ' So phan tu cua tep ', FileName, ' la ', SoPhanTu ) ;

END.



Ví dụ tiếp theo minh họa việc Copy từ một tệp các số nguyên gọi tệp nguồn sang một tệp khác. Chương trình được cho dưới dạng thủ tục.


Ví dụ 5 :


Code:
Type

F : File Of Integer ;

Var

  FS, FD : F ; (* FS : FileSource ( File nguồn ), FD : File Destination ( File đích ) *)

  Name1, Name2 : String [ 30 ] ;

(* ------------------------------------------------------------- *)

Procedure CopyFile ( Var Source, Destination : F ) ;

Var

  I : Integer ;

Begin

  Reset ( Source ) ;

  Rewrite ( Destination ) ;

  While Not Eof ( Source ) Do

  Begin

  Read ( Source, I ) ;

  Write ( Destination, I ) ;

   End ;

  Close ( Source ) ;

  Close ( Destination ) ;

End ;

(* ------------------------------------------------------------- *)

BEGIN

  Write ('Copy form file ') ; Readln ( Name1 ) ;

  Write (' to file ') ; Readln ( Name2 ) ;

  Assign ( FS, Name1 ) ;

  Assign ( FD, Name2 ) ;

  CopyFile ( FS, FD ) ;

  Writeln (' Copy successful ') ;

END.



* Tệp với các phần tử của tệp 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ìng xử lý các tệp có các phần tử là các dữ liệu đơn giản như Integer, Real... Tệp cũng có thể dùng mảng hoặc bản ghi như các phần tử của tệp (xem tệp FNS, F6 ở đầu chương).


Ví dụ với FNS, các phần tử của tệp FNS là bản ghi thì để ghi vào tệp ta phải dùng :


Write ( FNS, Nguoi ) ;


chứ không thể ghi riêng rẽ từng phần, từng trường :


Write ( FNS, Nguoi.ten ) ;

V – Tệp truy nhập trực tiếp

Pascal chuẩn chỉ định nghĩa một kiểu tệp : tệp truy nhập tuần tự. Các bộ nhớ ngoài như đĩa mềm, đĩa cứng... cho phép có thể tính toán tọa độ của một phần tử bất kỳ của tệp vì độ dài của các phần tử trong tệp là như nhau. Điều đó cho phép truy nhập trực tiếp vào tệp mặc dù cấu tạo logic của tệp vẫn là dạng tuần tự tức là phần tử nọ xếp sau phần tử kia. Trong Pascal có một thủ tục để truy nhập trực tiếp :SEEK.


* Cách viết : Seek ( FileVar, No );


với No là số thứ tự của phần tử trong tệp. Cần lưu ý là phần tử đầu tiên của tệp được đánh số 0.


Theo thủ tục này, máy sẽ đặt cửa sổ của tệp 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 một tệp một cách dễ dàng.


Ví dụ: Giả sử một tệp đã chứa 100 số nguyên từ 1 đến 100. Ta phải kiểm tra xem phần tử thứ hai (đếm từ 0) của tệp có giá trị bằng 3 không, nếu không bằng 3 thì phải sửa lại :



Code:
Var

  F : File Of Integer ;

  Ch : Char ;

  I : Integer ;

BEGIN

  ...........

  Assign ( F, 'Songuyen.dat' ) ;

  Reset ( F ) ; 

  Seek ( F, 2 ) ; (* đặt cửa sổ vào vị trí thứ 3 *)

  Read ( F, I ) ;

  Writeln ( ' I = ', I ) ;

  If I <> 3 Then Write ( F, 3 ) ; (* nếu không bằng 3 thì sửa lại *)

  Close( F ) ;

END.


VI – Xử lí tệp



Code:
FileSize ( FileVar ) ;


Hàm cho số phần tử của tệp FileVar. FileSize nhận giá trị 0 khi tệp rỗng, không có phần tử nào.


Code:
FilePos ( FileVar ) ;


Hàm cho vị trí tức thời của con trỏ tệp ( cửa sổ ) của tệp FileVar. Phần tử đầu tiên là phần tử số 0.


Ứng dụng: một tệp đã tồn tại chỉ có thể cho lớn lên tức là thêm số phần tử vào tệp bằng cách đặt thêm phần tử mới vào vị trí cuối cùng của tệp. Vì vậy con trỏ tệp có thể đặt vào vị trí cuối tệp bằng lệnh sau :


Code:
Seek ( FileVar, FileSize ( FileVar ) ) ;




Trong ví dụ ở bài trước, nếu muốn thêm số liệu I vào tệp F, ta viết :


Code:
 Seek ( F, FileSize ( F ) ) ;

   Write ( F, I ) ;



Mọi sự thay đổi vể tệp chỉ được giữ lại trên đĩa khi thực hiện thủ tục Close( F ).


Code:
 Erase ( FileVar ) ;


Thủ tục xóa file trên đĩa có tên đã được ấn định với FileVar.


Ví dụ : muốn xóa file File.exe trên đĩa, ta viết :


Code:
Assign ( F, 'File.exe' ) ;

  Erase ( F ) ;



Rename ( FileVar, Str ) ; 

Thủ tục cho phép they đổi tên tệp thành tên chứa trong chuỗi Str. Bạn cần lưu ý là tên mới không được trùng với tên nào trên thư mục đang làm việc.


Ví dụ : muốn đổi tên tệp từ ‘File.old’ sang ‘File.new’, ta viết :


Code:
 Assign ( F, 'File.old' ) ;

Rename ( F, 'File.new' ) ;



VII – Tệp văn bản (Text file *.txt)


Trong Turbo Pascal có một kiểu tệp được định nghĩa trước, đó là tệp văn bản được định nghĩa với từ chuẩn Text


Ví dụ : khai báo các biến tệp F1, F2 có kiểu Text :


Var

F1, F2 : Text ;


Các phần tử của tệp kiểu text là các kí tự song Text File khác với File Of Char ở chỗ Text File đượ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ã ASCII = 13) và LF (Line Feed: nhảy thẳng xuống dòng tiếp theo, mã ASCII = 10). Chúng được nhận dạng để ngăn cách giữa hai dãy kí tự tuơ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.


Ví 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 văn bản thành một dãy như sau :

vi du van ban CR LF 1234 CR LF het EOF


Do tệp văn bản được ghi thành từng dòng nên việc ghi và đọc tệp văn bản cũng có thêm thủ tục ghi và đọc theo dòng là Writeln (Write Line) và Readln (Read Line). Chúng ta sẽ nghiên cứu kĩ thêm dưới đây.

Mặc dù tệp văn bản chứa các kí tự nhưng các thủ tục Read(ln) và Write(ln) có những khả năng đặc biệt để ghi và đọc được cả những số nguyên, số thực, 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ự.


A. GHI VÀO TỆP VĂN BẢN:

Chúng ta có thể ghi các giá trị kiểu Integer, Real, Boolean, String vào tệp 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ạng đọc được một cách tường minh như trên trang giấy, cho phép viết các bảng dữ liệu... với quy cách mong muốn.



Các cách viết :



Code:
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 Item, 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, Boolean, String vào biến tệp FileVar. Các Item không nhất thiết phải cùng kiểu.


Ví dụ :
Code:
Var

  I, J : Integer ;

  X : Real ;

  B : Boolean ;

  S5 : String [5] ;


Ta có thể viết :
Code:
Write ( FileVar, ' Vi du ', I, J, X, B, S5, 6, X + I ) ;



_ Thủ tục Write để ghi vào tệp 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 :


Code:
Write ( FileVar, Nguoi ) ; (* Với Nguoi là một Record *) 



vì Nguoi là một 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 biến tệp mà là tệp chứa các bản ghi NhanSu như ta đã thấy ở các 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 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, tức là đưa dấu cách dòng vào tệp.


* Cách viết có quy cách 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à biểu thức nguyên :

+Write ( FileVar, VI ) ;sẽ viết vào tệp FileVar giá trị nguyên VI với đúng số chữ số cần thiết.

+Write ( FileVar, VI : n ) ;sẽ bố trí n chỗ cho giá trị nguyên VI và căn lề bên phải.

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à một biểu thứ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. Số chữ số từ chữ E trở đi luôn luôn là 4 kí tự ( kí tự E rồi đến dấu+hoặc-, cuối cùng là 2 chữ số ). 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ố còn lại trong quy cách viết này là n - 6 chỗ được dành cho các chữ số sau dấu chấm, còn gọi là các chữ số có nghĩa.



Ví dụ:

Code:
VR = 123. 123456

  Writeln ( FileVar, VR : 8 ) ; cho ra 1.23E + 02   



+Write( FileVar, VR : n : m ) ; máy sẽ bố trí n chỗ cho số thực 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.


Ví dụ :

Code:
VR = 123.123456

Write ( FileVar, VR : 10 : 2 ) ; cho ra ____123.12

  Write ( FileVar, VR : 15 : 9 ) ; cho ra __123.123456000



_ Nếu VC là một kí tự ( Char )

+Write ( FileVar, VC : n ) ;cho ra giá trị của VC với n chỗ được căn lề bên phải. Nếu n > 1, máy sẽ cho ra thêm n - 1 dấu cách vào trước kí tự VC


Ví dụ :

Code:
CH = 'H' ;

Write ( FileVar, VC : 1 ) ; cho ra H

Write ( FileVar, VC : 2 ) ; cho ra _H



_ Nếu VS là một biểu thức kí tự hoặc String

+Write ( FileVar, VS : n ) ; cho ra giá trị của VS với n chỗ được căn lề bên phải. Nếu n < độ dài của String thì máy sẽ cắt bớt các chữ cuối của String đi.


Ví dụ :

Code:
 Write ( FileVar, 'Hello' : 1 ) ; cho ra H

Write ( FileVar, 'Hello' : 3 ) ; cho ra Hel

  Write ( FileVar, 'Hello' : 10 ) ; cho ra _____Hello




Ví dụ tổng hợp :

Code:
Var

  Ketqua : Text ;

  A : Integer ;

  B : Real ;

  C : String [ 20 ] ;

  D : Boolean ;

BEGIN

  A : = 34 ;

  B : = 3.14 ;

  C : = ' END. ' ;

  D := True ;

  Assign ( Ketqua,' Ketqua.txt ' ) ;

  Rewrite ( Ketqua ) ;

  Write ( Ketqua,' Ket qua la : ' ) ;

  Writeln ( Ketqua, A : 10, B : 10 : 4, C ) ;

  Writeln ( ' Dong 2 ' : 10, D ) ;

  Close ( Ketqua ) ;

END.



Kết quả hiện ra trong file Ketqua.txt :



Kết qua la : 34 3.1400 END.

Dong 2 True


Mặc dù A là một số nguyên nhưng thủ tục Write sẽ tự động chuyển sang dạng kí tự tức là dạng đọc được. Máy sẽ dành cho A 10 chỗ, vì A chỉ có 2 chữ số nên 8 chỗ còn lại đều là khoảnh trắng. Tương tự B được viết ra trong khuôn khổ 10 chỗ với 4 chỗ dành cho phần thập phân. Còn D là biến Boolean nên máy sẽ tự động in ra các từ 'TRUE' hoặc 'FALSE' tương ứng.


B) ĐỌC DỮ LIỆU TỪ TỆP VĂN BẢN:

Chúng ta có thể đọc không những các kí tự từ tệp văn bản mà còn có thể đọc lại các số nguyên, các số thực, Bolean từ tệp văn bản thông qua thủ tục :


Code:
Read ( FileVar, Var1, Var2,... VarN ) ;

  Readln ( FileVAr, Var1, Var2,... VarN ) ;

Readln ( FileVar ) ;



Trong đó Var1, Var2,... VarN là các biến thuộc kiểu Char, String, Integer, Real, Boolean và muốn đọc cho đúng thì trong tệp văn bản các kí tự tương ứng từ vị trí đọc (vị trí cửa sổ) cũng phải diễn tả đúng các kiểu dữ liệu cần đọc trên.

Thủ tục Readln (FileVar, Var1, Var2,... VarN); sẽ đưa cửa sổ tệp sang đầu dòng tiếp theo sau khi đã lần lượt đọc các biến tương ứng.

Thủ tục Readln (FileVar) sẽ đưa cửa sổ tệp sang đầu dòng đầu tiên mà không đọc gì cả.


Hàm chuẩn kiểu Boolean EOLN( F ) sẽ phát hiện ra dấu hết dòng EOLN(End Of Line) của tệp F, tránh sai sót khi đọc quá dòng. Khi EOF = True thì EOLN cũng bằng True.


Việc đọc văn bản có thể chia làm hai loại :

+ Xử lý văn bản, các kí tự.

+ Đọc dữ liệu số nguyên, số thực từ tệp văn bản.


Ví dụ về xử lý văn bản :

Hãy lập một chương trình đếm số chữ trong một tệp văn bản F.


Code:
Program DEM_CHU ;

Var

  F : Text ;

   Ch : Char ;

  I : Integer ;

  FileName : String [ 30 ] ;

BEGIN

  Write ( ' Ten tep : ' ) ; Readln ( FileName ) ;

  Assign ( F, FileName ) ;

  Reset ( F ) ;

  I : = 0 ; (* I : Biến đếm *)

  While Not Eof ( F ) Do

   Begin

  While Not Eoln ( F ) Do

  Begin

  Read ( F, Ch ) ;

  I := I +1 ;

  End ;

  Readln ( F ) ;

  End ;

  Writeln (' So chu la : ', I ) ;

  Close ( F ) ;

END.



* Khi đọc dữ liệu số nguyên, số thực từ tệp văn bản, thủ tục Read và Readln sẽ tự động biến đổi một xâu kí tự thích hợp trong tệp văn bản sang các số nguyên và số thực. Dấu cách được xem là dấu ngăn cách giữa các số.



Ví dụ: với I là số nguyên và J là số thực thì để đọc giá trị của I, J từ tệp F, ta dùng lệnh :

Read ( F, I, J ) ;


* Thủ tục Seek, hàm FileSize,FilePos không áp dụng cho tệp văn bản vì Text được tính theo đơn vị là dòng (kí tự) với độ dài dòng thay đổi, chúng ta không thể tính toán vị trí đặt con trỏ. Tuy nhiên, Turbo Pascal có hai hàm xử lý Text :


Code:
SeekEoln ( FileVar ) :



Hàm kiểu Boolean, tương tự như hàm Eoln song trước khi thử Eoln nó nhảy qua các dấu cách Space và Tab.


Code:
 SeekEof ( FileVar ) ;



Hàm kiểu Boolean, tương tự như hàm Eof song trước khi thử Eof nó nhảy qua các dấu cách Space,Tab và các dấu cách dòng.

Như vậy thủ tục Read và Readln đối với tệp văn bản có thể đọc được nhiều kiểu biến khác nhau ghi trong tệp văn bản ( Integer, Real, Boolean, Char, String ).


Ví dụ ứng dụng :

Giả sử rằng chúng ta cần lưu trữ và xử lý các tham số là nhiệt độ (số nguyên), áp suất (số thực), độ ẩm (số nguyên) của nhiều ngày trong tháng (cần ghi rõ cả ngày). Sau đó các dữ liệu này được xử lý bằng một chương trình độc lập khác. Bạn có thể tạo ra một tệp văn bản chứa các dữ liệu với các quy định như sau :

_ Dòng 1 chứa tên

_ Dòng 2 chứa đường gạch nét cho đẹp và rõ ràng.

_ Từ dòng 3 trở đi cho hết tệp : chứa dữ liệu với thứ tự : ngày của tháng, nhiệt độ, áp suất, độ ẩm.


Chúng ta có thể tổ chức dữ liệu thành tệp các Record như sau :


Code:
Type

  Du_lieu = Record

  Ngay : byte;

  Nhietdo : Integer ;

  ApSuat : Real ;

  DoAm : Integer ;

  End ;

Var

  F : File Of Du_lieu ;



Nhược điểm của phương pháp cất dữ liệu dưới dạng văn bản là số ô nhớ chiếm nhiều hơn. Ví dụ khi NhietDo là 1656, nếu dùng mã Integer thì luôn luôn mất 2 byte, nếu dùng mã kí tự thì mất 4 byte chứa các kí tự '1' '6' '5' '6'. Song nhược điểm này chỉ là phụ.
Tuy nhiên chúng ta nên dùng tệp văn bản để xử lý. Ưu điểm của việc dùng tệp văn bản chứa dữ liệu là ta có thể dùng các chương trình soạn thảo văn bản ( các Editor như Editor của Turbo Pascal ) và sau đó có thể xem bằng mắt, sửa, cập nhật các dữ liệu một cách dễ dàng. Chắc bạn sẽ thắc mắc thêm : tại sao không đưa dữ liệu vào qua bàn phím lúc chạy chương trình ? Nếu làm như vậy bạn sẽ không mất chỗ trên đĩa từ song có hai nhược điểm lớn sau : nếu số liệu gõ vào sai thì bạn không sửa lại được nữa và nếu chương trình có sai sót nào đó thì bạn sẽ phải sửa chương trình và cho chạy lại chương trình với việc nhập dữ liệu mới ( qua bàn phím ). Điều này thực sự mất rất nhiều thời gian nếu số liệu có nhiều.

Sau khi quy định cách viết văn bản chứa dữ liệu, chúng ta phải tuân thủ quy định về dòng để đọc lại dữ liệu khi cần xử lý. Các dữ liệu trong một dòng cách nhau bằng dấu cách (Space) với số lượng khônh hạn chế, chủ yếu là do cách trình bày. Giả sử tệp văn bản có tên là Thang6.dat được tạo ra với nội dung như sau :


Code:
Dòng 1 THOI TIET THANG 6 NAM 2002

Dòng 2 .......................................................

Dòng 3 1 30 298.5 45

Dòng 4 2 35 100.8 24

............. .......................................................


Chương trình dưới đây sẽ đọc lại các dữ liệu của từng ngày để xử lý, với giả thiết 2 dòng đầu (các dòng không chứa dữ liệu chắc chắn tồn tại nên chương trình sẽ không kiểm tra EOLN trước khi đọc). Sau đó chương trình sẽ lần lượt đọc từng dòng số liệu. Với giả thiết số dòng chứa số liệu cũng không biết trước nên ta dùng vòng While.

Sau khi xử lý số liệu, chúng ta có thể thông báo số ngày (tương ứng với số dòng chứa số liệu).

Code:
 Program DOC_DU_LIEU ;

Var

  F : Text ;

  NhietDo, DoAm : Integer ;

  Ngay : Byte ;

  ApSuat : Real ;

  SoNgay : Byte ;

BEGIN

  Assign ( F, ' Thang6.dat ' ) ;

  Reset ( F ) ;

  Readln ( F ) ; (* nhảy qua dòng 1 *)  

  Readln ( F ) ; (* nhảy qua dòng 2 *)

  SoNgay := 0 ;

  While Not SeekEoln ( F ) Do

  Begin

  (* Đọc số liệu từng ngày một *)

  Readln ( F, Ngay, NhietDo, ApSuat, DoAm ) ;

  SoNgay := SoNgay + 1 ;

  (* Xử lý dữ liệu tùy theo yêu cầu của bài toán *)

  ...

  End ;

  Writeln ( ' Ket qua xu ly cua ', SoNgay,' ngay la : ' ) ;

  ...

  Close ( F ) ;

END.


Một tệp văn bản có thể nạp vào bộ nhớ trong để xử lý cho nhanh dưới dạng một mảng (Array) các String. Tất nhiên trước khi khai báo mảng chúng ta phải dự phòng xem tệp văn bản có nhiều nhất bao nhiêu dòng (700 trong ví dụ dưới đây), và mỗi dòng sẽ có nhiều nhất bao nhiêu ký tự. Việc khai báo với kích thước dự phòng này sẽ rất phí ô nhớ, nếu không dùng hết. Sau đó mọi xử lý văn bản có thể được xử lý không phải trên tệp nữa mà là trên mảng ô nhớ như đếm số chữ, đếm số từ... Cuối cùng là cất mảng văn bản vào tệp ban đầu nếu muốn.

Code:
Var

  VanBan : Array [1.. 700] Of String [80] ;   

  F :Text ;

  I, SoDong : Integer ;

  Name : String [30] ;

BEGIN

  (* Đọc tệp văn bản vào mảng *)

  Name := 'Vidu.txt' ;

  Assign ( F, Name ) ;

  Reset ( F ) ;

  I := 1 ;

  While Not Eof ( F ) Do

  Begin

  Readln ( F, VanBan [ I ] ) ; (* Đọc một dòng vào một chuỗi *)

  I := I + 1 ;

  End;

  SoDong := I - 1 ;

  Close ( F ) ;

  (* Xử lý văn bản trên mảng VanBan *)

  ...

  (* Cất lại vào tệp nếu muốn. Xin giành cho bạn đọc *)

  ...

END.



·Lưu ý : số dòng và số chữ của một dòng trong khai báo VanBan ở trên bị hạn chế vì trên máy tính, bộ nhớ cho khai báo các biến bị chặn trên là 64 KB. Muốn mở rộng, bạn cầ tham khảo biến động và con trỏ ở chương sau.


Việc xử lý các dữ liệu ít khi làm thẳng với tệp (không chỉ là tệp văn bản mà cả với tệp kiểu khác nữa) do tốc độ ghi / đọc của đĩa từ chậm hơn tốc độ ghi/ đọc của bộ nhớ trong. Người lập trình nên tổ chức các cấu trúc dữ liệu khác ( mảng, tập... ) là các kiểu dữ liệu nằm trong bộ nhớ trong của máy.C) KIỂM TRA TỆP KHI MỞ:


Nhiều vấn đề còn nảy sinh ra khi làm việc với tệp như: khi dùng Reset( F ) liệu tệp F đã tồm tại chưa, khi ghi vào tệp F thì liệu trên đĩa có còn đủ chỗ chứa thêm dữ liệu mới của F hay không ? Turbo Pascal cung cấp lời hướng dẫn ( directive ) cho chương trình dịch để đóng/mở (bật/tắt) việc kiểm tra lỗi sai trong quá trình vào ra tệp :

{$I+} mở việc kiểm tra. Khi gặp lỗi vào/ra chương trình sẽ báo lỗi và dừng lại. Đây là chế độ ngầm định (by default), nghĩa là chương trình dịch luôn luôn thực hiện chế độ nếu không được báo rõ.

{$I+} không kiểm tra lỗi vào/ra, chương trình không dừng lại nhưng sẽ treo tất cả các thủ tục vào/ra khác cho đến khi có lời gọi hàm kết quả IOResult (hàm có sẵn của Turbo Pascal, có kiểu là Integer). Khi có lời gọi hàm IOResult thì điều kiện sai bị xóa bỏ và các thủ tục vào/ra khác có thể tiếp tục hoạt động trở lại. Lúc này nhiệm vụ xử lý lỗi là của người lập trình. Hàm IOResult = 0 nếu mọi việc xảy ra tốt đẹp. Sau đây là một ví dụ nhỏ về kiểm tra vào/ra khi mở file để đọc :


Code:
 Program OpenInputFile ;

 Var

  OK : Boolean ;

  FileName : String ;

  F : Text ;

 BEGIN

  Repeat

  Write ( ' Ten tep : ' ) ;

  Readln ( FileName ) ;

  Assign ( F, FileName ) ;

  {$I-} (* chuyển việc kiểm tra vào / ra cho người dùng *)

  Reset ( F ) ;

  OK := IOResult = 0 ;

  {$I+} (* Sau khi dùng IOResult ta có thể chuyển thành $I+ *)

  If not OK Then Write (' Khong mo tep voi ten nay duoc ') ;

  Until OK ;

 END.



Toàn bộ các lỗi sai khi vào ra được liệt kê trong phần phụ lục dưới dạng một thủ tục IOCheck. Mặt khác bạn cũng cần lưu ý {$I-} và IOResult được dùng không chỉ với thủ tục Reset mà còn với các thủ tục khác như Erase, Rename, Write, Read...

VIII – Tệp không định kiểu


Tệp không định kiểu là một kiểu file đặc biệt, được định nghĩa ra trong Turbo Pascal và nó là một công cụ mạnh để bạn có thể khai thác. Đó là tệp mà khi định nghĩa hay khai báo ra, ta không nói rõ nó chứa gì, không nói rõ bản chất của các dữ liệu được ghi trong đó. Vì vậy việc chuyển dữ liệu từ đĩa vào cấu trúc dữ liệu của bạn sẽ được thực hiện ngay lập tức. Đó là lí do vì sao Tệp không định kiểu được sử dụng rộng rãi trong các ứng dụng đòi hỏi tốc độ cao.


Cách khai báo : tên tệp theo sau từ khóa File.

Ví dụ:


Code:
Program CopyFile ;

 Uses Crt ;

 Var

  SF, DF : File ;

  (* SF : Source File Tệp nguồn, DF : Destination File Tệp đích *)

  Buffer : Array[ 1..1000 ] Of Byte ;

  I : Integer ;

  Traloi : Char ;

 BEGIN

  ClrScr ;

  If ParamCount <> 2 Then

  Begin

  Writeln ( #7,' Copy File [ From File ] [ To File ] ' ) ;

  Halt ;

  End ;

  Assign ( SF, ParamStr(1) ) ;

  { $I- } (* Tắt chế độ tự kiểm tra lỗi vào ra *)

  Reset ( SF, 1 ) ;

  { $I+ } (* Bật chế độ tự kiểm tra lỗi vào ra *)

  If IOResult <> 0 Then

  Begin 

  Writeln ( #7,' Khong co tep ', ParamStr(1) ) ;

  Halt ; (* Kết thúc chương trình *)

  End ;

  Assign ( DF, ParamStr(2) ) ;

  { $I- } (* Tắt chế độ tự kiểm tra lỗi vào ra *)

  Reset ( SF, 1 ) ;

  { $I+ } (* Bật chế độ tự kiểm tra lỗi vào ra *)

  If IOResult = 0 Then

  Begin

  Writeln ( #7, ParamStr(2),' Da ton tai tren dia ! ' ) ;

  Write ( #7,' Co ghi de len khong (Y / N ) : ' ) ;

  Readln ( Traloi ) ;

  If ( Upcase ( Traloi ) = 'N' ) Or ( Upcase ( Traloi ) = 'K' ) Then

  Halt ; (* Kết thúc chương trình *)

  End ;

  Rewrite ( DF, 1 ) ;

  Writeln ('. = 1000 bytes copied ') ;

  BlockRead ( SF, Buffer, SizeOf( Buffer ), I ) ;

  While I > 0 Do

  Begin

  Write('. ') ;

  BlockWrite ( DF, Buffer, I ) ;

  BlockRead ( SF, Buffer, SizeOf( Buffer ), I ) ;

  End ;

  Close ( SF ) ; 

  Close ( DF ) ;

 END.



Giả sử chương trình trên được viết vào file Copy1.pas và được dịch thành Copy1.exe. Để copy từ file File1.dat thànhFile2.dat, bạn phải gõ :


Code:
 C:\ Copy1 File1.dat File2.dat


( Lưu ý rằng file Copy1.exe phải có sẵn trong thư mục C:\)


Turbo Pascal đã định nghĩa sẵn biến ParamCount để đếm số tham số của dòng lệnh trên. Nó sẽ đếm các cụm chữ cách nhau bằng các dấu Space nằm sau tên chương trình, tức là ParamCount bằng 2 vì có hai cụm chữ là File1.dat File2.dat. Hai cụm chữ này đồng thời được gán cho các biến có sẵn là ParamStr(1) và ParamStr(2) tương ứng. Nghĩa làParamStr(1) sẽ nhận giá trị là File1.dat còn ParamStr(2) sẽ nhận giá trị là File2.dat.

SD,SF ở đây là hai tệp không định kiểu, vì vậy sau chữ File không có thêm kiểu phần tử của File.

Không như các tệp văn bản hay tệp có định kiểu, thủ tục Reset và Rewrite đối với tệp không định kiểu SF,DF còn có thêm một tham số nữa, đó là kích thước của Record. Ví dụ Reset ( SF, 1 ) có nghĩa là chuẩn bị File để đọc và độ dài của Record là bằng 1 byte. Điều này làm cho ta có cảm giác SF như là Array Of Byte. Còn nếu Reset ( SF, 2 ) thì ta có thể coi SF là Array Of Integer. Nếu chỉ ghi Reset ( SF ) thì máy sẽ coi độ dài Record là 128 byte.

Việc ghi và đọc đối với tệp không định kiểu còn dùng đến 2 thủ tục là BlockRead và BlockWrite.


Ví dụ :

Code:
BlockRead ( SF, Buffer, SizeOf( Buffer ), I ) ;



Thủ tục dùng với 4 tham số :

_ Tham số thứ nhất : biến file SF.

_ Tham số thứ hai : nơi dữ liệu được đọc vào là Buffer.

Để điền hết dữ liệu vào nơi đọc, cần đưa tham số thứ ba là kích thước của Buffer, bằng 1000 trong trường hợp khai báo Buffer ở đây. Tuy nhiên, Turbo Pascal đã cung cấp cho bạn hàm SizeOf để lấy kích thước của mọi biến. Cách viết như thế này có cái lợi là mỗi khi bạn cần thay đổi độ dài của Buffer thì chỉ cần thay đổi trong phàn khai báo mà không phải thay nó trong mọi thủ tục BlockRead và BlockWrite.

Tham só cuối cùng là biến I, kiểu Integer, được dùng để nhận biết có bao nhiêu Record đã được đọc từ đĩa vào Buffer. Nhiều khi file trên đĩa đã hết dữ liệu, không đủ điền hết Buffer. Tham số thứ tư này có giá trị bằng 0 báo rằng hết dữ liệu để đọc.

Thủ tục BlockWrite hoạt động tương nhưng chỉ cần 3 tham số. Tham số thứ ba là số Record thực sự cần ghi vào đĩa chứ không phải là kích thước của Buffer. Đó là giá trị được ghi trong biến I.

Nhận xét

Bài đăng phổ biến từ blog này