Tải bản đầy đủ (.doc) (7 trang)

Ngôn ngữ Perl-Chương 10-Tước hiệu tệp

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (186.52 KB, 7 trang )

Learning Perl - Chương 10: Tước hiệu tệp và kiểm thử tệp
1. Xác định một hàm tiện ích
2. Gọi một hàm tiện ích
3. Giá trị trả về
4. Đối số của hàm
5. Biến cục bộ trong hàm
6. Bài tập
10.1 Tước hiệu tệp
Tước hiệu tệp là tên trong một chương trình Perl dành cho việc nối giữa tiến trình Perl của bạn
và bên ngoài. Chúng ta đã thấy và dùng tước hiệu tệp một cách không tường minh: STDIN là
một tước hiệu tệp, đặt tên cho việc nối giữa tiến trình Perl và lối vào chuẩn của UNIX. Giống
như vậy, Perl cung cấp STDOUT (cho lối ra chuẩn) và STDERR (cho lối ra chuẩn cho lỗi).
Những tên này là trùng với các tên được dùng trong bộ trình thư viện "vào/ra chuẩn" của
UNIX, Perl dùng chúng cho hầu hết việc vào/ra.
Tên tước hiệu tệp cũng giống như tên dành cho các khối có nhãn, nhưng chúng đến từ một
không gian tên khác (cho nên bạn có thể có một vô hướng $jerry, một mảng @jerry, một mảng
băm %jerry, một chương trình con jerry(), một nhãn jerry:, và bây giờ một tước hiệu tệp jerry).
Giống như nhãn khối, tước hiệu tệp được dùng không cần một kí tự đặc biệt đứng trước, và do
vậy có thể bị lẫn lộn với các từ dành riêng hiện có hay trong tương lai. Một lần nữa, khuyến
cáo của Larry là bạn hãy dùng tất cả các chữ hoa trong tước hiệu tệp của mình - không chỉ nó
biểu thị tốt hơn, mà nó cũng sẽ đảm bảo rằng chương trình của bạn sẽ không hỏng khi các từ
dành riêng tương lai được đưa vào.
10.2 Mở và đóng một tước hiệu tệp
Perl cung cấp ba tước hiệu tệp STDIN, STDOUT, STDERR mà tự động mở cho các tệp hay
thiết bị do tiến trình cha mẹ của chương trình này đã thiết lập. Bạn dùng toán tử open() để mở
các tước hiệu tệp phụ, hệt như bạn làm trong chương trình được viết trong C. Cú pháp của nó
giống thế này:
open(FILEHANDLE, "ten file");
với FILEHANDLE là tước hiệu tệp mới, còn ten file là tên tệp ngoài (như một tệp hay thiết bị)
mà sẽ được liên kết với tước hiệu tệp mới. Việc gọi này mở tước hiệu tệp để đọc. Việc mở một
tệp để ghi thì cũng dùng cùng toán tử open, nhưng phần tiền tố của tên tệp có một dấu lớn hơn


(>):
open(OUT, ">outfile");
Chúng ta sẽ thấy trong mục "Dùng tước hiệu tệp" dưới đây cách sử dụng tước hiệu tệp này.
Cũng tương tự như vậy, bạn có thể mở một tệp để thêm vào sau bằng việc dùng hai dấu lớn
hơn làm tiền tố (>>), ví dụ như:
open(LOGFILE, ">>mylogfile");
Tất cả ba dạng này của open trả về giá trị đúng (true) nếu việc mở thành công và sai (false) nếu
thất bại. (Việc mở một tệp để đọc sẽ sai nếu như tệp đó không tồn tại hay không thể truy cập
được bởi không được phép của hệ điều hàng; việc mở tệp để ghi sẽ sai nếu ta không được phép
ghi vào tệp hay thư mục).
Khi bạn kết thúc với một tước hiệu tệp, bạn có thể đóng nó bằng toán tử close, tựa như:
close(LOGFILE);
Việc mở lại một tước hiệu tệp cũng làm đóng tệp mở trước đó một cách tự động, cũng như khi
ra khỏi chương trình. Vì điều này, phần lớn các chương trình Perl không bận tâm với close.
Nhưng nó vẫn có đó nếu bạn muốn được chặt chẽ hay chắc chắn rằng tất cả dữ liệu đều được
đẩy ra hết đôi khi sớm hơn việc kết thúc của chương trình.
10.3 die()
Ta hãy coi đây như là một chú thích lớn cuối trang, nhưng lại nằm ở giữa trang.
Một tước hiệu tệp mà không được mở thành công thì có thể vẫn được dùng mà thậm chí không
gây ra cảnh báo gì nhiều lắm trong toàn bộ chương trình. Nếu bạn đọc từ tước hiệu tệp thì bạn
sẽ nhận được ngay cuối tệp. Nếu bạn ghi lên tước hiệu tệp thì dữ liệu bị bỏ đi.
Thường bạn muốn kiểm tra lại kết quả của việc mở tệp và báo cáo lại lỗi nếu kết quả không
phải là điều bạn dự kiến. Chắc chắn, bạn có thể rải rắc trong chương trình của mình với những
thứ kiểu như:
unless (open(DATAPLACE, ">/tmp/dataplace")) {
print "Co loi: khong the tao duoc tep /tmp/dataplace\n";
} else {
# phan con lai cua chuong trinh
}
Nhưng bạn sẽ phải làm nhiều việc lắm. Và điều thường xẩy ra với Perl là đưa ra một lối tắt.

