25/05/2018, 07:25

Những đặc điểm bổ sung về file

Khi một đơn vị file trong các lệnh nhập hoặc xuất là tên của một biến ký tự, thì lệnh sẽ chuyển dữ liệu từ một vùng lưu giữ nội tại trong bộ nhớ sang một vùng khác. Những vùng lưu giữ này được gọi là các file nội tại (internal file). Thí ...

Khi một đơn vị file trong các lệnh nhập hoặc xuất là tên của một biến ký tự, thì lệnh sẽ chuyển dữ liệu từ một vùng lưu giữ nội tại trong bộ nhớ sang một vùng khác. Những vùng lưu giữ này được gọi là các file nội tại (internal file). Thí dụ, ta có thể đọc dữ liệu từ một xâu ký tự thay vì đọc từ một dòng dữ liệu trong file thông thường với những lệnh sau đây:

CHARACTER * 13 DATA1

INTEGER I, J

REAL X

DATA1 = '137 65 42.17'

READ (DATA1, *) I, J, X

Những lệnh trên đây có nghĩa rằng chúng ta khai báo một biến có kiểu văn bản DATA1 với độ dài 13 ký tự. Sau đó gán cho biến này dòng văn bản:

‘137 65 42.17 ‘

Đó là việc bình thường, chúng ta đã biết từ trước đến nay. Nhưng hãy chú ý đến lệnh cuối cùng. Đó là lệnh:

READ (DATA1, *) I, J, X

Trông lệnh này giống như một lệnh đọc dữ liệu bình thường, chỉ có khác là thay vì đơn vị file trong cặp dấu ngoặc đơn ta đã đưa tên biến DATA1 vào đó. Kết quả là sau lệnh đọc này các đoạn văn bản biểu diễn những chữ số 137, 65 và 42.17 đã được đọc ra như là những số nguyên, số thực và gán vào các biến nguyên I, J và biến thực X trong danh sách các biến cần đọc của lệnh READ một cách đúng đắn. Sau những lệnh này giá trị các biến số sẽ như sau:

I sẽ bằng 137, J sẽ bằng 65 và X bằng 42.17.

Đây là một đặc điểm rất quan trọng của Fortran. Ta sẽ thấy ích lợi của đặc điểm này của file nội tại qua thí dụ sau:

INTEGER PTR
REAL AMOUNT
CHARACTER * 15 TEMP
. . .
. . .
READ (12, 5) TEMP
5 FORMAT (A10)
IF (INDEX (TEMP, '$') .NE. 0) THEN
PTR = INDEX (TEMP, '$')
TEMP (PTR: PTR) = ' '
END IF
READ (TEMP, *) AMOUNT

Với đoạn chương trình này dữ liệu từ trong đơn vị file (12) thông thường (file ngoại) được đọc vào biến ký tự TEMP. Trong trường hợp dữ liệu có kèm theo dấu $ ở bên trái (cách viết dấu đô la đằng trước và dính liền số tiền của những người Mỹ thường làm), thì lệnh đọc

READ (12,5) TEMP

vẫn không mắc lỗi về kiểu dữ liệu. Sau đó ta xử lý, thay ký tự $ bằng ký tự dấu trống và đọc lấy giá trị số thực AMOUNT bằng lệnh đọc file nội tại

READ (TEMP, *) AMOUNT

Nhận thấy rằng lệnh đọc dữ liệu từ file nội tại hoàn toàn tương tự lệnh đọc các file thông thường. Thay vì số hiệu thiết bị hay số hiệu file, ta ghi tên biến (ở đây là biến TEMP) vào vị trí của thiết bị hay số hiệu file.

Bây giờ ta xét một thí dụ về sử dụng file nội để chuyển đổi dữ liệu số thành dữ liệu văn bản. Giả sử ta muốn tạo ra 12 tên file lần lượt là ‘GIO.1’, ‘GIO.2’, ..., ‘GIO.12’. Đoạn chương trình sau đây có thể làm được việc đó:

