सक्रिय रूप से लिखी जा रही फ़ाइल से पढ़ने के लिए मैं जावा का उपयोग कैसे करूं?


99

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

मुझे लगता है कि ऐसा करना संभव है, लेकिन जावा का उपयोग करते समय गेटा क्या शामिल है? यदि रीडिंग लेखन को पकड़ लेती है, तो क्या यह फ़ाइल बंद होने तक अधिक लिखने का इंतजार करेगा, या रीड इस बिंदु पर एक अपवाद को फेंक देगा? यदि बाद में, मैं तब क्या करूँ?

मेरा अंतर्ज्ञान वर्तमान में मुझे बफर्डस्ट्रीम की ओर धकेल रहा है। क्या यह रास्ता है?


1
हे, जैसा कि मैं एक समान परिदृश्य का सामना कर रहा हूं, अगर आप स्वीकार किए गए एक से बेहतर समाधान पा चुके हैं तो मैं क्या कर रहा था?
आसफ डेविड

मुझे पता है कि यह एक पुराना प्रश्न है, लेकिन भविष्य के पाठकों के लिए, क्या आप अपने उपयोग के मामले में थोड़ा और विस्तार कर सकते हैं? अधिक जानकारी के बिना, यदि आप शायद गलत समस्या को हल कर रहे हैं, तो एक आश्चर्य होता है।
user359996

Apache Commons IO से टेलर का उपयोग करते हुए देखें । यह ज्यादातर किनारे के मामलों को संभालता है।
जोशुआ

2
डेटाबेस का उपयोग करें। ये 'एक फ़ाइल पढ़ते हैं, जबकि इसके लिखे जाने' परिदृश्य आँसू में समाप्त होते हैं।
लोर्ने की मार्की

@ ईजेपी - आप किस डीबी की सिफारिश करते हैं? मुझे लगता है कि MySQL एक अच्छी शुरुआत है?
कॉफी

जवाबों:


39

FileChannel.read(ByteBuffer)इसका उपयोग करके काम करने के लिए उदाहरण नहीं मिल सका क्योंकि यह एक अवरुद्ध रीड नहीं है। हालांकि काम करने के लिए नीचे दिया गया कोड मिला:

boolean running = true;
BufferedInputStream reader = new BufferedInputStream(new FileInputStream( "out.txt" ) );

public void run() {
    while( running ) {
        if( reader.available() > 0 ) {
            System.out.print( (char)reader.read() );
        }
        else {
            try {
                sleep( 500 );
            }
            catch( InterruptedException ex ) {
                running = false;
            }
        }
    }
}

बेशक एक ही चीज एक धागे के बजाय टाइमर के रूप में काम करेगी, लेकिन मैं इसे प्रोग्रामर तक छोड़ देता हूं। मैं अभी भी बेहतर तरीके की तलाश कर रहा हूं, लेकिन यह मेरे लिए अभी काम करता है।

ओह, और मैं इस के साथ चेतावनी दूंगा: मैं 1.4.2 का उपयोग कर रहा हूं। हाँ मुझे पता है कि मैं अभी भी पाषाण युग में हूँ।


1
इसे जोड़ने के लिए धन्यवाद ... मुझे ऐसा करने के लिए कभी कुछ नहीं मिला। मुझे लगता है कि फ़ाइल लॉक करने का ब्लेड का जवाब भी एक अच्छा है। हालांकि, इसके लिए जावा 6 (मुझे लगता है) की आवश्यकता है।
एंथनी क्रैम्प

@JosephGordon - आपको इन दिनों में से एक ड्रोन युग में जाना होगा ;-)
TungstenX

12

यदि आप एक फ़ाइल को पढ़ना चाहते हैं, जबकि वह लिखी जा रही है और केवल नई सामग्री को पढ़ना है, तो निम्नलिखित आपको उसी को प्राप्त करने में मदद करेगा।

इस प्रोग्राम को चलाने के लिए आप इसे कमांड प्रॉम्प्ट / टर्मिनल विंडो से लॉन्च करेंगे और पढ़ने के लिए फाइल का नाम पास करेंगे। यह फ़ाइल को तब तक पढ़ेगा जब तक आप प्रोग्राम को नहीं मारते।

java FileReader c: \ myfile.txt

जैसे ही आप पाठ की एक पंक्ति टाइप करते हैं, उसे नोटपैड से बचाते हैं और आप पाठ को कंसोल में प्रिंट होते देखेंगे।

public class FileReader {

    public static void main(String args[]) throws Exception {
        if(args.length>0){
            File file = new File(args[0]);
            System.out.println(file.getAbsolutePath());
            if(file.exists() && file.canRead()){
                long fileLength = file.length();
                readFile(file,0L);
                while(true){

                    if(fileLength<file.length()){
                        readFile(file,fileLength);
                        fileLength=file.length();
                    }
                }
            }
        }else{
            System.out.println("no file to read");
        }
    }

