2012-12-19 13 views
9

में गैर-मौजूदा फ़ाइल का परमाणु खुला मैं एक फ़ाइल में कुछ लिखना चाहता हूं जिसका नाम परिवर्तनीय $filename में है। मैं इसे अधिलेखित नहीं करना चाहते, तो मैं सबसे पहले यदि वह मौजूद है और फिर उसे खोलें:पर्ल

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

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

लेकिन इस परमाणु नहीं है। सैद्धांतिक रूप से कोई व्यक्ति इस फ़ाइल को stage1 और stage2 के बीच बना सकता है। क्या open कमांड का कुछ संस्करण है जो इन दोनों चीजों को परमाणु तरीके से करेगा, इसलिए फ़ाइल मौजूद होने पर यह लिखने के लिए फ़ाइल खोलने में विफल रहेगी?

उत्तर

4

आप एक ही फाइल को संशोधित करने के लिए कई पर्ल स्क्रिप्ट के बारे में चिंतित हैं, तो सिर्फ फ़ाइल में आपकी रुचि है लॉक करने के लिए हर एक में flock() समारोह का उपयोग करें।

आप बाहरी प्रक्रियाओं, बारे में चिंतित हैं जो आपके पास शायद नियंत्रण नहीं है, आप sysopen() फ़ंक्शन का उपयोग कर सकते हैं। प्रोग्रामिंग पर्ल पुस्तक (जो मेरी सशक्त अनुशंसा, वैसे) के अनुसार:

अधिलेखन की इस समस्या को दूर करने के लिए आपको sysopen उपयोग करने के लिए है, जो है कि क्या एक बनाने के लिए अधिक व्यक्तिगत नियंत्रण प्रदान करता है की आवश्यकता होगी नई फाइल या क्लॉबर एक मौजूदा है। और हम –e फ़ाइल अस्तित्व परीक्षण खो देंगे क्योंकि यह यहां कोई उपयोगी उद्देश्य नहीं देता है और केवल दौड़ की स्थिति में हमारे एक्सपोजर को बढ़ाता है।

उन्होंने यह भी कोड के इस नमूना ब्लॉक प्रदान करते हैं:

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: $!"; 

इस उदाहरण में, वे पहली बार में कुछ स्थिरांक में खींच (sysopen कॉल में इस्तेमाल किया जाएगा)। इसके बाद, वे फ़ाइल को open के साथ खोलने का प्रयास करते हैं, और यदि यह विफल रहता है, तो वे sysopen आज़माएं। वे कहते हैं कि करने के लिए पर जारी:

अब भले ही फ़ाइल किसी भी तरह जब खुले विफल रहता है और जब sysopen की कोशिश करता लेखन के लिए एक नई फ़ाइल को खोलने के लिए, कोई नुकसान , किया जाता है क्योंकि के साथ झंडे प्रदान की के बीच अस्तित्व में स्प्रिंग्स, sysopen एक फ़ाइल जो पहले से मौजूद है, को खोलने से इंकार कर देगा।

तो, अपनी स्थिति के लिए चीजों को स्पष्ट करना, फ़ाइल परीक्षण पूरी तरह से (कोई और अधिक चरण 1) निकाल सकते हैं और केवल ऊपर ब्लॉक के समान कोड का उपयोग कर खुला आपरेशन करते हैं। समस्या सुलझ गयी!

+0

यह अभी भी समाधान नहीं करता है * सैद्धांतिक रूप से किसी को Stage1 और stage2 * मुद्दे के बीच इस फाइल बना सकते हैं! यह फाइलें खोलने का सिर्फ एक गैर-क्लॉबरिंग तरीका है। – creaktive

+0

यकीन है कि यह करता है। हमने ओपी के प्रश्न से पूरी तरह से "चरण 1" से छुटकारा पा लिया है। अब केवल एक मंच है: फ़ाइल खोलना! –

+0

असहमत होने के लिए खेद है ... 'ओपन (एफएच, "<", $ फ़ाइल) के बारे में क्या || (! नींद 1) || sysopen (...) '? अभी भी दो चरण हैं, आप उन्हें एक ही कथन में डाल दें।कृपया मुझे सुधारें अगर मैं गलत हूं। – creaktive

6

यहाँ खोलने फ़ाइलों का एक परमाणु तरीका है:

#!/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; 

डीबग सत्र:

[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

यदि झुंड आवश्यक है, तो यह ओपी के प्रश्न का उत्तर नहीं देता है। क्या यह जरूरी है, या सिसोपेन चाल करता है? – ikegami

+0

धन्यवाद @ikegami, मैंने यह इंगित करने के लिए जवाब संपादित किया है कि 'झुंड() 'प्रश्न से संबंधित नहीं है, यद्यपि आमतौर पर समान कोड में मौजूद है। – creaktive