INTEGER J
CHARACTER *6 TENF(12), TAM
DO J = 1, 12
IF (J .LT. 10) THEN
WRITE (TAM, ‘(I1)’) J
ELSE
WRITE (TAM, ‘(I2)’) J
END IF
TENF (J) = ‘GIO’ // ‘.’ // TAM
END DO

Các file được sử dụng trong tất cả các thí dụ từ trước tới nay gọi là file truy nhập tuần tự vì một khi file đã được tạo ra, ta không thể cập nhật một bản ghi đơn lẻ nào trong nó. Muốn thay đổi một bản ghi, ta phải đọc các thông tin trong bản ghi, sửa đổi nó và sau đó ghi vào một file khác. Bây giờ ta sẽ xét lệnh OPENphức tạpcó thêm những chỉ định khác so với những thí dụ trước đây:

OPEN (UNIT = Biểu thức nguyên ,
* FILE = Biểu thức ký tự,
* ACCESS = Biểu thức ký tự,
* STATUS = Biểu thức ký tự,
* FORM = Biểu thức ký tự,
* IOSTAT = Biến nguyên,
* RECL = Biểu thức nguyên,
* BLANK = Biểu thức ký tự,
* ERR = N hãn lệnh chuyển điều khiển )

Biểu thức nguyên trong chỉ định UNIT, thường là một hằng, được sử dụng trong các lệnh READ hoặc WRITE để chỉ đơn vị file được dùng.

Biểu thức ký tự trong chỉ định FILE là tên của file cần mở. Hai chỉ định vừa rồi chúng ta đã quen dùng trong các chương trước.

Biểu thức ký tự trong chỉ định ACCESS phải có giá trị bằng 'DIRECT' hoặc ‘SEQUENTIAL' dùng để chỉ file thuộc loại truy cập trực tiếp hay truy cập tuần tự. Nếu vắng mặt chỉ định này thì ngầm định là 'SEQUENTIAL' như trước đây chúng ta đã dùng.

Biểu thức ký tự của chỉ định STATUS có thể có một trong những giá trị là ‘NEW' (để chỉ file mới sẽ tạo ra bằng lệnh WRITE), hoặc 'OLD' (file đang tồn tại), hoặc ‘UNKNOWN’ (chưa rõ), hoặc 'SCRATCH' (file xuất, sẽ bị xóa khi chương trình kết thúc).

Biểu thức ký tự trong chỉ định FORM hoặc có giá trị là 'FORMATTED' hoặc là 'UNFORMATTED' hay ‘BINARY’. Các file FORMATTED có thể dùng với cả lệnh READ và WRITE có định dạng hoặc dùng với các lệnh nhập, xuất đơn giản. Trong file UNFORMATTED dữ liệu được truy cập như là các xâu nhị phân, không phải là các số hay các ký tự. Nếu chỉ định FORM vắng mặt thì ngầm định sẽ là ‘FORMATTED’ đối với các file tuần tự và ‘UNFORMATTED’ đối với các file trực tiếp.

IOSTAT có thể dùng để khôi phục lỗi khi mở file. Nếu không có lỗi khi mở file, biến nguyên sẽ có giá trị 0. Nếu có lỗi, thí dụ không tìm thấy file với tên đã chỉ định, thì một giá trị khác 0 sẽ được lưu trong biến. Người ta thường kiểm tra giá trị của biến này để quyết định hành động tiếp theo. Thí dụ

CHARACTER TEN *12, TEMP *70

PRINT *, ‘GO TEN FILE’

READ (*, ‘(A12)’) TEN

OPEN (UNIT=15, FILE=TEN, STATUS=’OLD’, IOSTAT=IERR)

IF (IERR .EQ. 0) THEN

. . .

. . .

. . .

ELSE

PRINT*, ‘LOI MO FILE ‘,IERR

END IF

