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

用于双向I/O的Java数据对象,java,io,Java,Io,我正在开发一个接口,它将加密字节流(可能是非常大的字节流)作为输入,生成大致相同格式的输出 输入格式如下: {N byte envelope} - encryption key IDs &c. {X byte encrypted body} 输出格式相同 下面是常见的用例(当然,大量的伪代码): 对我来说,使用同一个对象来封装这种行为似乎是有道理的,但我有点不知所措,不知道该怎么做。一次装入所有加密体是不实际的;我需要能够对其进行流式处理(因此,我将使用某种输入流过滤器对其进行

我正在开发一个接口,它将加密字节流(可能是非常大的字节流)作为输入,生成大致相同格式的输出

输入格式如下:

{N byte envelope}
    - encryption key IDs &c.
{X byte encrypted body}
输出格式相同

下面是常见的用例(当然,大量的伪代码):


对我来说,使用同一个对象来封装这种行为似乎是有道理的,但我有点不知所措,不知道该怎么做。一次装入所有加密体是不实际的;我需要能够对其进行流式处理(因此,我将使用某种输入流过滤器对其进行解密),但同时我需要能够写出此对象的新实例。有什么好方法可以让这一切顺利进行?
Message
内部应该是什么样子?

你能在任意位置分割尸体吗

如果是这样,我将有两个线程,输入线程和输出线程,并且有一个由输出线程监视的并发字符串队列。比如:

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);
    }
}
ConcurrentLinkedQueue outputQueue=新建ConcurrentLinkedQueue();
...
私有void readInput(流){
字符串str;
而((str=stream.readLine())!=null){
put(processStream(str));
}
}
私有字符串processStream(字符串输入){
//做点什么
返回输出;
}
私有void writeOutput(流式输出){
while(true){
while(outputQueue.peek()==null){
睡眠(100);
}
字符串msg=outputQueue.poll();
out.write(msg);
}
}

注意:这绝对不会按原样工作。只是一个设计建议。欢迎有人来编辑这个

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

如果您想用java制作流式API,通常应该提供InputStream用于读取,OutputStream用于写入。通过这种方式,可以将这些数据传递给其他API,这样您就可以链接这些数据,从而使这些数据流一直作为数据流运行

输入示例:

Message message = new Message(inputStream);
results = process(message.getInputStream());
Message message = new Message(outputStream);
writeContent(message.getOutputStream());
输出示例:

Message message = new Message(inputStream);
results = process(message.getInputStream());
Message message = new Message(outputStream);
writeContent(message.getOutputStream());
消息需要用一个类包装给定的流,该类执行所需的加密和解密

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

您应该检查支持流加密的不同分组密码模式。不同的加密算法可能支持其中的一个子集

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


演示ZipInputStream和ZipOutStream的示例可以为您解决此问题提供一些指导。看

您需要的是使用密码流()。这里是一个如何使用它的示例。

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

InputStream decrypted = new DecryptingStream(inputStream, decryptionParameters);
...
OutputStream encrypted = new EncryptingStream(outputSream, encryptionOptions);
它们可能有类似于惰性初始化机制的功能,在第一次
read()
call/在第一次
write()调用之前读取信封。在过滤器实现中还可以使用Message或MessageEnvelope之类的类,但它们可以保持包保护的非API类

处理将不知道仅在流上进行反/加密。在处理流式处理输入和输出的过程中,您也可以同时使用两个流进行输入和输出。

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

以下是我对结构的想法,稍微改变一下架构,将消息类移到加密流之外:

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输出;//这是用于发送消息的流 消息输入消息=新消息(输入); Message outputMessage=新消息(inputMessage.getEnvelope()); 进程(inputMessage.read(),outputMessage.write(output))

现在,process方法只需要根据需要从输入中读取数据块,然后将结果写入输出:

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.
  }
}

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

正文将是XML,但我认为这在这里并不重要。传入消息从不写入,传出消息从不读取,但在其他方面它们是相同的。不必有多个线程来支持“同时”读取和写入。在这种情况下,如果不提供任何真正的好处,引入线程将使它变得更加困难。你不应该像这样弄脏你的逻辑。删除构造函数并将创建信封的责任交给用户。现在,如果用户使用构造函数1,则需要在调用getOutputStream()之前调用getEnvelope()。我希望你们明白为什么这是一个糟糕的设计。我已经稍微调整了我的答案,wds。我认为用户不应该自己阅读信封——如果他们将流传递给错误的读者,就会导致混乱。我认为这一切都应该是内部消息。用户不需要知道将内容写入流的协议。