PHP file_put_contents फ़ाइल लॉकिंग


9

सेनारियो:

आपके पास प्रत्येक पंक्ति में एक स्ट्रिंग (औसत वाक्य लायक) के साथ एक फ़ाइल है। तर्कों के लिए यह कहने दें कि यह फ़ाइल आकार में 1Mb (हजारों लाइनें) है।

आपके पास एक स्क्रिप्ट है जो फ़ाइल को पढ़ती है, दस्तावेज़ के भीतर कुछ तारों को बदल देती है (न केवल आकर्षक, बल्कि कुछ लाइनों को हटाने और संशोधित भी करती है) और फिर नए डेटा के साथ सभी डेटा को अधिलेखित कर देती है।

प्रश्न:

  1. क्या सर्वर 'PHP, OS या httpd आदि में पहले से ही इस तरह की समस्याओं को रोकने के लिए सिस्टम हैं (पढ़ने / लिखने के माध्यम से आधा रास्ता)?

  2. यदि ऐसा होता है, तो कृपया बताएं कि यह कैसे काम करता है और प्रासंगिक प्रलेखन के उदाहरण या लिंक देता है।

  3. यदि नहीं, तो क्या ऐसी चीजें हैं जो मैं सक्षम या सेट-अप कर सकता हूं, जैसे कि एक फ़ाइल को तब तक लॉक करना जब तक कि एक लेखन पूरा न हो जाए और अन्य सभी रीड्स और / या लिखना तब तक विफल हो जाए जब तक कि पिछली स्क्रिप्ट लिखना समाप्त न हो जाए?

मेरी मान्यताओं और अन्य जानकारी:

  1. विचाराधीन सर्वर PHP और Apache या Lighttpd चला रहा है।

  2. यदि स्क्रिप्ट एक उपयोगकर्ता द्वारा कॉल की जाती है और फ़ाइल में लिखने के माध्यम से आधी हो जाती है और दूसरा उपयोगकर्ता उस सटीक समय पर फ़ाइल पढ़ता है। जो उपयोगकर्ता इसे पढ़ता है, उसे पूर्ण दस्तावेज़ नहीं मिलेगा, क्योंकि यह अभी तक नहीं लिखा गया है। (यदि यह धारणा गलत है तो कृपया मुझे सुधारें)

  3. मैं केवल PHP लिखने और एक पाठ फ़ाइल को पढ़ने के साथ संबंधित हूं, और विशेष रूप से, फ़ंक्शन "fopen" / "fwrite" और मुख्य रूप से "file_put_contents"। मैंने "file_put_contents" दस्तावेज़ देखा है, लेकिन "LOCK_EX" ध्वज क्या है या क्या करता है, इसका विवरण या विवरण का स्तर नहीं मिला है।

  4. परिदृश्य सबसे खराब स्थिति का एक उदाहरण है, जहां मुझे लगता है कि इन मुद्दों को फ़ाइल के बड़े आकार और डेटा को संपादित करने के तरीके के कारण होने की अधिक संभावना है। मैं इन मुद्दों के बारे में अधिक सीखना चाहता हूं और "mysql का उपयोग करें" या "आप ऐसा क्यों कर रहे हैं" जैसे जवाब या टिप्पणियों की आवश्यकता नहीं है या नहीं, क्योंकि मैं ऐसा नहीं कर रहा हूं, मैं सिर्फ फ़ाइल पढ़ने / लिखने के बारे में सीखना चाहता हूं PHP के साथ और सही स्थानों / दस्तावेज़ीकरण में नहीं दिख रहा है और हाँ मैं समझता हूँ कि PHP इस तरह से फाइलों के साथ काम करने के लिए सही भाषा नहीं है।


2
मैं आपको अनुभव से बता सकता हूं कि PHP के साथ बड़ी फ़ाइलों को पढ़ना और लिखना (1 एमबी वास्तव में इतना बड़ा नहीं है, लेकिन अभी भी) मुश्किल (और धीमा) हो सकता है। आप हमेशा फ़ाइल को लॉक कर सकते हैं , लेकिन यह शायद आसान होगा और सिर्फ एक डेटाबेस का उपयोग करने के लिए सुरक्षित होगा।
NullUserException