Đặc tả IOSTAT cũng có thể dùng với các lệnh READ và WRITE.

Chỉ định RECL cần cho các file truy cập trực tiếp, không dùng với các file truy cập tuần tự. Biểu thức nguyên nó chỉ định độ dài của một bản ghi.

Biểu thức ký tự của chỉ định BLANK có thể là 'NULL' hoặc 'ZERO'. Nếu đặc tả là 'NULL' các dấu trống trong các trường số bị bỏ qua, nếu là 'ZERO' các dấu trống được xem là các số 0. Ngầm định là 'NULL'.

Chỉ định ERR là tùy chọn và có giá trị để xử lý lỗi. Nếu lỗi xảy ra trong khi thực hiện lệnh OPEN hay một lệnh nào đó có chứa chỉ định này thì chương trình sẽ chuyển điều khiển tới lệnh có nhãn ghi trong chỉ định ERR thay vì tạo ra lỗi thực hiện chương trình. Chỉ định ERR cũng dùng với các lệnh READ và WRITE.

Lệnh CLOSE là một lệnh thực hiện, nó ngắt một file ngoại khỏi chương trình. Dạng tổng quát như sau:

CLOSE (UNIT = Biểu thức nguyên,
* STATUS = Biểu thức ký tự,
* IOSTAT = Biến nguyên,
* ERR = Nhãn lệnh chuyển điều khiển)

Lệnh CLOSE và các chỉ định là tùy chọn. Chỉ định STATUS trong lệnh CLOSE có giá trị ‘KEEP’ có nghĩa file được giữ lại, ‘DELETE’ có nghĩa file không cần nữa và nên xóa đi.

Lệnh REWIND

REWIND (UNIT = Biểu thức nguyên,
* IOSTAT = Biến nguyên,
* ERR = Nhãn lệnh điều khiển )

dùng để chuyển về vị trí bản ghi thứ nhất trong file tuần tự.

Lệnh BACKSPACE

BACKSPACE (UNIT = Biểu thức nguyên,
* IOSTAT = Biến nguyên,
* ERR = Nhãn lệnh điều khiển )

chuyển vị trí đọc ngược lại về phía trước một bản ghi trong file tuần tự.

Lệnh ENDFILE

ENDFILE (UNIT = Biểu thức nguyên,
* IOSTAT = Biến nguyên,
* ERR = Nhãn lệnh điều khiển )

ghi vào file một bản ghi chỉ sự kết thúc file khi file đã được tạo ra.

Các bản ghi trong các file truy cập trực tiếp được truy cập không theo cách tuần tự, mà theo thứ tự được chỉ định trong chương trình. Khi một file trực tiếp được mở, chỉ định ACCESS trong lệnh OPEN phải đặt là ‘DIRECT’ và độ dài của bản ghi phải được cho với chỉ định RECL. Các lệnh READWRITE phải chứa chỉ định REC để cung cấp số hiệu của bản ghi cần truy cập.

Dạng tổng quát của các lệnh READ hoặc WRITE với file truy cập trực tiếp như sau:

READ (Số hiệu file, nhãn lệnh FORMAT,
* REC =Biểu thứ nguyên) Danh sách biến
WRITE (Số hiệu file, nhãn lệnh FORMAT,
* REC = Biểu thức nguyên ) Danh sách biến

Biểu thức nguyên trong chỉ định REC dùng để chỉ số hiệu bản ghi cần xử lý. Các chỉ định ERR và IOSTAT có thể được sử dụng với các lệnh READ hoặc WRITE trực tiếp. Tùy chọn END có thể chỉ dùng với lệnh READ. Khi tổ chức file truy cập trực tiếp, người ta thường sử dụng số thứ tự hoặc số hiệu phân biệt - một phần của bản ghi làm số hiệu bản ghi. Thí dụ các số hiệu phân biệt của sinh viên trong một trường đại học thường bắt đầu bằng 00001 rồi đến 00002... Do đó thông tin về sinh viên số 00210 có thể được lưu trong bản ghi 210. Đôi khi có thể thực hiện một số tính toán với một trường của bản ghi để nhận được số hiệu của nó.