    public static void readFile(File file,Long fileLength) throws IOException {
        String line = null;

        BufferedReader in = new BufferedReader(new java.io.FileReader(file));
        in.skip(fileLength);
        while((line = in.readLine()) != null)
        {
            System.out.println(line);
        }
        in.close();
    }
}

2
क्या इस बात की संभावना नहीं है कि फ़ाइल को पढ़ने के समय और फ़ाइल की लंबाई के बीच के समय के बीच, बाहरी प्रक्रिया फ़ाइल में अधिक डेटा जोड़ सकती है। यदि ऐसा है, तो इसका परिणाम फ़ाइल में लिखी गई रीडिंग मिसिंग डेटा गुम हो जाएगा।
JohnC

1
यह कोड सीपीयू की बहुत खपत करता है क्योंकि लूप में थ्रेड नहीं होता है। थोड़ी मात्रा में देरी के बिना यह कोड सीपीयू को बहुत व्यस्त रखता है।
ChaitanyaBhatt

उपरोक्त दोनों टिप्पणियाँ सही हैं और इसके अतिरिक्त BufferedReaderप्रत्येक लूप कॉल में यह निर्माण इतना व्यर्थ है। इसके बनने के बाद एक बार स्किप करना आवश्यक नहीं होगा, क्योंकि बफ़र किए गए पाठक आने के साथ ही नई लाइनें पढ़ेंगे।
पियोट्र

5

आप किसी फ़ाइल के एक भाग को लॉक करने के लिए जावा चैनल पर भी नज़र डाल सकते हैं।

http://java.sun.com/javase/6/docs/api/java/nio/channels/FileChannel.html

यह कार्य FileChannelएक शुरुआत हो सकती है

lock(long position, long size, boolean shared) 

इस पद्धति का एक आमंत्रण तब तक अवरुद्ध होगा जब तक कि क्षेत्र लॉक नहीं किया जा सकता है


5

मैं जोशुआ की प्रतिक्रिया से पूरी तरह सहमत हूं , टेलर इस स्थिति में नौकरी के लिए फिट है। यहाँ एक उदाहरण है :

यह एक फ़ाइल में प्रत्येक 150 एमएस में एक पंक्ति लिखता है, जबकि हर 2500 एमएस में एक ही फ़ाइल को पढ़ता है

