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

Learning Perl - Tước hiệu tệp và kiểm thử tệp

Chia sẻ: AJFGASKJHF SJHDB | Ngày: | Loại File: PDF | Số trang:6

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

10.1 Tước hiệu tệp Tước hiệu tệp là tên trong một c hương trình Perl dành c ho 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 c huẩn của UNIX. Giống như vậy, Perl cung c ấp STDOUT (c ho lối ra chuẩn) và STDERR (cho lối ra c huẩn c ho lỗi). ...

Chủ đề:
Lưu

Nội dung Text: Learning Perl - Tước hiệu tệp và kiểm thử tệp

  1. D iễn đàn tin học | Tutorial Room Mục lục «« C hương 9 »» C hương 1 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 íc h 2. Gọi một hàm tiện ích 3. Giá t rị 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 c hương trình Perl dành c ho 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 t rình Perl và lối vào c huẩn của UNIX. Giống như vậy, Perl cung c ấp STDOUT (c ho lối ra chuẩn) và STDERR (cho lối ra c huẩn c ho lỗi). Những tên này là t rùng với các tên được dùng trong bộ trình thư viện "vào/ra c huẩn" c ủa UNIX, Perl dùng c hú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 c ho c ác khối c ó nhãn, nhưng c húng đến từ một không gian tên khác (c ho 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 c hữ hoa trong tước hiệu tệp c ủa mình - không c hỉ nó biểu thị tốt hơn, mà nó cũng sẽ đảm bảo rằng c hươ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 c ung c ấp ba tước hiệu tệp STDIN, STDOUT, STDERR mà tự động mở c ho c ác tệp hay thiết bị do tiến trình cha mẹ c ủa c hương trình này đã thiết lập. Bạn dùng t oá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 t en 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 t hì c ũng dùng cùng t oá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 ác h 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 t rả 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ẽ s ai 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 t a 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 t oán tử c lose, 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 ác h tự động, c ũng như khi ra khỏi chương trình. Vì điều này, phần lớn c ác c hương trình Perl không bận tâm với c lose. Nhưng nó vẫn có đó nếu bạn muốn được chặt c hẽ hay c hắc c hắ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 c oi đây như là một c hú thíc h lớn c uối trang, nhưng lại nằm ở giữa trang.
  2. 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 c hí không gây ra cảnh báo gì nhiều lắm trong toàn bộ c hương t rình. Nếu bạn đọc từ tước hiệu tệp thì bạn sẽ nhận được ngay c uố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 c hắn, bạn có thể rải rắc trong c hươ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 c huẩn, và rồi kết thúc tiến t rình Perl (tiến trình đang c hạy c hươ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 c hí 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ụ s au: 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 c hỉ 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 c hương trình Perl và số dòng được gắn tự động vào, c ho 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íc h 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 c uố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, c hẳ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 c ho 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ác h đối khác. Ví dụ:
  3. hiện ngay sau từ khoá print nhưng trước danh sác h đố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à c au "Xin c hao!\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 c ho câu lệnh print . Vậy, tóm lại, sau đây là c ách để sao c hé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 t rong $b. Nó minh hoạ gần như mọi thứ mà ta đã học t rong c hươ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ác h để 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 c hắc c hắ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ịc h 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 c ho cả t ệp index.html và index.c gi: 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 c ho 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
  4. đượ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 (exec utable) -o Tệp hoặc thư mục thuộc quyền sở hữu c ủa người dùng (người đang c hạy c hươ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 t hư 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 soc ket? -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 stic ky -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
  5. -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 c hú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 c ho lại giá trị đúng nếu tệp là khác rỗng, nhưng giá trị c ho lại là một loại đúng đặc biệt. Đó là c hiề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 (c húng đều là c hữ hoa c ả) c ho lại số ngày kể từ tệp được sửa đổi, t ruy c ập hay c ó thay đổi inode lần c uối (t uổi được đo tương đối theo thời gian c hương t rì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 c ho 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 c hỉ 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 c hính xác để được c ác tệp nằm giữa ba và bốn ngày lẻ. 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 c hỉ 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 c ho 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ì c hú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 c ho 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ử s tat(), toán tử trả lại mọi thứ mà lời gọi hàm hệ thống UNIX stat() c ung c ấp cho t a. 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ị t rả v ề hoặc là undef, c hỉ ra rằng s tat 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ác h 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ả c hi t iế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() t rê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
  6. 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() t hay vì stat() (cho c ùng t hô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 t rê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 c hương trình, thì Perl đều phải t rở ra hệ thống để hỏi bộ đệm stat t rên tệp (bộ đệm c ho 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 c ho c ùng một thông tin (điều này không thể thay đổi được trong một môi t rường khá không thân thiện). Đ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, s tat , hay lstat t rên _filehandle (một dấu gạch thấp) xem như toán hạng sẽ bảo c ho Perl dùng bất kì c ái gì ngẫu nhiên có t rong bộ nhớ từ lần kiểm tra tệp trước đó. Đôi khi điều này là nguy hiểm: một c hương trình con c ó thể gọi stat một c ác h 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 c ho 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 c ho 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 c họn cho các c hứ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 c hương trình đọc vào tên 1 tệp từ STDIN, t iế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 c hấ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 à c cc t hì bạn c ần phải hiển thị như sau: fred: aaa fred: bbb fred: c cc 2. Bạn hãy viết c hương trình đọc vào 1 tên tệp (để đọc ), 1 t ên tệp (để ghi), 1 c huỗi c ần tìm, 1 c huỗ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 "c huỗi c ần tìm" bằng "c huỗi thay thế". 3. Bạn hãy viết c hương trình đọc vào 1 danh sác h 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 (exec utable) và tệp nào không tồn tại. 4. Bạn hãy viết c hương trình đọc vào 1 danh sác h c ác tên tệp v à xác định xem tệp nào là "c ũ" nhất (thời gian lần c uối tệp được sửa đổi là lâu nhất trong danh sác h 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. M ục lục «« C hương 9 »» C hương 1 1
ADSENSE

CÓ THỂ BẠN MUỐN DOWNLOAD


ERROR:connection to 10.20.1.100:9315 failed (errno=111, msg=Connection refused)
ERROR:connection to 10.20.1.100:9315 failed (errno=111, msg=Connection refused)

 

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