Java 中的非阻塞文件 IO

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3601586/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 02:36:17  来源:igfitidea点击:

Non-Blocking File IO in Java

javanionamed-pipesnonblocking

提问by Gautam

I want to write to a named pipe (already created) without blocking on the reader. My reader is another application that may go down. If the reader does go down, I want the writer application to keep writing to that named pipe. Something like a this in Java

我想在不阻塞读取器的情况下写入命名管道(已创建)。我的阅读器是另一个可能会出现故障的应用程序。如果读取器确实出现故障,我希望写入器应用程序继续写入该命名管道。Java中的类似这样的东西

fopen(fPath, O_NONBLOCK)

So that when the reader comes up, it may resume from where it failed.

这样当阅读器出现时,它可以从失败的地方恢复。

回答by Alfred

First I try to answer your questions. Next I will try to show you a code snippet I created that solves your problem using blocking IO.

首先我试着回答你的问题。接下来,我将尝试向您展示我创建的代码片段,该代码片段使用阻塞 IO 解决了您的问题。

Your questions

你的问题

I want to write to a named pipe (already created) without blocking on the reader

我想在不阻塞阅读器的情况下写入命名管道(已创建)

You don't need non blocking IO to solve your problem. I think it can not even help you solve your problem. Blocking IO will also run good(maybe even better then non blocking IO because of the low concurrency). A plus is blocking IO is easier to program. Your reader can/should stay blocking.

您不需要非阻塞 IO 来解决您的问题。我认为它甚至不能帮助你解决你的问题。阻塞 IO 也将运行良好(由于低并发性,可能比非阻塞 IO 更好)。一个优点是阻塞 IO 更容易编程。你的读者可以/应该保持阻塞。

My reader is another application that may go down. If the reader does go down, I want the writer application to neep writing to the named pipe. So that when the reader comes up, it may resume from where it failed.

我的阅读器是另一个可能会出现故障的应用程序。如果阅读器确实失败了,我希望编写器应用程序不需要写入命名管道。这样当阅读器出现时,它可以从失败的地方恢复。

just put the messages inside a blocking queue. Next write to the named pipe onlywhen the reader is reading from it(happens automatically because of blocking IO). No need for non-blocking file IO when you use a blocking queue. The data is asynchronous delivered from the blocking queue when a reader is reading, which will sent your data from your writer to the reader.

只需将消息放入阻塞队列即可。当读取器正在读取时才写入命名管道(由于阻塞 IO 自动发生)。使用阻塞队列时不需要非阻塞文件 IO。当读取器正在读取时,数据从阻塞队列异步传递,这会将您的数据从您的写入器发送到读取器。

Something like a fopen(fPath, O_NONBLOCK) in Java

类似于 Java 中的 fopen(fPath, O_NONBLOCK)

You don't need non-blocking IO on the reader and even if you used it. just use blocking IO.

即使您使用了它,您也不需要读取器上的非阻塞 IO。只需使用阻塞 IO。

CODE SNIPPET

代码片段

A created a little snippet which I believe demonstrates what your needs.

创建了一个小片段,我相信它展示了您的需求。

Components:

组件:

  • Writer.java: reads lines from console as an example. When you start program enter text followed by enter which will sent it to your named pipe. The writer will resume writing if necessary.
  • Reader.java: reads lines written from your named pipe(Writer.java).
  • Named pipe: I assume you have created a pipe named "pipe" in the same directory.
  • Writer.java:以从控制台读取行为例。当您启动程序时输入文本,然后输入将其发送到您的命名管道。如有必要,作者将继续写作。
  • Reader.java:读取从命名管道(Writer.java)写入的行。
  • 命名管道:我假设您已经在同一目录中创建了一个名为“pipe”的管道。

Writer.java

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

阅读器.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;
            }
        }
    }
}

回答by samkass

If you want pipes to stay active and queue up messages, you probably want a messaging system rather than a raw pipe. In Java, the standard API is called "Java Messaging System" (JMS), and there are many standard implementations-- the most common of which I've seen being Apache ActiveMQ. If you want a cross-platform, sockets-like interface that does buffering and recovery I might suggest 0MQ, which while not being "pure Java" has bindings for many languages and excellent performance.

如果您希望管道保持活动状态并将消息排队,您可能需要消息传递系统而不是原始管道。在 Java 中,标准 API 被称为“Java 消息系统”( JMS),并且有许多标准实现——我见过的最常见的是 Apache ActiveMQ。如果您想要一个跨平台的、类似套接字的接口来进行缓冲和恢复,我可能会建议0MQ,它虽然不是“纯 Java”,但具有多种语言的绑定和出色的性能。

回答by user207421

If there was such a thing as non-blocking file I/O in Java, which there isn't, a write to a named pipe that wasn't being read would return zero and not write anything. So non-blocking isn't part of the solution.

如果在 Java 中有非阻塞文件 I/O 之类的东西,而没有,那么写入未被读取的命名管道将返回零并且不写入任何内容。所以非阻塞不是解决方案的一部分。

There's also the issue that named pipes have a finite buffer size. They aren't infinite queues regardless of whether there is a reading process or not. I agree with the suggestion to look into JMS.

还有一个问题是命名管道的缓冲区大小有限。无论是否有读取过程,它们都不是无限队列。我同意研究 JMS 的建议。

回答by slim

You should be able to use NIO's asynch writeon a UNIX FIFO, just as you can to any other file:

您应该能够write在 UNIX FIFO 上使用 NIO 的异步,就像您可以使用任何其他文件一样:

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

... or...

... 或者...

 channel.write(..., myCompletionHandler);

However, it's not clear to me what you want to happen when the FIFO isn't accepting writes. Do you want it to buffer? If so you'll need to provide it within the Java program. Do you want it to time out? There's no simple timeout option on Java file writes.

但是,我不清楚当 FIFO 不接受写入时您希望发生什么。你想让它缓冲吗?如果是这样,您需要在 Java 程序中提供它。你想让它超时吗?Java 文件写入没有简单的超时选项。

These aren't insurmountable problems. If you're determined you can probably get something working. But I wonder whether you'd not find life much easier if you just used a TCP socket or a JMS queue.

这些都不是无法克服的问题。如果您下定决心,您可能会有所作为。但是我想知道如果您只使用 TCP 套接字或 JMS 队列,您是否会发现生活更轻松。