Toán tử die() lấy một danh sách bên trong dấu ngoặc tròn tuỳ chọn, đưa ra danh sách đó (giống
như print) trên lối ra lỗi chuẩn, và rồi kết thúc tiến trình Perl (tiến trình đang chạy chương trình
Perl) với một trạng thái ra khác không của UNIX (nói chung chỉ ra một cái gì đó bất thường
xẩy ra). Cho nên, viết lại đoạn mã trên thì ta sẽ thấy nó giống như thế này:
unless (open(DATAPLACE, ">/tmp/dataplace")) {
die "Co loi: khong the tao duoc tep /tmp/dataplace\n";
}
# phan con lai cua chuong trinh
Nhưng chúng ta thậm chí còn có thể đi thêm một bước nữa. Nhớ rằng ta có thể dùng toán tử
logic hoặc (||) để làm ngắn thêm điều này, như trong ví dụ sau:
unless (open(DATAPLACE, ">/tmp/dataplace")) ||
die "Co loi, khong the tao duoc tep /tmp/dataplace\n";
Vậy die sẽ được thực hiện chỉ khi kết quả của open là sai. Cách thông dụng để đọc hiểu câu
lệnh trên là "hãy mở tệp đó ra hoặc die" và đó là cách dễ dàng để nhớ bất kì khi nào dùng toán
tử logic và (&&) hay logic hoặc (||).
Thông báo được in ra từ die (được xây dựng từ đối của die) có tên chương trình Perl và số
dòng được gắn tự động vào, cho nên bạn có thể dễ dàng xác định được die nào trong chương
trình của bạn đã in ra thông báo lỗi này. Nếu bạn không thích số dòng hay tên tệp bị lộ ra, bạn
phải thêm một dấu xuống dòng vào cuối thông báo. Chẳng hạn:
die "......";
sẽ in ra tên tệp và số dòng, trong khi:
die "....\n";
thì không in ra tên tệp và số dòng.
10.4 Dùng tước hiệu tệp
Một khi tước hiệu tệp được mở ra để đọc thì bạn có thể đọc các dòng từ nó hệt như bạn có thể
đọc từ lối vào chuẩn với STDIN. Vậy, chẳng hạn, để đọc các dòng từ tệp mật mã:
open (EP, "/etc/passwd");
while (<EP>) {
chop;
print "Tim thay $_ trong tep /etc/passwd!\n";

}
Lưu ý rằng tước hiệu tệp mới mở được dùng bên trong dấu ngoặc nhọn hệt như ta đã dùng
STDIN trước đây.
Một tước hiệu tệp mở ra để ghi hay hiệu đính đều phải được cho như một đối của toán tử print,
xuất hiện ngay sau từ khoá print nhưng trước danh sách đối khác. Ví dụ:
print LOGFILE "Tong so = $total\n";
print STDOUT "Xin chao!\n"; # tuong tu nhu print "Xin
chap!\n";
Trong trường hợp này, thông báo bắt đầu với "Tong so = $total\n" ghi lên tước hiệu tệp
LOGFILE, mà giả thiết là đã mở trước đây trong chương trình. Và cau "Xin chao!\n" sẽ đi ra
lối ra chuẩn, hệt như khi bạn không xác định tước hiệu tệp. Chúng ta nói rằng STDOUT là
tước hiệu xử lí tệp ngầm định cho câu lệnh print.
Vậy, tóm lại, sau đây là cách để sao chép tất cả văn bản từ một tệp được xác định trong $a vào
một tệp được xác định trong $b. Nó minh hoạ gần như mọi thứ mà ta đã học trong chương này
vừa qua:
open (IN, $a) || die "Khong the mo duoc $a de doc";
open (OUT, ">$b") || die "Khong the mo duoc $b de ghi";
while (<IN>) { #Doc 1 dong tu tep $a vao $_
print OUT $_; #In dong do vao tep $b
}
close(IN);
close(OUT);
10.5 Kiểm tra tệp -x
Bây giờ bạn đã biết cách để mở một tước hiệu tệp để ghi ra, viết đè lên bất kì tệp hiện có nào
với cùng tên. Giả sử bạn muốn chắc chắn rằng không có một tệp nào với tên đó (để giữ cho
bạn khỏi ngẫu nhiên làm mất tiêu dữ liệu bảng tính hay lịch ngày sinh quan trọng). Nếu bạn
định viết một shell script thì bạn nên dùng cái gì đó tựa như -e tên_tệp để kiểm tra liệu tệp đó
có tồn tại hay không. Tương tự thế, Perl dùng -e $filevar để kiểm tra sự tồn tại của tệp mang
tên bởi giá trị vô hướng $filevar. Nếu tệp này tồn tại thì kết quả là đúng (true); ngược lại nó là
sai (false). Chẳng hạn:

