मैं जावा (यदि संभव हो) का उपयोग करके किसी फ़ाइल को कैसे लॉक कर सकता हूं


121

मेरे पास एक जावा प्रक्रिया है जो एक FileReader का उपयोग करके एक फ़ाइल खोलता है। मैं इस फ़ाइल को खोलने से किसी अन्य (जावा) प्रक्रिया को कैसे रोक सकता हूं या कम से कम उस दूसरी प्रक्रिया को सूचित कर सकता हूं कि फाइल पहले से ही खुली हुई है? क्या यह स्वचालित रूप से दूसरी प्रक्रिया को अपवाद बनाता है यदि फ़ाइल खुली है (जो मेरी समस्या हल करती है) या क्या मुझे स्पष्ट रूप से किसी तरह के झंडे या तर्क के साथ पहली प्रक्रिया में इसे खोलना है?

स्पष्टीकरण देना:

मेरे पास एक जावा ऐप है जो एक फ़ोल्डर को सूचीबद्ध करता है और इसे संसाधित करने के लिए लिस्टिंग में प्रत्येक फ़ाइल खोलता है। यह प्रत्येक फाइल को एक के बाद एक प्रोसेस करता है। प्रत्येक फ़ाइल के प्रसंस्करण में इसे पढ़ने और सामग्री के आधार पर कुछ गणनाएं करने और लगभग 2 मिनट लगते हैं। मेरे पास एक और जावा ऐप भी है जो समान काम करता है लेकिन इसके बजाय फाइल पर लिखता है। मैं जो चाहता हूं, उसी समय इन ऐप्स को चलाने में सक्षम हो सकता हूं इसलिए परिदृश्य इस तरह से चलता है। ReadApp फ़ोल्डर को सूचीबद्ध करता है और फ़ाइलों को ए, बी, सी पाता है। यह फ़ाइल ए को खोलता है और रीडिंग शुरू करता है। WriteApp फ़ोल्डर को सूचीबद्ध करता है और फ़ाइलें A, B, C. को ढूँढता है। यह फ़ाइल A को खोलता है, देखता है कि खुली हुई है (अपवाद या किसी भी तरह से) खुली हुई है और फ़ाइल में जाती है। B. ReadApp फ़ाइल A को समाप्त करती है और इसे जारी रखती है। यह देखता है कि खुला है और सी के लिए जारी है। यह महत्वपूर्ण है कि WriteApp doesn ' t लिखिए जबकि ReadApp एक ही फाइल या इसके विपरीत पढ़ रहा है। वे विभिन्न प्रक्रियाएं हैं।


12
क्या आपका मतलब प्रक्रिया (दो JVM) या थ्रेड (एक ही JVM) के रूप में 'प्रोसेस' से है । उत्तर पर प्रभाव सर्वोपरि है।
स्टु थॉम्पसन

सैंपल कोड दिखाते हुए समाधान यहाँ देखें: stackoverflow.com/a/58871479/5154619
Davi Cavalcanti

जवाबों:


117

FileChannel.lock शायद वही है जो आप चाहते हैं।

try (
    FileInputStream in = new FileInputStream(file);
    java.nio.channels.FileLock lock = in.getChannel().lock();
    Reader reader = new InputStreamReader(in, charset)
) {
    ...
}

(अस्वीकरण: कोड संकलित नहीं किया गया और निश्चित रूप से परीक्षण नहीं किया गया।)

फ़ाइललॉक के लिए एपीआई डॉक्टर में "प्लेटफ़ॉर्म निर्भरता" नामक अनुभाग पर ध्यान दें ।


22
इससे भी महत्वपूर्ण बात, यह समझें कि जेवीएम के लिए लॉक, और एकल जेवीएम के भीतर अलग-अलग थ्रेड द्वारा एक्सेस के लिए फाइल लॉक करने के लिए उपयुक्त नहीं है।
स्टु थॉम्पसन

11
आपको एक लिखने योग्य स्ट्रीम (यानी FileOutputStream) की आवश्यकता है।
जेवियर

@ जेवियर क्या आप? मैंने कोशिश नहीं की है। एपीआई डॉक्स में से कुछ भी नहीं कहते हैं कि यह एक आवश्यकता है। FileOutputStreamएक के लिए ज्यादा इस्तेमाल नहीं होने जा रहा है Reader
टॉम हैटिन

18
हां, मैंने इसे आजमाया और इसे फेंक दिया NonWritableChannelException, क्योंकि lock()एक विशेष ताला प्राप्त करने का प्रयास किया गया, लेकिन इसके लिए लिखने की आवश्यकता है। यदि आपके पास एक इनपुट स्ट्रीम है, तो आप उपयोग कर सकते हैं lock(0L, Long.MAX_VALUE, false)जो एक साझा लॉक प्राप्त करता है और केवल एक रीड एक्सेस की आवश्यकता होती है। RandomAccessFileयदि आप पढ़ते समय एक विशेष लॉक चाहते हैं तो आप रीड-राइट मोड में एक ओपन का उपयोग कर सकते हैं ... लेकिन यह समवर्ती पाठकों को मना करेगा।
जेवियर १

6
@ जेवियर मुझे लगता है कि आप कहने का मतलब है lock(0L, Long.MAX_VALUE, true), नहीं lock(0L, Long.MAX_VALUE, false)। अंतिम तर्क है boolean shared docs.oracle.com/javase/8/docs/api/java/nio/channels/…
john sullivan

60

