2012-12-19 27 views
9

Tôi muốn viết một thứ gì đó vào một tệp có tên biến là $filename. Tôi không muốn ghi đè lên nó, vì vậy tôi kiểm tra đầu tiên nếu nó tồn tại và sau đó mở nó:Mở nguyên tử tệp không tồn tại trong Perl

#stage1 
if(-e $filename) 
{ 
    print "file $filename exists, not overwriting\n"; 
    exit 1; 
} 

#stage2 
open(OUTFILE, ">", $filename) or die $!; 

Nhưng điều này không phải là nguyên tử. Về mặt lý thuyết, ai đó có thể tạo tệp này giữa stage1stage2. Có một số biến thể của lệnh open sẽ thực hiện cả hai điều này theo cách nguyên tử, vì vậy nó sẽ không mở được tệp để ghi nếu tệp tồn tại?

Trả lời

4

Nếu bạn lo ngại về nhiều kịch bản Perl thay đổi cùng một tập tin, chỉ cần sử dụng flock() chức năng trong mỗi người để khóa các tập tin bạn quan tâm.

Nếu bạn đang lo lắng về quá trình bên ngoài, mà có thể bạn không có quyền kiểm soát, bạn có thể sử dụng chức năng sysopen(). Theo Lập trình Perl cuốn sách (mà tôi khuyên bạn nên, bằng cách này):

Để khắc phục vấn đề này ghi đè, bạn sẽ cần phải sử dụng sysopen, mà cung cấp điều khiển riêng về việc liệu để tạo ra một tệp mới hoặc một tệp hiện có. Và chúng tôi sẽ bỏ qua điều đó –e kiểm tra sự tồn tại tệp vì nó không phục vụ mục đích hữu ích ở đây và chỉ làm tăng hiển thị của chúng tôi với điều kiện chủng tộc.

Họ cũng cung cấp khối mẫu mã này:

use Fcntl qw/O_WRONLY O_CREAT O_EXCL/; 
open(FH, "<", $file) 
    || sysopen(FH, $file, O_WRONLY | O_CREAT | O_EXCL) 
    || die "can't create new file $file: $!"; 

Trong ví dụ này, đầu tiên họ kéo trong một vài hằng số (được sử dụng trong sysopen cuộc gọi). Tiếp theo, họ cố mở tệp bằng open và nếu điều đó không thành công, họ sẽ thử sysopen. Họ tiếp tục nói:

Bây giờ ngay cả khi file bằng cách nào đó lò xo vào sự tồn tại giữa khi mở thất bại và khi sysopen cố gắng để mở một tập tin mới cho văn bản, không có hại được thực hiện, bởi vì với những lá cờ được cung cấp, sysopen sẽ từ chối mở một tệp đã tồn tại.

Vì vậy, để làm cho mọi việc rõ ràng cho tình hình của bạn, loại bỏ các tập tin thử nghiệm hoàn toàn (không có giai đoạn hơn 1), và chỉ làm các hoạt động mở sử dụng mã tương tự như các khối ở trên. Đã giải quyết được vấn đề!

+0

này vẫn không giải quyết được * Về mặt lý thuyết ai đó có thể tạo ra tập tin này giữa stage1 và stage2 * vấn đề! Nó chỉ là một cách mở khóa các tập tin. – creaktive

+0

Chắc chắn rồi. Chúng tôi đã hoàn toàn thoát khỏi "giai đoạn 1" từ câu hỏi của OP. Bây giờ chỉ có một giai đoạn: mở tập tin! –

+0

Xin lỗi vì không đồng ý ... Còn về 'open (FH," <", $ file) || (! ngủ 1) || sysopen (...) '? Vẫn còn hai giai đoạn, bạn chỉ cần đặt chúng trong cùng một tuyên bố.Nêu tôi sai vui long chân chỉnh tôi. – creaktive

6

Dưới đây là một cách nguyên tử của các file đang mở:

#!/usr/bin/env perl 
use strict; 
use warnings qw(all); 

use Fcntl qw(:DEFAULT :flock); 

my $filename = 'test'; 
my $fh; 

# this is "atomic open" part 
unless (sysopen($fh, $filename, O_CREAT | O_EXCL | O_WRONLY)) { 
    print "file $filename exists, not overwriting\n"; 
    exit 1; 
} 

# flock() isn't required for "atomic open" per se 
# but useful in real world usage like log appending 
flock($fh, LOCK_EX); 

# use the handle as you wish 
print $fh scalar localtime; 
print $fh "\n"; 

# unlock & close 
flock($fh, LOCK_UN); 
close $fh; 

gỡ lỗi phiên:

[email protected]:~/stackoverflow$ cat test 
Wed Dec 19 12:10:37 2012 
[email protected]:~/stackoverflow$ perl sysopen.pl 
file test exists, not overwriting 
[email protected]:~/stackoverflow$ cat test 
Wed Dec 19 12:10:37 2012 
+1

Nếu đàn là cần thiết, điều này không trả lời câu hỏi của OP. Có cần thiết, hay không sysopen làm thủ thuật? – ikegami

+0

Cảm ơn bạn @ikegami, tôi đã chỉnh sửa câu trả lời cho biết rằng 'flock()' không liên quan đến câu hỏi, mặc dù thường xuất hiện trong mã tương tự. – creaktive

Các vấn đề liên quan