File truy cập trực tiếp thường được tạo ra bằng cách ghi thông tin vào một cách tuần tự, với bản ghi bắt đầu bằng 1 và tăng lên 1 mỗi lần có một bản ghi mới được viết vào. File này có thể xử lý theo thứ tự tuần tự bằng cách thay đổi số hiệu bản ghi từ 1 đến tổng số tất cả các bản ghi. Tuy nhiên, ưu điểm của file trực tiếp sẽ thể hiện rõ khi chúng ta muốn cập nhật thông tin trong một số bản ghi của file. Thay vì đọc từng bản ghi một cách tuần tự, tìm bản ghi mà ta muốn cập nhật, ta chỉ cần chỉ định số hiệu bản ghi và bản ghi đó tự động được xử lý. Khi cập nhật thông tin xong, ta có thể ghi thông tin mới vào bản ghi. Nếu trong lệnh READ ta chỉ định một số hiệu bản ghi mà bản ghi đó không tồn tại thì sẽ xảy ra lỗi. Để khôi phục lỗi, chỉ định ERR cần phải có mặt trong lệnh READ.

Lệnh INQUIRE có hai dạng:

INQUIRE ( FILE = biểu thức ký tự, danh sách chỉ định truy vấn )

INQUIRE ( UNIT = biểu thức nguyên, danh sách chỉ định truy vấn )

Lệnh này là một lệnh thực hiện, nó truy vấn thông tin về file hay số hiệu file. Bảng 9.1 liệt kê những chỉ định truy vấn. Thí dụ:

INQUIRE (FILE = 'TSDATA', SEQUENTIAL = TRALOI)

INQUIRE (UNIT = 12, SEQUENTIAL = TRALOI)

Bảng 11.1. Các chỉ định truy vấn của lệnh INQUIRE

Chỉ định truy vấn Kiểu biến Giá trị truy vấnfile FILE Giá trị truy vấnđơn vị file UNIT
ACCESS = CHARACTER 'SEQUENTIAL'DIRECT' 'SEQUENTIAL'DIRECT'
BLANK = CHARACTER 'NULL'ZERO' 'NULL'ZERO'
DIRECT = CHARACTER 'YES'NO' _
ERR = INTEGER Số hiệu lệnh xử lý lỗi Số hiệu lệnh xử lý lỗi
EXIST = LOGICAL .TRUE..FALSE. .TRUE..FALSE.
FORM = CHARACTER 'FORMATTED'UNFORMATTED' 'FORMATTED'UNFORMATTED'
FORMATTED = CHARACTER 'YES'NO'UNKNOWN'
IOSTAT = INTEGER Mã lỗi Mã lỗi
NAME = CHARACTER Tên file nếu file đó không phải là file loại scratch
NAMED + = LOGICAL _ .TRUE..FALSE.
NEXTREC = INTEGER Số hiệu bản ghi tiếp theo trong file truy cập trực tiếp Số hiệu bản ghi tiếp theo trong file truy cập trực tiếp
NUMBER + = INTEGER Đơn vị file
OPEND = LOGICAL .TRUE..FALSE. .TRUE..FALSE.
RECL = INTEGER Độ dài bản ghi Độ dài bản ghi
SEQUENTIAL = CHARACTER 'YES'NO'UNKNOWN'
UNFORMATTED = CHARACTER 'YES'NO'UNKNOWN'

Thí dụ 36: Sự tương tác giữa người dùng và chương trình. Giả sử khi chương trình yêu cầu người dùng gõ một tên của file dữ liệu để mở ra làm việc trong chương trình. Trường hợp file đó không tồn tại, chương trình sẽ kết thúc bởi lỗi thực hiện. Nếu ta dùng lệnh INQUIRE, chương trình có thể xác định file đó có tồn tại không và nếu không tồn tại, chương trình nhắc người dùng gõ một tên file khác. Các lệnh sau đây thực hiện sự tương tác này:

