1. Trang chủ
  2. » Công Nghệ Thông Tin

Tước hiệu tệp và kiểu thử tệp

8 117 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Tớc hiệu tệp kiểm thử tệp Tớc hiệu tệp là gì? 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 thế giới bên ngoài. Chúng ta đã thấy 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 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) 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, nhng 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 $fred, một mảng @fred, một mảng kết hợp %fred, một chơng trình con &fred, một nhãn fred, bây giờ một t- ớc hiệu tệp fred). 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, 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. Mở đó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 (có thể là lớp vỏ). 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, tên nào đó); với FILEHANDLE là tớc hiệu tệp mới, còn tên nào đó là tên tệp UNIX 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ì cung dùng cùng toán tử open, nhng phần tiền tố của tên tệp có một dấu lớn hơn (nh trong vỏ): 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 vậy, nh trong vỏ, 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ố, nh trong: open (LOGFILE, >>mylogfile); Tất cả ba dạng này của open đều cho lại đúng nếu việc mở thành công sai nếu thất bại. (Việc mở một tệp đa vào sẽ sai, chẳng hạn, nếu tệp đó không có hay không thể thâm nhập tới đợc bởi không đợc phép; việc mở tệp đa sẽ sai nếu danh mục không cho ghi hay không cho thâm nhập tới.) 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 nhu 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(). Nhng 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. Một chút tiêu khiển: die() Ta hãy coi đây nh là một chú thích cuối trang lớn, nhng 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 cứ im ỉm bị bỏ đi (giống nh lời hứa hẹn vận động bầu cử năm trớc). Thờng bạn muốn kiểm tra lại kết quả của việc mở tệp 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 Rất tiếc, tôi không thể tạo đợc /tmp/dataplace\n; } else { # phần còn lại chơng trình của bạn } Nhng đấy là cả đống việc. đ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, phun ra danh sách đó (giống nh print) trên lối ra lỗi chuẩn, 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 Rất tiếc, tôi không thể tạo đợc /tmp/dataplace\n; } # phần còn lại chơng trình của bạn Nhng 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 unless (open(DATAPLACE, >/tmp/dataplace)) || die Rất tiếc, tôi không thể tạo đợc /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 điều này là hãy mở tệp đó ra nếu không thì chết quách đi cho rồi! đó là cách dễ dàng để nhớ bất kì khi nào dùng toán tử logic hay logic hoặc. Thông báo vào lúc chết (đợc xây dựng từ đối của die) có tên chơng trình Perl 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 chịu trách nhiệm cho việc ra không đúng lúc này. Nếu bạn không thích số dòng hay tệp bị lộ ra, thì phải chắc chắn rằng văn bản chết có một dấu dòng mới ở cuối. Chẳng hạn: die bạn nấu nớc xốt - lợn sữa; sẽ in ra tên tệp số dòng, trong khi die bạn nấu nớc xốt - lợn sữa\n; thì không in ra tên tệp số dòng. 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 hiệu: open (EP, /etc/passwd); while (<EP>) { chop; print Tôi thấy $_ trong tệp mật hiệu!\n; } Lu ý 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 nhng trớc danh sách đối: print LOGFILE Khoản mục kết thúc của $max\n; print STDOUT Xin chào, mọi ngời!\n; # giống nh in xin chào mọi ngời!\n Trong trờng hợp này, thông báo bắt đầu với Khoản mục kết thúc sẽ ghi lên tớc hiệu tệp LOGFILE, mà giả thiết là đã mở trớc đây trong chơng trình. xin chào mọi ngời 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 vài trang vừa qua: open (IN,$a) || die không thể mở đợc $a để đọc; open (OUT, >$b) || die không thể tạo dợc $b; while (<IN>) { # đọc một dòng từ tệp $a vào $_ print OUT $_; # in dòng đó vào tệp $b } close(IN); close(OUT); 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 bản ghi vỏ 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; ngợc lại nó là sai. Chẳng hạn: $x = /etc/passwd; if (-e $x) { # liệu /etc/passwd có tồn tại không? # tốt } else { print how in the world did you get logged in?\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 tính 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ả mật hiệu hệ thống tệp nhóm: if (-e /etc/passwd && -e /etc/group) { print looks like you have a normal system\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 đọc đợc. Tơng tự, -w $filevar kiểm tra xem liệu có ghi đợc đợc 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 ghi đợc: print ở đâu? ; $filename = <STDIN>; chop($filename); # quẳng cái dấu dòng mới khó chịu đi if (-r $filename && -w $filename) { # tệp đ có, tôi có thể đọc ghi nóã . } Nhiều việc kiểm tra tệp đãcó sẵn. Xin xem Bảng 10-1 để biết danh sách đầy đủ. Bảng 10.1: Kiểm tra tệp ý nghĩa của chúng Kiểm tra tệp ý nghĩa -r Tệp hay danh mục đọc đợc -w Tệp hay danh mục ghi đợc -x Tệp hay danh mục thực hiện đợc -o Tệp hay danh mục do ngời dùng sở hữu -R Tệp hay danh mục đọc đợc bởi ngời dùng thực, không phải ngời dùng hiệu quả (khác -r với chơng trình setuid) -W Tệp hay danh mục ghi đợc bởi ngời dùng thực, không phải ngời dùng hiệu quả (khác với -w cho ch- ơng trình setuid) -X Tệp hay danh mục thực hiện đợc bởi ngời dùng thực, không phải ngời dùng hiệu quả (khác với -x cho chơng trình setuid) -O Tệp hay danh mục đợc sở hữu bởi ngời dùng thực, không phải ngời dùng hiệu quả (khác với -o cho ch- ơng trình setuid) -e Tệp hay danh mục đã có -z Tệp đã có có kích thớc không (danh mục thì không bao giờ rỗng) -s Tệp hay danh mục đã có có kích thớc khác không (giá trị đợc tính theo byte) -f Khoản mục là tệp rõ -d Khoản mục là danh mục -l Khoản mục là symlink -S Khoản mục là chỗ cắm -p Khoản mục là đờng ống có tên (một fifo) -b Khoản mục là tệp khối đặc biệt (giống nh đĩa tháo lắp đợc) -c Khoản mục là tệp kí tự đặc biệt (nh thiết bị vào/ra) -u Tệp hay danh mục là setuid -g Tệp hay danh mục là setgid -k Tệp hay danh mục có tập bit dính -t isatty() trên tớc hiệu tệp là đúng -T Tệp là văn bản -B Tệp là nhị phân -M sửa tuổi theo ngày -A Tuổi thâm nhập theo ngày -C Tuổi thay đổi inode theo ngày 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, nhng 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 -C (đúng, chúng đều là chữ hoa cả) cho lạu số ngày kể từ tệp đợc sửa đổi, thâm nhập hay có thay đổi inode * lần cuối. (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 toàn bộ số (chẳng hạn ba), 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 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) { # mở tệp trên SOMEFILE là thực hiện đợc } 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 $_ là đọc đợc\n if -r; # cũng nh -r $_ } Các toán tử stat() 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ộ câu chuyện. 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ử cho lại đủ mọi thứ mà lời gọi hàm hệ thống UNIX stat() cho (hi vọng nhiều thứ hơn điều bạn muốn biết). 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ị cho lại hoặc là undef, chỉ ra rằng stat không tsinh đợc, hay một mảng 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, * * 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. $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 stat(2) của bạn. 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 ID nhóm của tệp mật hiệu, ta hãy thử: ($uid,$gid) = (stat (/etc/passwd)) [4, 5]; đó là cách làm. 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() trên những điều 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 $_. 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 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) Điều này có vẻ nh lãng phí, 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, ném tiêu bộ đệm của bạn đi. Nhng 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 đọc đợc $filevar, dùng mẹo mới: if (-r $filevar && -w _) { print $filevar là vừa đọc đợc ghi đợc\n; } Lu ý 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ó. Bài tập Xem phụ lục A về lời giải. 1. Hãy viết một chơng trình để đọc vào một tên tệp từ STDIN, rồi mở tệp đó hiển thị nội dung của nó có đứng trớc bởi tên tệp một dấu hai chấm. Chẳng hạn, nếu fred đợc đọc vào, tệp fred bao gồm ba dòng aaa, bbb ccc thì bạn sẽ thấy fred: aaa, fred: bbb fred: ccc. 1. Hãy viết một chơng trình nhắc đa vào một tên tệp vào, một tên tệp ra, một mẫu tìm kiếm, một xâu thay thế, rồi thay thế tất cả mọi lần xuất hiện của mẫu tìm kiếm bằng xâu thay thế trong khi sao tệp vào sang tệp ra. Hãy thử nó trên các tệp. Bạn có thể ghi đè một tệp hiện có (đừng thử nó với những tệp quan trọng!) không? Bạn có thể dùng các kí tự biểu thức chính qui trong xâu tìm kiếm không? Bạn có thể dùng \1 trong xâu thay thế không? 1. Hãy viết một chơng trình để đọc vào một danh sách các tên tệp rồi cho hiển thị từ đó các tệp nào là đọc đợc, ghi đợc, và/hoặc thực hiện đợc, tệp nào không tồn tại. (Bạn có thể thực hiện từng phép kiểm thử cho từng tên tệp khi bạn đọc chúng; hay trên toàn bộ tập các tên khi bạn đã đọc tất cả chúng. Đừng quên loại bỏ dấu dòng mới tại cuối mỗi tên tệp mà bạn đã đọc vào. 1. Hãy viết một chơng trình để đọc vào một danh sách các tên tệp, tìm tệp cũ nhất trong chúng. hãy in ra tên của tệp đó, tuổi của nó theo số ngày. . Tớc hiệu tệp và kiểm thử tệp Tớc hiệu tệp là gì? 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à thế. vào một tên tệp từ STDIN, rồi mở tệp đó và hiển thị nội dung của nó có đứng trớc bởi tên tệp và một dấu hai chấm. Chẳng hạn, nếu fred đợc đọc vào, và tệp

Ngày đăng: 28/09/2013, 10:20

Xem thêm: Tước hiệu tệp và kiểu thử tệp

w