मुझे पता है कि डीबी का उपयोग करना बेहतर होगा। कृपया प्रश्न पढ़ें (अंतिम पैरा संख्या 4)
hozza

2
मैंने सवाल पढ़ा; मैं कह रहा हूं कि यह एक अच्छा विचार नहीं है और बेहतर विकल्प हैं।
NullUserException

2
file_put_contents()fopen()/fwrite()डांस के लिए सिर्फ एक रैपर है , LOCKEXजैसा आप कॉल करेंगे वैसा ही होगा flock($handle, LOCKEX)
यानिस

2
@hozza यही कारण है कि मैंने एक टिप्पणी पोस्ट की, जवाब नहीं।
NullUserException

जवाबों:


4

1) नहीं 3) नहीं

मूल सुझाए गए दृष्टिकोण के साथ कई समस्याएं हैं:

सबसे पहले, कुछ यूनिक्स जैसे सिस्टम जैसे लिनक्स में लॉकिंग सपोर्ट लागू नहीं हो सकता है। OS डिफ़ॉल्ट रूप से फ़ाइलों को लॉक नहीं करता है। मैंने syscalls को NOP (नो-ऑपरेशन) होने के रूप में देखा है, लेकिन यह कुछ साल पहले है, इसलिए आपको यह सत्यापित करने की आवश्यकता है कि क्या आपके एप्लिकेशन के लॉक सेट को किसी अन्य उदाहरण द्वारा सम्मानित किया गया है। (यानी 2 समवर्ती आगंतुक)। यदि लॉकिंग अभी भी लागू नहीं किया गया है [बहुत संभावना है], OS आपको उस फ़ाइल को अधिलेखित करने देता है।

प्रदर्शन के कारणों के लिए बड़ी फ़ाइलों को लाइन-दर-पंक्ति पढ़ना संभव नहीं है। मैं पूरी फ़ाइल को मेमोरी में लोड करने के लिए file_get_contents () का उपयोग करने का सुझाव देता हूं और फिर लाइनों को प्राप्त करने के लिए इसे विस्फोट करता हूं। वैकल्पिक रूप से, ब्लॉक में फ़ाइल को पढ़ने के लिए फ़्रेड () का उपयोग करें। उद्देश्य रीड कॉल की संख्या को कम करना है।

फ़ाइल लॉकिंग के संबंध में:

LOCK_EX का अर्थ है एक विशेष ताला (आमतौर पर लिखने के लिए)। केवल एक प्रक्रिया किसी दिए गए फ़ाइल के लिए किसी विशेष समय में एक विशेष लॉक रख सकती है। LOCK_SH एक साझा लॉक है (आमतौर पर पढ़ने के लिए), एक से अधिक प्रक्रिया किसी दिए गए फ़ाइल के लिए एक साझा लॉक को एक निश्चित समय पर रोक सकती है। LOCK_UN फ़ाइल को अनलॉक करता है। यदि आप file_get_contents () http://en.wikipedia.org/wiki/File_locking#In_Unix-like_systems का उपयोग करते हैं तो अनलॉकिंग स्वचालित रूप से की जाती है

सुरुचिपूर्ण समाधान

PHP डेटा स्ट्रीम फ़िल्टर का समर्थन करती है जो फ़ाइलों में या अन्य इनपुट से डेटा को संसाधित करने के लिए होती हैं। आप मानक API का उपयोग करके एक ऐसा फ़िल्टर ठीक से बनाना चाह सकते हैं। http://php.net/manual/en/function.stream-filter-register.php http://php.net/manual/en/filters.php