CHARACTER *70 TENFIL, TIT
LOGICAL XONG, OK, CO
XONG = .FALSE.
OK = .FALSE.
PRINT *, 'NHAP TEN FILE'
READ *, TENFIL
5 IF (.NOT. XONG) THEN
INQUIRE (FILE = TENFIL, EXIST = CO)
IF (.NOT. CO) THEN
PRINT *, 'FILE KHONG TON TAI'
PRINT *, 'NHAP TEN KHAC HOAC GO THOI'
READ *, TENFIL
IF (TENFIL .EQ. 'THOI') XONG = .TRUE.
ELSE
XONG = .TRUE.
OK = .TRUE.
ENDIF
GOTO 5
ENDIF
IF (OK) THEN
OPEN (UNIT = 10, FILE = TENFIL, STATUS = 'OLD')
. . .
. . .
. . .
END IF
END

Bài tập

1. Viết chương trình đếm và in số bản ghi trong các file DATA1 và DATA2. Giả sử các file đó là file tuần tự và mỗi bản ghi chứa hai giá trị thực với format sau:

FORMAT (F6.2, 1X, F6.2)

Nếu lỗi xảy ra khi mở file, hãy in thông báo lỗi thay vì in số bản ghi.

2. File TEM60.JAN lưu trường ba chiều nhiệt độ nước biển Đông tháng Giêng độ phân giải 1o kinh vĩ có quy cách ghi như sau: Dòng đầu tiên gồm 5 số nguyên cách nhau lần lượt chỉ kinh độ mép trái, kinh độ mép phải, vĩ độ mép trên, vĩ độ mép dưới của miền không gian và số tầng sâu. Dòng thứ hai ghi độ sâu (số nguyên) của tầng trên cùng. Sau đó là bảng giá trị nhiệt độ (số thực cách nhau) với số cột bằng số điểm nút theo kinh tuyến, số dòng bằng số điểm nút theo vĩ tuyến. Các tầng tiếp theo ghi hoàn toàn tương tự. Giá trị nhiệt độ khuyết hoặc rơi vào vùng đất liền được ghi bằng số 99.99. Viết chương trình tính giá trị nhiệt độ nước trung bình toàn biển Đông.

3. Với file số liệu của bài tập 2, viết chương trình đọc thông tin trong file và tạo cho mỗi điểm nút thuộc miền tính một file đặt tên theo quy tắc sau: bắt đầu bằng chữ K, sau đó đến các chữ số chỉ kinh độ điểm, sau đó chữ V và các chữ số chỉ vĩ độ điểm, đuôi file là ‘.BLN’. Trong các file có quy cách ghi như sau, dòng trên cùng có một số nguyên chỉ số tầng quan trắc thực tế của điểm, một dấu cách và chữ số 1. Sau đó liệt kê liên tiếp giá trị nhiệt độ và tầng sâu ứng với nhiệt độ đó với dấu ngược lại.

4. Giả sử có file dữ liệu lưu giá trị quan trắc của một số yếu tố khí tượng thủy văn tại trạm hải văn, có quy cách ghi như sau:

- Dòng thứ nhất có hai số nguyên 1 và 2 cách nhau một dấu trống.

- Dòng thứ hai ghi tên trạm (không quá 100 ký tự).

- Dòng thứ ba ghi hai số nguyên chỉ số dòng dữ liệu (không quá 5000) và số yếu tố quan trắc (không quá 12) cách nhau ít nhất một dấu trống.

- Dòng thứ tư lần lượt ghi tên các yếu tố được quan trắc, mỗi tên với định dạng A8.

- Dòng thứ 5 lần lượt ghi đơn vị đo của từng yếu tố quan trắc, cũng với định dạng A8.