java.ioपैकेज में कक्षाओं का उपयोग न करें , इसके बजाय पैकेज का उपयोग करें java.nio। उत्तरार्द्ध में एक FileLockवर्ग है। आप लॉक को एक पर लागू कर सकते हैं FileChannel

 try {
        // Get a file channel for the file
        File file = new File("filename");
        FileChannel channel = new RandomAccessFile(file, "rw").getChannel();

        // Use the file channel to create a lock on the file.
        // This method blocks until it can retrieve the lock.
        FileLock lock = channel.lock();

        /*
           use channel.lock OR channel.tryLock();
        */

        // Try acquiring the lock without blocking. This method returns
        // null or throws an exception if the file is already locked.
        try {
            lock = channel.tryLock();
        } catch (OverlappingFileLockException e) {
            // File is already locked in this thread or virtual machine
        }

        // Release the lock - if it is not null!
        if( lock != null ) {
            lock.release();
        }

        // Close the file
        channel.close();
    } catch (Exception e) {
    }

btw, मैं इस टिप stackoverflow.com/a/35885/1422630 से वर्तमान फ़ाइल को लॉक फ़ाइल पर लिख रहा हूं , इसलिए मैं इसे नए उदाहरण पर पढ़ सकता हूं!
कुंभ राशि बिजली

1
यह एक अच्छा लग रहा था, लेकिन यह काम नहीं करता है। मुझे हर बार ओवरलैपिंगफाइललॉक अपवाद मिलता है, यहां तक ​​कि जब फ़ाइल एक्ससिस्ट भी नहीं हुई
गेवरियल

1
समस्या तब होगी जब आप लॉक के बाद tryLock को कॉल करेंगे जैसा कि उदाहरण में लिखा गया है
इगोर वुकोविक

17

यदि आप Java NIO ( JDK 1.4 या अधिक से अधिक ) का उपयोग कर सकते हैं , तो मुझे लगता है कि आप ढूंढ रहे हैंjava.nio.channels.FileChannel.lock()

FileChannel.lock ()


5
शायद। ओपी 'प्रक्रिया' से क्या मतलब है पर निर्भर करता है। "फ़ाइल लॉक पूरे जावा वर्चुअल मशीन की ओर से आयोजित किए जाते हैं। वे एक ही वर्चुअल मशीन के भीतर कई थ्रेड्स द्वारा फ़ाइल तक पहुंच को नियंत्रित करने के लिए उपयुक्त नहीं हैं।"
स्टु थॉम्पसन

@Stu: मुझे पता है कि आप इस सवाल का जवाब बहुत पहले दे चुके हैं, लेकिन मुझे आशा है कि आप विस्तार से बता सकते हैं कि आपका क्या मतलब हैFile locks are held on behalf of the entire Java virtual machine. They are not suitable for controlling access to a file by multiple threads within the same virtual machine
थंग फाम

3
@Harry वह डॉक्स से उद्धृत कर रहा है: download.oracle.com/javase/6/docs/api/java/nio/channels/… इसका अर्थ है कि यह थ्रेड्स के लिए अदृश्य है लेकिन अन्य प्रक्रियाओं को प्रभावित करता है।
अर्तुर कज्जाका

@ हेर्री: इन नेक्रो-टिप्पणियों को और भी अधिक जोड़ने के लिए, कल्पना कीजिए कि आप टॉमकैट के साथ वेबसाइटों की सेवा के लिए जावा का उपयोग कर रहे हैं। आपके पास बहुत सारे थ्रेड हो सकते हैं, प्रत्येक एक वेब-ब्राउज़र से एक अनुरोध परोसता है। हालांकि, वे सभी एक ही फाइल लॉकिंग तंत्र को नियंत्रित करते हैं जैसे कि रसोई में बहुत सारे रसोइए। एक अनुरोध एक दूसरे के बीच में खत्म हो सकता है, और अचानक आपकी फ़ाइल "अनलॉक" हो गई, जबकि आप अभी भी कुछ के बीच में थे, और फिर कुछ अन्य प्रक्रिया जैसे क्रोनजोब इसे बंद कर सकता है, और फिर आपने अप्रत्याशित रूप से अपना खो दिया है लॉक और आपका अनुरोध समाप्त नहीं हो सकता ...
Darien


5

यह वह नहीं हो सकता है जिसे आप ढूंढ रहे हैं, बल्कि किसी अन्य कोण से एक समस्या पर आने के हित में ...।

क्या ये दो जावा प्रोसेस हैं जो एक ही एप्लिकेशन में एक ही फाइल को एक्सेस करना चाहते हैं? शायद आप केवल एकल, सिंक्रनाइज़ विधि (या, यहां तक ​​कि JSR-166 का उपयोग करके बेहतर ) के माध्यम से फ़ाइल तक सभी पहुंच को फ़िल्टर कर सकते हैं ? इस तरह, आप फ़ाइल तक पहुंच को नियंत्रित कर सकते हैं, और शायद यहां तक ​​कि एक्सेस अनुरोधों को भी कतारबद्ध कर सकते हैं।


3
दो प्रक्रियाएँ सिंक्रनाइज़ेशन का उपयोग नहीं कर सकती हैं, एक ही प्रक्रिया में केवल दो धागे।
लोर्ने

3

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


क्या आप विस्तार से समझा सकते हैं? मेरा मतलब है, रैंडम
असफल

नीचे पोस्ट किए गए सरल उदाहरण से लिंक करें
टूको

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

1

नीचे एक नमूना स्निपेट कोड है जो किसी फ़ाइल को तब तक लॉक करने के लिए है जब तक कि यह प्रक्रिया जेवीएम द्वारा न की जाए।

 public static void main(String[] args) throws InterruptedException {
    File file = new File(FILE_FULL_PATH_NAME);
    RandomAccessFile in = null;
    try {
        in = new RandomAccessFile(file, "rw");
        FileLock lock = in.getChannel().lock();
        try {

            while (in.read() != -1) {
                System.out.println(in.readLine());
            }
        } finally {
            lock.release();
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        try {
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

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