वैकल्पिक समाधान (3 चरणों में):

  1. एक कतार बनाएँ। एक फ़ाइलनाम को संसाधित करने के बजाय, डेटाबेस या अन्य तंत्र का उपयोग करके लंबित / संसाधित / कहीं संसाधित किए गए अद्वितीय फ़ाइलनामों को संग्रहीत करने के लिए उपयोग करें। इस तरह से कुछ भी नहीं लिखा जाता है। डेटाबेस अतिरिक्त जानकारी संग्रहीत करने के लिए भी उपयोगी होगा, जैसे मेटाडेटा, विश्वसनीय टाइमस्टैम्प, प्रसंस्करण परिणाम, और अन्य।

  2. कुछ MB तक की फ़ाइलों के लिए, पूरी फ़ाइल को मेमोरी में पढ़ें और फिर उसे प्रोसेस करें (file_get_contents () + explode () + foreach ())

  3. बड़ी फ़ाइलों के लिए ब्लॉक (यानी 1024 बाइट्स) में फाइल पढ़ें और प्रत्येक ब्लॉक को पढ़ने के रूप में वास्तविक-समय में लिखें + (अंतिम पंक्ति के बारे में सावधान रहना जो \ n के साथ समाप्त नहीं होता है। इसे अगले बैच में संसाधित करने की आवश्यकता है।


1
"मैंने syscalls को NOP (नो-ऑपरेशन) होते देखा है ..." कौन सा कर्नेल?
मासिमो

1
"बड़ी फ़ाइलों को लाइन-बाय-लाइन पढ़ना प्रदर्शन कारणों से संभव नहीं है। मैं पूरी फ़ाइल को मेमोरी में लोड करने के लिए file_get_contents () का उपयोग करने का सुझाव देता हूं ..." यह एक गैर-भावना है। मैं कह सकता हूं: प्रदर्शन कारणों से बड़ी फ़ाइलों को मेमोरी में नहीं पढ़ना ... क्या करना है यह कई अन्य कारकों पर निर्भर करता है।
मासिमो

4

मुझे पता है कि यह उम्र पुरानी है, लेकिन अगर कोई इसमें भाग लेता है। IMHO इसके बारे में जाने का तरीका इस प्रकार है:

1) file_get_contents ('original.txt') का उपयोग करके मूल फ़ाइल (जैसे original.txt) खोलें।

2) अपने परिवर्तन / संपादन करें।

3) file_put_contents ('original.txt.tmp') का उपयोग करें और इसे अस्थायी फ़ाइल में लिखें ।.txt.tmp।

4) फिर tmp फाइल को ओरिजिनल फाइल पर ले जाएं, ओरिजिनल फाइल को बदले। इसके लिए आप नाम बदलें ('original.txt.tmp', 'original.txt') का उपयोग करें।

लाभ: जबकि फ़ाइल को संसाधित किया जा रहा है और फ़ाइल को लिखा जाना बंद नहीं है और अन्य अभी भी पुरानी सामग्री को पढ़ सकते हैं। कम से कम लिनक्स / यूनिक्स बक्से का नाम बदलना एक परमाणु ऑपरेशन है। फ़ाइल लेखन के दौरान कोई भी रुकावट मूल फ़ाइल को नहीं छूती है। केवल एक बार फाइल पूरी तरह से डिस्क पर लिखे जाने के बाद इसे स्थानांतरित किया जाता है। Http://php.net/manual/en/function.rename.php पर टिप्पणियों में इस पर अधिक दिलचस्प पढ़ा

संप्रदायों को संपादित करने के लिए संपादित करें (टिप्पणी के लिए भी):

/programming/7054844/is-rename-atomic के पास आगे के संदर्भ हैं कि अगर आपको फाइलसिस्टम में काम कर रहे हैं तो आपको क्या करने की आवश्यकता हो सकती है।

पढ़ने के लिए साझा किए गए लॉक पर मुझे यकीन नहीं है कि इसकी आवश्यकता क्यों होगी क्योंकि इस कार्यान्वयन में सीधे फाइल पर कोई लेखन नहीं है। PHP का झुंड (जो ताला प्राप्त करने के लिए उपयोग किया जाता है) एक छोटा लेकिन अविश्वसनीय है और इसे अन्य प्रक्रियाओं द्वारा अनदेखा किया जा सकता है। यही कारण है कि मैं नाम बदलने का सुझाव दे रहा हूं।

नाम बदलने की प्रक्रिया के लिए नाम बदलने वाली फ़ाइल को आदर्श रूप से विशिष्ट रूप से नामित किया जाना चाहिए ताकि यह सुनिश्चित हो सके कि 2 प्रक्रियाएं समान कार्य नहीं करती हैं। लेकिन यह निश्चित रूप से एक ही समय में एक से अधिक लोगों द्वारा एक ही फाइल के संपादन को नहीं रोकता है। लेकिन कम से कम फ़ाइल को बरकरार रखा जाएगा (अंतिम संपादन जीत)।