- Mỗi dòng trong các dòng tiếp sau lần lượt ghi giá trị quan trắc của các yếu tố, mỗi giá trị ghi với định dạng F8.2.

Viết chương trình cho phép nhập tên file từ bàn phím, đọc dữ liệu và lập phương trình hồi quy giữa biến thứ nhất (biến phụ thuộc) và biến thứ hai (biến độc lập). In kết quả ra màn hình theo quy cách sau: giả sử tên biến thứ nhất là Tw, biến thứ hai là Ta, phương trình phải viết có dạng:

Tw = 0.915 Ta + 1.237

(Ghi chú: xem công thức trong phụ lục 3).

5. Cải tiến chương trình trong bài tập 4 để cho phép người dùng tùy ý chỉ định biến phụ thuộc và biến độc lập từ bàn phím.

6. Với file dữ liệu đã mô tả trong bài tập 4, lập chương trình tính phương trình hồi quy nhiều biến giữa yếu tố quan trắc thứ nhất (biến phụ thuộc) và các yếu tố quan trắc 2, 3, 6, 8, 9. In kết quả lên màn hình dưới dạng phương trình hồi quy với tên các yếu tố đã ghi trong file.

Gợi ý: Xem phương pháp thiết lập phương trình hồi quy tuyến tính nhiều biến trong phụ lục 4.

7. File HESOA.MAT lưu các giá trị của các hệ số của hệ phương trình đại số tuyến tính theo quy cách như sau: Dòng thứ nhất có một số nguyên chỉ số phương trình. Các dòng tiếp sau ghi các giá trị các hệ số, kể cả hệ số tự do ứng với từng phương trình, mỗi phương trình trên một dòng, mỗi hệ số ghi với định dạng F8.4, thí dụ:

4 1.1161 0.1254 0.1397 0.1490 1.5471

0.1582 1.1675 0.1768 0.1871 1.6471

0.1968 0.2071 1.2168 0.2271 1.7471

0.2368 0.2471 0.2568 1.2671 1.8471

Viết chương trình đọc file và giải hệ phương trình bằng phương pháp loại biến Gauss. Kết quả in ra màn hình gồm: viết lại hệ phương trình, sau đó cách ra một dòng rồi ghi các nghiệm ở dòng cuối cùng, thí dụ, ứng với ma trận các hệ số như trên phải có kết quả trên màn hình như sau:

1.1161X1 + 0.1254X2 + 0.1397X3 + 0.1490X4 = 1.5471

0.1582X1 + 1.1675X2 + 0.1768X3 + 0.1871X4 = 1.6471

0.1968X1 + 0.2071X2 + 1.2168X3 + 0.2271X4 = 1.7471

0.2368X1 + 0.2471X2 + 0.2568X3 + 1.2671X4 = 1.8471

1.04059 0.98697 0.93505 0.88130

Gợi ý: Xem phương pháp giải hệ phương trình đại số tuyến tính theo sơ đồ loại biến Gauss trong phụ lục 2.

8. File HESOAB.MAT lưu các giá trị của các hệ số của hệ phương trình đại số tuyến tính theo quy cách như đã mô tả trong bài tập 7. Giả sử ma trận các hệ số A=[aij] size 12{A= [ a rSub { size 8{i} rSub { size 8{j} } } ] } {} là ma trận đối xứng, tức aij=aji(i,j=1,2,...,n) size 12{a rSub { size 8{ ital "ij"} } =a rSub { size 8{ ital "ji"} } " " ( i,j=1, 2, "." "." "." , n ) } {}.

Hãy viết chương trình đọc file các hệ số và giải hệ phương trình. In kết quả theo quy cách của bài tập 7.

Gợi ý: Trường hợp ma trận các hệ số A size 12{A} {} là ma trận đối xứng, nên dùng phương pháp căn bậc hai để giải hệ phương trình đại số tuyến tính (phụ lục 2).

0