public class TailerTest
{
    public static void main(String[] args)
    {
        File f = new File("/tmp/test.txt");
        MyListener listener = new MyListener();
        Tailer.create(f, listener, 2500);

        try
        {
            FileOutputStream fos = new FileOutputStream(f);
            int i = 0;
            while (i < 200)
            {
                fos.write(("test" + ++i + "\n").getBytes());
                Thread.sleep(150);
            }
            fos.close();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    private static class MyListener extends TailerListenerAdapter
    {
        @Override
        public void handle(String line)
        {
            System.out.println(line);
        }
    }
}

टेलर से आपका लिंक टूट गया है।
चुपके रब्बी

2
@StealthRabbi सबसे अच्छी बात यह है कि सही लिंक की खोज करें, और इसके साथ उत्तर को संपादित करें।
.ग्रेसिया

3

जवाब "नहीं" ... और "हां" लगता है। ऐसा लगता है कि कोई फ़ाइल किसी अन्य एप्लिकेशन द्वारा लिखने के लिए खुली है या नहीं यह जानने का कोई वास्तविक तरीका नहीं है। इसलिए, इस तरह की फ़ाइल से पढ़ना तब तक प्रगति करेगा जब तक कि सामग्री समाप्त न हो जाए। मैंने माइक की सलाह ली और कुछ टेस्ट कोड लिखे:

Writer.java फाइल करने के लिए एक स्ट्रिंग लिखता है और फिर फाइल के लिए एक और लाइन लिखने से पहले उपयोगकर्ता के हिट होने का इंतजार करता है। यह विचार किया जा रहा है कि इसे शुरू किया जा सकता है, फिर एक पाठक को यह देखने के लिए शुरू किया जा सकता है कि यह "आंशिक" फ़ाइल के साथ कैसे मेल खाता है। मैंने जो पाठक लिखा है, वह Reader.java में है।

Writer.java

public class Writer extends Object
{
    Writer () {

    }

    public static String[] strings = 
        {
            "Hello World", 
            "Goodbye World"
        };

    public static void main(String[] args) 
        throws java.io.IOException {

        java.io.PrintWriter pw =
            new java.io.PrintWriter(new java.io.FileOutputStream("out.txt"), true);

        for(String s : strings) {
            pw.println(s);
            System.in.read();
        }

        pw.close();
    }
}

Reader.java

public class Reader extends Object
{
    Reader () {

    }

    public static void main(String[] args) 
        throws Exception {

        java.io.FileInputStream in = new java.io.FileInputStream("out.txt");

        java.nio.channels.FileChannel fc = in.getChannel();
        java.nio.ByteBuffer bb = java.nio.ByteBuffer.allocate(10);

        while(fc.read(bb) >= 0) {
            bb.flip();
            while(bb.hasRemaining()) {
                System.out.println((char)bb.get());
            }
            bb.clear();
        }

        System.exit(0);
    }
}

कोई गारंटी नहीं है कि यह कोड सबसे अच्छा अभ्यास है।

यह समय-समय पर जाँच के माइक द्वारा सुझाए गए विकल्प को छोड़ देता है यदि फ़ाइल से पढ़ा जाने वाला नया डेटा है। इसके बाद फ़ाइल रीडर को बंद करने के लिए उपयोगकर्ता के हस्तक्षेप की आवश्यकता होती है जब यह निर्धारित होता है कि रीडिंग पूरी हो गई है। या, पाठक को फ़ाइल की सामग्री से अवगत कराना होगा और लिखने की स्थिति का निर्धारण और अंत करने में सक्षम होना चाहिए। यदि सामग्री XML थी, तो दस्तावेज़ के अंत का उपयोग यह संकेत देने के लिए किया जा सकता है।


1

जावा प्रति-से नहीं, लेकिन आप उन मुद्दों पर चल सकते हैं, जहाँ आपने किसी फ़ाइल में कुछ लिखा है, लेकिन यह वास्तव में अभी तक नहीं लिखा गया है - यह कहीं कैश में हो सकता है, और उसी फ़ाइल से पढ़ना वास्तव में आपको नहीं दे सकता है नई जानकारी।

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

नोट मैं ओएस स्तर के डिस्क कैश के बारे में बात नहीं कर रहा हूं - यदि आपका डेटा यहां हो जाता है, तो यह इस बिंदु के बाद एक रीड () में दिखाई देना चाहिए। यह हो सकता है कि भाषा स्वयं कैश लिखती है, जब तक कि एक बफर भर जाता है या फ़ाइल को फ्लश / बंद किया जाता है तब तक प्रतीक्षा करता है।


1

ऐसा करने वाला एक ओपन सोर्स जावा ग्राफिक टेल है।

https://stackoverflow.com/a/559146/1255493

public void run() {
    try {
        while (_running) {
            Thread.sleep(_updateInterval);
            long len = _file.length();
            if (len < _filePointer) {
                // Log must have been jibbled or deleted.
                this.appendMessage("Log file was reset. Restarting logging from start of file.");
                _filePointer = len;
            }
            else if (len > _filePointer) {
                // File must have had something added to it!
                RandomAccessFile raf = new RandomAccessFile(_file, "r");
                raf.seek(_filePointer);
                String line = null;
                while ((line = raf.readLine()) != null) {
                    this.appendLine(line);
                }
                _filePointer = raf.getFilePointer();
                raf.close();
            }
        }
    }
    catch (Exception e) {
        this.appendMessage("Fatal error reading log file, log tailing has stopped.");
    }
    // dispose();
}

1

आप एक फ़ाइल नहीं पढ़ सकते हैं जो किसी अन्य प्रक्रिया से FileInputStream, FileReader या RandomAccessFile का उपयोग करके खोली गई है।

लेकिन सीधे FileChannel का उपयोग कर काम करेंगे:

private static byte[] readSharedFile(File file) throws IOException {
    byte buffer[] = new byte[(int) file.length()];
    final FileChannel fc = FileChannel.open(file.toPath(), EnumSet.of(StandardOpenOption.READ));
    final ByteBuffer dst = ByteBuffer.wrap(buffer);
    fc.read(dst);
    fc.close();
    return buffer;
}

0

मैंने कभी इसकी कोशिश नहीं की है, लेकिन आपको यह देखने के लिए एक परीक्षण मामला लिखना चाहिए कि क्या आप एक स्ट्रीम से पढ़ रहे हैं, जिसके बाद आप अंत में काम करेंगे, भले ही फ़ाइल में अधिक डेटा लिखा हो।

क्या कोई कारण है कि आप एक पाइप्ड इनपुट / आउटपुट स्ट्रीम का उपयोग नहीं कर सकते हैं? क्या डेटा को उसी एप्लिकेशन से लिखा और पढ़ा जा रहा है (यदि हां, तो आपके पास डेटा है, आपको फ़ाइल से पढ़ने की आवश्यकता क्यों है)?

अन्यथा, शायद फ़ाइल के अंत तक पढ़ा जाता है, तो परिवर्तनों की निगरानी करें और जहां आप छोड़ दिया और जारी रखना चाहते हैं ... हालांकि दौड़ की स्थिति के लिए देखें।

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