चरण 3) और 4) तब यह बन जाएगा:

$tempfile = uniqid(microtime(true)); // make sure we have a unique name
file_put_contents($tempFile); // write temp file
rename($tempfile, 'original.txt'); // ideally on the same filesystem

बिल्कुल वैसा ही जैसा मैं प्रपोज करना चाहता था। लेकिन मैं डेटा क्लॉबर को रोकने के लिए पढ़ते समय एक साझा लॉक भी प्राप्त करूंगा।
मार्को-एक

नाम एक ही डिस्क पर एक परमाणु ऑपरेशन है, विभिन्न डिस्क पर नहीं।
Xnoise

करने के लिए वास्तव में एक अनूठा tempfile नाम की गारंटी, आप भी उपयोग कर सकते हैं काम करता है, जो atomically एक फ़ाइल और रिटर्न फाइल नाम बनाता है। tempnam
मैथिज्स कोइजमैन

1

File_put_contents () के लिए PHP दस्तावेज़ीकरण में आप उदाहरण # 2 LOCK_EX के लिए उपयोग कर सकते हैं , बस डाल:

file_put_contents('somefile.txt', 'some text', LOCK_EX);

LOCK_EX एक के साथ एक स्थिर है पूर्णांक की तुलना में एक में कुछ कार्यों पर इस्तेमाल किया जा सकता मूल्य बिटवाइज़

फ़ाइलों के लिए लॉकिंग को नियंत्रित करने के लिए एक विशिष्ट कार्य भी है: झुंड () तरीके से।


हालांकि यह दिलचस्प है और कुछ स्थितियों में उपयोगी हो सकता है, जब किसी फ़ाइल को पढ़ना, संशोधित करना और पुन: लिखना, लॉक को आपके पढ़ने से पहले अधिग्रहित किया जाना चाहिए और इसे तब तक बनाए रखा जाना चाहिए जब तक कि इसे पूरी तरह से फिर से लिखा नहीं गया हो (अन्यथा एक अन्य प्रक्रिया एक पुरानी कॉपी पढ़ सकती है और इसे बदल सकती है। आपकी प्रक्रिया समाप्त होने के बाद वापस)। मुझे विश्वास नहीं है कि यह हासिल किया जा सकता है file_get/put_contents
जूल्स

0

एक ऐसा मुद्दा जिसका आपने उल्लेख नहीं किया है कि आपको दौड़ की स्थितियों से सावधान रहने की आवश्यकता है जहां आपकी स्क्रिप्ट के दो उदाहरण लगभग एक ही समय पर चल रहे हैं, उदाहरण के लिए घटनाओं का यह क्रम:

  1. स्क्रिप्ट उदाहरण 1: फ़ाइल पढ़ता है
  2. स्क्रिप्ट उदाहरण 2: फ़ाइल पढ़ता है
  3. स्क्रिप्ट उदाहरण 1: फ़ाइल में परिवर्तन बदलता है
  4. स्क्रिप्ट उदाहरण 2: अपने स्वयं के परिवर्तनों के साथ फाइल करने के लिए पहले स्क्रिप्ट उदाहरण के परिवर्तन को ओवरराइट करता है (क्योंकि इस बिंदु पर इसका रीड बासी हो गया है)।

इसलिए जब एक बड़ी फाइल को अपडेट किया जाता है, तो आपको उस फ़ाइल को LOCK_EX करने की आवश्यकता होती है जब आप इसे पढ़ते हैं और तब तक लॉक जारी नहीं करते हैं जब तक कि राइट्स नहीं बना दिया गया हो। इस उदाहरण में, मेरा मानना ​​है कि दूसरी स्क्रिप्ट का उदाहरण थोड़ी देर के लिए लटका होगा, क्योंकि यह फ़ाइल तक पहुंचने के लिए अपनी बारी का इंतजार करता है, लेकिन यह खोए हुए डेटा से बेहतर है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.