Неблокируемый файловый ввод-вывод в Java - PullRequest
7 голосов
/ 30 августа 2010

Я хочу записать в именованный канал (уже создан) без блокировки на считывателе.Мой читатель - еще одно приложение, которое может выйти из строя.Если читатель не работает, я хочу, чтобы приложение писателя продолжало писать в этот именованный канал.Что-то вроде этого в Java

fopen(fPath, O_NONBLOCK)

Так что, когда читатель подходит, он может возобновить работу с того места, где он вышел из строя.

Ответы [ 4 ]

8 голосов
/ 31 августа 2010

Сначала я попытаюсь ответить на ваши вопросы.Далее я попытаюсь показать вам фрагмент кода, который я создал, который решает вашу проблему, используя блокировку ввода-вывода.

Ваши вопросы

Я хочу написать в именованный канал (уже создан) безблокировка на считывателе

Вам не нужен неблокирующий ввод-вывод для решения вашей проблемы.Я думаю, что это не может даже помочь вам решить вашу проблему.Блокирующий ввод-вывод также будет работать хорошо (возможно, даже лучше, чем неблокирующий ввод-вывод из-за низкого уровня параллелизма).Плюсом является блокировка ввода-вывода, легче программировать.Ваш читатель может / должен оставаться заблокированным.

Мой читатель - еще одно приложение, которое может выйти из строя.Если читатель не работает, я хочу, чтобы приложение писателя записывало в именованный канал.Так что, когда читатель подходит, он может возобновить работу с того места, где он вышел из строя.

просто поместите сообщения в очередь блокировки.Далее пишите в именованный канал только , когда читатель читает с него (происходит автоматически из-за блокировки ввода-вывода).Нет необходимости в неблокирующем вводе-выводе файла при использовании очереди блокировки.Данные асинхронно доставляются из очереди блокировки, когда читатель читает, что отправит ваши данные от вашего писателя читателю.

Что-то вроде fopen (fPath, O_NONBLOCK) в Java

Вам не нужен неблокирующий ввод-вывод для считывателя, даже если вы его использовали.просто используйте блокировку ввода-вывода.

КОД SNIPPET

A создал небольшой фрагмент, который, я считаю, демонстрирует ваши потребности.

Компоненты:

  • 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.Ява

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;
            }
        }
    }
}
2 голосов
/ 30 августа 2010

Если вы хотите, чтобы каналы оставались активными и помещали в очередь сообщения, вам, вероятно, нужна система обмена сообщениями, а не необработанный канал.В Java стандартный API называется «Java Messaging System» ( JMS ), и существует множество стандартных реализаций, наиболее распространенной из которых я видел Apache ActiveMQ .Если вам нужен кроссплатформенный сокет-подобный интерфейс, который выполняет буферизацию и восстановление, я мог бы предложить 0MQ , который, хотя и не является «чистой Java», имеет привязки для многих языков и отличную производительность.

1 голос
/ 31 августа 2010

Если бы в Java была такая вещь, как неблокируемый файловый ввод / вывод, которого нет, запись в именованный канал, который не читался, вернула бы ноль и ничего не записывала.Поэтому неблокирование не является частью решения.

Существует также проблема, заключающаяся в том, что именованные каналы имеют конечный размер буфера.Это не бесконечные очереди, независимо от того, идет процесс чтения или нет.Я согласен с предложением заглянуть в JMS.

0 голосов
/ 10 января 2017

Вы должны быть в состоянии использовать асинхронность NIO write в FIFO UNIX, как и в любом другом файле:

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

... или ...

 channel.write(..., myCompletionHandler);

Однако мне неясно, что вы хотите, чтобы FIFO не принимал записи. Вы хотите, чтобы это буферизовало? Если это так, вам нужно предоставить это в программе Java. Вы хотите, чтобы время вышло? При записи в файл Java не существует простого тайм-аута.

Это не непреодолимые проблемы. Если вы полны решимости, вы, вероятно, можете заставить что-то работать. Но мне интересно, разве вы не нашли бы жизнь намного проще, если бы просто использовали сокет TCP или очередь JMS.

...