用于双向I / O的Java数据对象

时间:2008-12-12 13:34:28

标签: java io

我正在开发一个接口,它将加密的字节流作为输入 - 可能是一个非常大的 - 产生或多或少相同格式的输出。

输入格式为:

{N byte envelope}
    - encryption key IDs &c.
{X byte encrypted body}

输出格式相同。

这是通常的用例(当然是高度伪编码):

Message incomingMessage = new Message (inputStream);

ProcessingResults results = process (incomingMessage);

MessageEnvelope messageEnvelope = new MessageEnvelope ();
// set message encryption options &c. ...

Message outgoingMessage = new Message ();
outgoingMessage.setEnvelope (messageEnvelope);

writeProcessingResults (results, message);

message.writeToOutput (outputStream);

对我而言,使用相同的对象来封装这种行为似乎是有意义的,但我对于如何解决这个问题感到有点失落。一次加载所有加密的主体是不切实际的;我需要能够流式传输它(所以,我将使用某种输入流过滤器来解密它)但同时我需要能够写出这个对象的新实例。做这项工作的好方法是什么? Message内部应该是什么样的?

6 个答案:

答案 0 :(得分:1)

我不会创建一个类来处理输入和输出 - 一个类,一个责任。我想要两个过滤器流,一个用于输入/解密,另一个用于输出/加密:

InputStream decrypted = new DecryptingStream(inputStream, decryptionParameters);
...
OutputStream encrypted = new EncryptingStream(outputSream, encryptionOptions);

在第一次read()调用之前,{@ 1}}首先write()调用/写入信封之前,他们可能会使用惰性初始化机制来读取信封。您还可以在过滤器实现中使用Message或MessageEnvelope等类,但它们可能保留受包受保护的非API类。

处理对于仅在流上工作的解密/加密一无所知。在处理流处理输入和输出的过程中,您也可以同时使用两个流进行输入和输出。

答案 1 :(得分:0)

你可以在任意位置拆分身体吗?

如果是这样,我将有两个线程,输入线程和输出线程,并具有输出线程监视的并发队列的字符串。类似的东西:

ConcurrentLinkedQueue<String> outputQueue = new ConcurrentLinkedQueue<String>();
...

private void readInput(Stream stream) {
    String str;
    while ((str = stream.readLine()) != null) {
       outputQueue.put(processStream(str));
    }
}

private String processStream(String input) {
    // do something
    return output;
}

private void writeOutput(Stream out) {
    while (true) {
        while (outputQueue.peek() == null) {
            sleep(100);
        }

        String msg = outputQueue.poll();
        out.write(msg);
    }
}

注意:这肯定不会按原样运作。只是一个设计的建议。欢迎有人编辑此内容。

答案 2 :(得分:0)

如果需要同时读写,则必须使用线程(不同的线程读写)或异步I / O(java.nio包)。使用来自不同线程的输入和输出流不是问题。

如果你想在java中创建一个流API,你通常应该提供InputStream用于读取和OutputStream用于写入。通过这种方式,可以将这些API传递给其他API,以便您可以将事物链接起来,从而使流一直作为流。

输入示例:

Message message = new Message(inputStream);
results = process(message.getInputStream());

输出示例:

Message message = new Message(outputStream);
writeContent(message.getOutputStream());

消息需要使用执行所需加密和解密的类来包装给定的流。

请注意,同时读取多条消息或同时写入多条消息也需要协议支持。您需要使同步正确。

答案 3 :(得分:0)

您应该在支持流加密的不同分组密码模式下检查Wikipedia article。不同的加密算法可能支持这些算法的子集。

缓冲流将允许您在循环中读取,加密/解密和写入。

演示ZipInputStream和ZipOutputStream的示例可以提供有关如何解决此问题的一些指导。见example

答案 4 :(得分:0)

您需要的是使用密码流(CipherInputStream)。以下是example如何使用它。

答案 5 :(得分:0)

我同意Arne,数据处理器不应该知道加密,它只需要读取消息的解密主体,并写出结果,流过滤器应该负责加密。但是,由于这在逻辑上对同一条信息(消息)进行操作,我认为打包在一个处理消息格式的类中,尽管加密/解密流确实独立于此

这是我对结构的想法,在某种程度上翻转架构,并将Message类移到加密流之外:

class Message {
  InputStream input;
  Envelope envelope;

  public Message(InputStream input) {
    assert input != null;
    this.input = input;
  }

  public Message(Envelope envelope) {
    assert envelope != null;
    this.envelope = envelope;
  }

  public Envelope getEnvelope() {
    if (envelope == null && input != null) {
      // Read envelope from beginning of stream
      envelope = new Envelope(input);
    }
    return envelope
  }

  public InputStream read() {
    assert input != null

    // Initialise the decryption stream
    return new DecryptingStream(input, getEnvelope().getEncryptionParameters());
  }

  public OutputStream write(OutputStream output) {
    // Write envelope header to output stream
    getEnvelope().write(output);

    // Initialise the encryption
    return new EncryptingStream(output, getEnvelope().getEncryptionParameters());
  }
}

现在您可以通过为输入创建新消息来使用它,并为输出创建一个消息:     OutputStream输出; //这是发送消息的流     消息inputMessage = new消息(输入);     消息outputMessage = new Message(inputMessage.getEnvelope());     process(inputMessage.read(),outputMessage.write(output));

现在,进程方法只需要根据输入需要读取数据块,并将结果写入输出:

public void process(InputStream input, OutputStream output) {
  byte[] buffer = new byte[1024];
  int read;
  while ((read = input.read(buffer) > 0) {
    // Process buffer, writing to output as you go.
  }
}

这一切现在都是锁步,你不需要任何额外的线程。您也可以提前中止而无需处理整个消息(例如,如果输出流已关闭)。