簡體   English   中英

Java中的非阻塞文件IO

[英]Non-Blocking File IO in Java

我想寫一個命名管道(已經創建)而不會阻塞讀取器。 我的讀者是另一個可能會失敗的應用程序。 如果讀者確實失敗了,我希望編寫器應用程序繼續寫入該命名管道。 像Java這樣的東西

fopen(fPath, O_NONBLOCK)

因此,當讀者出現時,它可能會從失敗的地方恢復。

首先,我試着回答你的問題。 接下來,我將嘗試向您展示我創建的代碼片段,它使用阻止IO來解決您的問題。

你的問題

我想寫一個命名管道(已經創建)而不會阻塞讀取器

您不需要非阻塞IO來解決您的問題。 我認為它甚至無法幫助您解決問題。 阻止IO也將運行良好(可能甚至比非阻塞IO更好,因為並發性低)。 加號阻止IO更容易編程。 您的讀者可以/應該保持阻止。

我的讀者是另一個可能會失敗的應用程序。 如果讀者確實失敗了,我希望編寫器應用程序能夠寫入命名管道。 因此,當讀者出現時,它可能會從失敗的地方恢復。

只是將消息放入阻塞隊列中。 接下來只有當讀者從中讀取時才寫入命名管道(由於阻塞IO而自動發生)。 使用阻塞隊列時不需要非阻塞文件IO。 當讀者正在閱讀時,數據是從阻塞隊列異步傳遞的,這會將您的數據從您的編寫器發送到閱讀器。

類似於Java中的fopen(fPath,O_NONBLOCK)

您在閱讀器上不需要非阻塞IO,即使您使用它也是如此。 只使用阻塞IO。

代碼鏈

創建了一個小片段,我相信它可以展示您的需求。

組件:

  • Writer.java :從控制台讀取行作為示例。 當您啟動程序時,輸入文本,然后輸入,將其發送到您的命名管道。 如有必要,作者將繼續寫作。
  • Reader.java :讀取從命名管道(Writer.java)寫入的行。
  • 命名管道 :我假設您在同一目錄中創建了一個名為“pipe”的管道。

Writer.java

import java.io.BufferedWriter;
import java.io.Console;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Writer {
    private final BlockingDeque<StringBuffer> queue;
    private final String filename;

    public static void main(String[] args) throws Exception {
        final Console console = System.console();
        final Writer writer = new Writer("pipe");

        writer.init();

        while(true) {
            String readLine = console.readLine();
            writer.write(new StringBuffer(readLine));
        }
    }

    public Writer(final String filename){
        this.queue = new LinkedBlockingDeque<StringBuffer>();
        this.filename = filename;
    }

    public void write(StringBuffer buf) {
        queue.add(buf);
    }

    public void init() {
        ExecutorService single = Executors.newSingleThreadExecutor();

        Runnable runnable = new Runnable() {
            public void run() {
                while(true) {
                    PrintWriter w = null;
                    try {
                        String toString = queue.take().toString();
                        w = new PrintWriter(new BufferedWriter(new FileWriter(filename)), true);
                        w.println(toString);
                    } catch (Exception ex) {
                        Logger.getLogger(Writer.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        };

        single.submit(runnable);
    }
}

Reader.java

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Reader {
    private final BufferedReader br;

    public Reader(final String filename) throws FileNotFoundException {
        br = new BufferedReader(new FileReader(filename));
    }

    public String readLine() throws IOException {
        return br.readLine();
    }

    public void close() {
        try {
            br.close();
        } catch (IOException ex) {
            Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static void main(String[] args) throws FileNotFoundException {
        Reader reader = new Reader("pipe");
        while(true) {
            try {
                String readLine = reader.readLine();
                System.out.println("readLine = " + readLine);
            } catch (IOException ex) {
                reader.close();
                break;
            }
        }
    }
}

如果您希望管道保持活動狀態並排隊消息,則可能需要消息傳遞系統而不是原始管道。 在Java中,標准API被稱為“Java消息系統”( JMS ),並且有許多標准實現 - 我最常見的是Apache ActiveMQ 如果你想要一個跨平台,類似套接字的接口進行緩沖和恢復,我可能會建議0MQ ,雖然不是“純Java”,但它具有許多語言的綁定和出色的性能。

如果Java中存在非阻塞文件I / O這樣的事情,那么對未被讀取的命名管道的寫入將返回零並且不寫入任何內容。 因此,非阻塞不是解決方案的一部分。

還存在命名管道具有有限緩沖區大小的問題。 無論是否有閱讀過程,它們都不是無限的隊列。 我同意調查JMS的建議。

您應該能夠在UNIX FIFO上使用NIO的異步write ,就像對任何其他文件一樣:

 AsynchronousFileChannel channel = AsynchronousFileChannel.open(...);
 Future<Integer> writeFuture = channel.write(...);

... 要么...

 channel.write(..., myCompletionHandler);

但是,當FIFO不接受寫入時,我不清楚你想要發生什么。 你想要緩沖嗎? 如果是這樣,您將需要在Java程序中提供它。 你想讓它超時嗎? Java文件寫入沒有簡單的超時選項。

這些都不是不可克服的問題。 如果你確定你可能會得到一些有用的東西。 但我想知道如果你只是使用TCP套接字或JMS隊列,你是否會發現生活更輕松。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM