intTypePromotion=1
zunia.vn Tuyển sinh 2024 dành cho Gen-Z zunia.vn zunia.vn
ADSENSE

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

Chia sẻ: Son Cung | Ngày: | Loại File: DOC | Số trang:7

246
lượt xem
74
download
 
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

PERL là cách viết tắt cho “Practical Extraction and Report Language”, mặc dù còn được gọi là “Pathologically Eclectic Rubbish Lister". Larry Wall đã tạo ra Perl khi c gắng sản xuất ra một số báo cáo từ một cấp bậc các tệp kiểu như thư người dùng mạng Usenet về hệ thống báo lỗi, và lệnh awk..và đưa ra bản đầu tiên của Perl. Sau đ Larry đưa nó cho các độc giả Usenet, thường vẫn được gọi là “the Net”. Kết quả là Perl phát triển dần và cũng cùng tỉ lệ như kernel của UNIX. Nó đã phát triển...

Chủ đề:
Lưu

Nội dung Text: Ngôn ngữ Perl-Chương 10-Tước hiệu tệp

  1. 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).
  2. 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
  3. 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 () { 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 () { #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:
  4. $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 = ; 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)
  5. -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ó lẽ bạn sẽ muốn có việc so sánh theo phạm vi (hay toán tử int()) hơn là so sánh chính xác để được các tệp nằm giữa ba và bốn ngày lẻ.
  6. Tất cả những toán tử này có thể vận hành trên tước hiệu tệp cũng như tên tệp. Với tước hiệu tệp làm toán hạng là tất cả những gì toán tử đó cần. Vậy để kiểm tra xem liệu tệp có được mở như SOMEFILE có là thực hiện được hay không, bạn có thể dùng: if (-x SOMEFILE) { #... } Nếu bạn để tham biến tên tệp hay tước hiệu tệp bỏ không (tức là, bạn chỉ có - r hay -s) thì toán hạng mặc định là tệp có tên trong biến $_ (nó vẫn có đấy!). Cho nên, để kiểm thử một danh sách các tên tệp xem tệp nào đọc được, thì chỉ cần đơn giản là: foreach (@some_list_of_filenames) { print "$_ la doc duoc" if -r; } 10.6 Các toán tử stat() và lstat() Trong khi các phép kiểm tra tệp này là tốt cho việc kiểm tra nhiều thuộc tính liên quan tới một tệp hay danh mục đặc biệt, thì chúng lại không nói được toàn bộ tất cả. Chẳng hạn, không có việc kiểm tra tệp nào cho lại số các liên kết với một tệp. Để thu được thông tin còn lại về tệp, đơn thuần hãy gọi tới toán tử stat(), toán tử trả lại mọi thứ mà lời gọi hàm hệ thống UNIX stat() cung cấp cho ta. Toán hạng của stat() là tước hiệu tệp, hay một biểu thức tính cho tên tệp. Giá trị trả về hoặc là undef, chỉ ra rằng stat không tính được, hoặc một mảng có 13 giá trị, phần lớn đều dễ mô tả bằng việc dùng danh sách sau đây các biến vô hướng: ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = stat(...); Các tên ở đây đều trỏ tới các bộ phận của cấu trúc stat, được mô tả chi tiết trong phần hướng dẫn của lệnh stat (Unix). Có lẽ bạn nên nhìn vào đó để xem các mô tả chi tiết. Chẳng hạn để lấy ID (số hiệu) người dùng và ID nhóm của tệp mật mã, ta hãy thử: ($uid,$gid) = (stat("/etc/passwd"))[4, 5]; Gọi toán tử stat() trên tên của một liên kết kí hiệu sẽ cho lại thông tin về liên kết kí hiệu này đang trỏ tới cái gì, không phải thông tin về bản thân liên kết kí hiệu (trừ phi liên kết này xẩy ra để không trỏ vào cái gì hiện thời thâm nhập được). Nếu bạn cần thông tin (phần lớn vô dụng) về bản thân liên kết kí hiệu, thì hãy dùng lstat() thay vì stat() (cho cùng thông tin theo cùng thứ tự). Toán tử lstat() làm việc tựa như stat() nhưng thực hiện trên những đối số không phải là liên kết kí hiệu. Giống như việc kiểm tả tệp, toán hạng của stat hay lstat mặc định là $_, nghĩa là stat sẽ được thực hiện trên tệp có tên trong biến vô hướng $_. 10.7 Dùng _Filehandle Mọi lần bạn nói stat(), -r, -w hay bất kì cái gì trong chương trình, thì Perl đều phải trở ra hệ thống để hỏi bộ đệm stat trên tệp (bộ đệm cho lại từ lời gọi hệ thống stat). Điều đó có nghĩa là nếu bạn muốn biết liệu tệp có vừa đọc được và ghi được không thì bạn về bản chất đã hỏi hệ thống hai lần cho cùng một thông tin (điều này không thể thay đổi được trong một môi trường khá không thân thiện).
  7. Điều này có vẻ như lãng phí, và trong thực tế, có thể tránh được. Thực hiện việc kiểm tra tệp, stat, hay lstat trên _filehandle (một dấu gạch thấp) xem như toán hạng sẽ bảo cho Perl dùng bất kì cái gì ngẫu nhiên có trong bộ nhớ từ lần kiểm tra tệp trước đó. Đôi khi điều này là nguy hiểm: một chương trình con có thể gọi stat một cách không chủ định, bỏ mất bộ đệm của bạn đi. Nhưng nếu bạn cẩn thận thì bạn có thể tiết kiệm một vài lời gọi hệ thống không cần thiết. Sau đây là thí dụ nữa về việc kiểm tra tính ghi được và đọc được $filevar, dùng mẹo mới: if (-r $filevar && -w _) { print "$filevar vua doc duoc vua ghi duoc\n"; } Lưu ý rằng tôi đã dùng $filevar cho phép kiểm tra thứ nhất - điều này lấy dữ liệu từ hệ điều hành. Lần kiểm tra thứ hai dùng _filehandle ảo thuật; với phép kiểm tra này, bản thân dữ liệu bị bỏ lại từ phép kiểm tra $filevar về tính đọc được nay lại được dùng, đúng là điều ta mong muốn. Chú ý rằng việc kiểm thử _filehandle không hệt như việc cho phép toán hạng của việc kiểm tra tệp, stat, hay lstat được mặc định kiểm tra $_; điều này sẽ là việc kiểm tra mới mỗi lần trên tệp hiện tại mang tên theo nội dung của $_. Đây lại là một trường hợp khác khi các tên tương tự đuợc chọn cho các chức năng khá khác nhau. Hiện tại, bạn có lẽ đã quen với nó. 10.8 Bài tập 1. Bạn hãy viết chương trình đọc vào tên 1 tệp từ STDIN, tiếp theo mở tệp đó ra và hiển thị nội dung của tệp đó với mỗi dòng được bắt đầu bằng tên tệp và 1 dấu hai chấm. Ví dụ: nếu bạn hiển thị tệp có tên fred và tệp này có 3 dòng là aaa, bbb và ccc thì bạn cần phải hiển thị như sau: fred: aaa fred: bbb fred: ccc 2. Bạn hãy viết chương trình đọc vào 1 tên tệp (để đọc), 1 tên tệp (để ghi), 1 chuỗi cần tìm, 1 chuỗi thay thế. Sau đó cóp-pi nội dung của tệp "đọc" sang tệp "ghi" và đồng thời thay thế các "chuỗi cần tìm" bằng "chuỗi thay thế". 3. Bạn hãy viết chương trình đọc vào 1 danh sách các tên tệp và hiển thị tệp nào là đọc được, tệp nào ghi được, tệp nào thi hành được (executable) và tệp nào không tồn tại. 4. Bạn hãy viết chương trình đọc vào 1 danh sách các tên tệp và xác định xem tệp nào là "cũ" nhất (thời gian lần cuối tệp được sửa đổi là lâu nhất trong danh sách các tệp). Hãy hiển thị tên tệp cùng với tuổi của tệp đó tính theo ngày.
ADSENSE

CÓ THỂ BẠN MUỐN DOWNLOAD

 

Đồng bộ tài khoản
2=>2