$x = "/etc/passwd";
if (-e $x) { #lieu /etc/passwd co ton tai khong?
# Co
} else {
print "Khong co, lam sao ban log in duoc day?\n";
}
Toán hạng của toán tử -e thực sự là bất kì biểu thức vô hướng nào mà kết quả là một xâu nào
đó, kể cả một xâu hằng. Sau đây là một thí dụ kiểm tra cho cả tệp index.html và index.cgi:
if (-e "index.html" && -e "index.cgi") {
print "OK!\n";
}
Các toán tử khác cũng được xác định rõ. Chẳng hạn, -r $filevar cho lại giá trị đúng nếu tệp có
tên trong $filevar đang tồn tại và có thể đọc được. Tương tự, -w $filevar kiểm tra xem liệu có
ghi được lên tệp trong $filevar hay không. Sau đây là một thí dụ kiểm tra tên tệp do người
dùng xác định cho cả tính đọc được và ghi được:
print "Where? ";
$filename = <STDIN>;
chop($filename); # bo dau xuong dong
if (-r $filename && -w $filename) {
#OK, co the doc va ghi
...
}
Có nhiều toán tử để kiểm tra tệp có sẵn. Xin xem bảng lệt kê sau để biết danh sách đầy đủ.
Kiểm tra tệp Ý nghĩa
-r Tệp hoặc thư mục có thể đọc được
-w Tệp hoặc thư mục có thể ghi vào được
-x Tệp hoặc thư mục có thuộc tính thi
hành (executable)
-o Tệp hoặc thư mục thuộc quyền sở hữu
của người dùng (người đang chạy

chương trình Perl)
-R Tệp hoặc thư mục đọc được bởi người
dùng thực
-W Tệp hoặc thư mục ghi được vởi người
dùng thực
-X Tệp hoặc thư mục có thể thi hành được
bởi người dùng thực
-O Tệp hoặc thư mục được sở hữu bởi
người dùng thực
-e Tệp hoặc thư mục tồn tại
-z Tệp hoặc thư mục tồn tại và có kích
thước là 0 byte (thư mục luôn luôn có
kích thước > 0)
-s Tệp hoặc thư mục tồn tại và có kích
thước > 0 byte
-f Kiểm tra đối số có phải là 1 tệp?
-d Kiểm tra đối số có phải là 1 thư mục?
-l Kiểm tra đối số có phải là 1 symlink?
-S Kiểm tra đối số có phải là 1 socket?
-p Kiểm tra đối số có phải là 1 pipe?
-b Kiểm tra đối số có phải là 1 tệp khối
đặc biệt (vd như một đĩa mềm/cứng)
-c Kiểm tra đối số có phải là 1 tệp ký tự
đặc biệt (vd như thiết bị vào ra)
-u Tệp hoặc thư mục được thiết lập setuid
-g Tệp hoặc thư mục được thiết lập setgid
-k Tệp hoặc thư mục được thiết lập thuộc
tính sticky
-t giá trị trả về sẽ tương tự như khi dùng
hàm isatty()

-T Là tệp "văn bản" (text)
-B Là tệp "nhị phân" (binary)
-M Tệp được thay đổi (tính theo ngày)
-A Tệp được truy cập (tính theo ngày)
-C Inode của tệp được thay đổi (tính theo
ngày)
Bảng 10.1: Kiểm tra tệp và ý nghĩa của chúng

Phần lớn trong những phép kiểm tra này đều cho lại một điều kiện đúng-sai đơn giản. Số ít thì
không, cho nên ta hãy nói về chúng.
Toán tử -s không cho lại giá trị đúng nếu tệp là khác rỗng, nhưng giá trị cho lại là một loại
đúng đặc biệt. Đó là chiều dài theo byte của tệp, vẫn được coi là đúng đối với một số khác
không.
Toán tử tuổi -M, -A và -C (chúng đều là chữ hoa cả) cho lại số ngày kể từ tệp được sửa đổi,
truy cập hay có thay đổi inode lần cuối (tuổi được đo tương đối theo thời gian chương trình bắt
đầu, như được lấy theo thời gian UNIX trong biến S^T. Có thể lấy được số âm cho những tuổi
này nếu giá trị hỏi tham khảo tới một sự kiện đã xẩy ra sau khi chương trình bắt đầu. inode
chứa tất cả các thông tin về tệp ngoại trừ nội dung của nó - xem chi tiết trong lời gọi hệ thống
stat). Giá trị tuổi này là phân số với độ phân giải một giây: 36 giờ được cho lại là 1.5 ngày.
Nếu bạn so sánh tuổi này với một số nguyên (chẳng hạn 3), bạn sẽ thu được chỉ các tệp đã bị
thay đổi đúng nhiều ngày trước đây, không nhiều hay ít hơn một giây. Điều này có nghĩa là có

×