【问题标题】:Is it possible to convert a ByteArrayOutputStream to a InputStream?是否可以将 ByteArrayOutputStream 转换为 InputStream?
【发布时间】:2021-10-15 13:56:06
【问题描述】:

是否可以将 ByteArrayOutputStream 转换为 InputStream? URLConnection.guessContentTypeFromStream() 我需要它。

我需要这个,因为我确实想避免 new ByteArrayInputStream(baos.toByteArray()),它会生成 两个 数据的新副本。

我检查了PipedInputStream 的javadoc,它似乎只能从PipedOutputStream 创建。

我试过了

try (PipedOutputStream pos = new PipedOutputStream()) {
    pos.write(bytes);
    
    try (InputStream is = new PipedInputStream(pos)) {
        contentType = URLConnection.guessContentTypeFromStream(is);
    }
}
catch (IOException e) {
    throw new IOUncheckedException(e);
}

但它给了我

java.io.IOException: 管道未连接

是否有可能,也许将其转换为中间 PipedOutputStream,而不创建数据副本?

【问题讨论】:

  • 管道 I/O(额外线程!)应该为您提供一个位于 ByteArrayOutputStream 上的 InputStream。只是改编一个例子。否则,由于您只需要数据开头的字节,只需复制这些字节即可。
  • @JoopEggen Piped I/O (extra thread!) should give you an InputStream sitting on the ByteArrayOutputStream. Just adapt an example 如果我有一个例子,我没有问:D
  • 这与管道流无关。你的大线索是here:参数:是-支持标记的输入流。如果您要覆盖该方法,则可以使用 BufferedInputStream,标记它并在完成启发式方法后将其重置。
  • ByteArrayOutputStream 来自哪里?是否不可能用不同的OutputStream(例如管道末端)替换它数据写入它之前存在?为什么?
  • 那么,是否可以将OutputStream 的创建与写入它的代码分开?所以一个调用者仍然可以创建一个ByteArrayOutputStream 并将其传递给编写代码,而其他代码可以传递一个不同的OutputStream,例如PipedOutputStream。我看到删除的答案建议ByteArrayOutputStream 的子类,这确实暗示了更改创建站点的可能性。

标签: java type-conversion pipe java-7 bytearrayoutputstream


【解决方案1】:

当您有可能将ByteArrayOutputStream 替换为子类时,有效地回读实际上非常容易:

public class ReadableByteArrayOutputStream extends ByteArrayOutputStream {

    public ReadableByteArrayOutputStream() {
    }

    public ReadableByteArrayOutputStream(int size) {
        super(size);
    }

    public synchronized InputStream read() {
        return new ByteArrayInputStream(buf, 0, count);
    }

    @Override
    public synchronized void reset() {
        buf = new byte[buf.length];
        count = 0;
    }
}

虽然toArray() 会创建缓冲区的副本,但ByteArrayInputStream 的构造函数不会复制数据,而是存储数组引用。所以是最高效的数据读取方式,支持所有批量传输方式,以及mark/reset

例如

ReadableByteArrayOutputStream os = new ReadableByteArrayOutputStream();
OutputStreamWriter w = new OutputStreamWriter(os, "UTF-8");
w.write("just some text");
w.flush();

System.out.println(new Scanner(os.read()).next());

InputStream is = os.read();
is.mark(9);
byte[] b = new byte[9];
new DataInputStream(is).readFully(b);
System.out.println(new String(b, "UTF-8"));

is.reset();
System.out.println(new String(new DataInputStream(is).readAllBytes(), "UTF-8"));
just
just some
just some text

read() 返回的输入流代表了到目前为止写入的数据的快照,不受后续写入的影响。为了保证输入流保持一致,输出流的reset()方法已经被覆盖,所以这个输出流永远不会覆盖之前的数据。

【讨论】:

  • 非常巧妙!
【解决方案2】:

即使这不能回答问题,我还是使用mime-util 解决了我的问题:

public class MyMimeUtil {
    static {
        MimeUtil.registerMimeDetector(
            "eu.medsea.mimeutil.detector.MagicMimeMimeDetector"
        );
    }
    
    public static String getMime(byte[] bytes) {
        Collection<MimeType> mimeTypes = MimeUtil.getMimeTypes(bytes);
        MimeType mimeType = mimeTypes.iterator().next();
        String res = mimeType.toString();
        
        return res;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-13
    • 2013-11-11
    • 1970-01-01
    • 1970-01-01
    • 2013-07-09
    • 2018-11-21
    • 2010-09-28
    • 1970-01-01
    相关资源
    最近更新 更多