如何将 InputStream 转换为 DataHandler?

问题描述 投票:0回答:8

我正在开发一个 Java Web 应用程序,其中的文件将存储在数据库中。最初,我们通过简单地在我们的结果集上调用

getBytes
来检索已经在数据库中的文件:

byte[] bytes = resultSet.getBytes(1);
...

然后使用明显的构造函数将此字节数组转换为

DataHandler

dataHandler = new DataHandler(bytes, "application/octet-stream");

在我们开始尝试存储和检索更大的文件之前,这一直很有效。将整个文件内容转储到一个字节数组中,然后从中构建一个

DataHandler
只需要太多内存。

我的直接想法是使用

getBinaryStream
检索数据库中的数据流,并以某种方式以内存高效的方式将
InputStream
转换为
DataHandler
。不幸的是,似乎没有直接的方法可以将
InputStream
转换为
DataHandler
。我一直在玩的另一个想法是从
InputStream
读取数据块并将它们写入
OutputStream
DataHandler
。但是......我找不到创建一个“空”
DataHandler
的方法,当我调用
OutputStream
...
时返回非空
getOutputStream

有人做过吗?我很感激你能给我的任何帮助或引导正确的方向。

java inputstream outputstream
8个回答
24
投票

实施Kathy Van Stone 的回答

首先,创建一个辅助类,它从 InputStream 创建一个数据源:

public class InputStreamDataSource implements DataSource {
    private InputStream inputStream;

    public InputStreamDataSource(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    @Override
    public InputStream getInputStream() throws IOException {
        return inputStream;
    }

    @Override
    public OutputStream getOutputStream() throws IOException {
        throw new UnsupportedOperationException("Not implemented");
    }

    @Override
    public String getContentType() {
        return "*/*";
    }

    @Override
    public String getName() {
        return "InputStreamDataSource";
    }
}

然后您可以从 InputStream 创建 DataHandler:

DataHandler dataHandler = new DataHandler(new InputStreamDataSource(inputStream))

进口

import javax.activation.DataSource;
import java.io.OutputStream;
import java.io.InputStream;

19
投票

我也遇到了这个问题。如果您的源数据是

byte[]
Axis 已经有一个包装 InputStream 并创建 DataHandler 对象的类。这是代码

// This constructor takes byte[] as input
ByteArrayDataSource rawData = new ByteArrayDataSource(resultSet.getBytes(1));
DataHandler data = new DataHandler(rawData);
yourObject.setData(data);

相关进口

import javax.activation.DataHandler;
import org.apache.axiom.attachments.ByteArrayDataSource;

18
投票

我的方法是编写一个自定义类来实现

DataSource
来包装您的
InputStream
。然后创建
DataHandler
给它创建的
DataSource
.


4
投票

注意DataSource的getInputStream每次调用都要返回一个新的InputStream。这意味着您需要先将其复制到某个地方。

有关更多信息,请参阅 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4267294


2
投票

bugs_ 的代码 对我不起作用。我使用 DataSource 创建 attachments 到电子邮件(从具有 inputStreamname 的对象)和丢失的附件内容。

看起来 Stefan 是对的,每次都必须返回一个新的 inputStream。至少在我的具体情况下。以下实现解决了这个问题:

public class InputStreamDataSource implements DataSource {

    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    private final String name;

    public InputStreamDataSource(InputStream inputStream, String name) {
        this.name = name;
        try {
            int nRead;
            byte[] data = new byte[16384];
            while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
                buffer.write(data, 0, nRead);
            }

            buffer.flush();
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public String getContentType() {
        return new MimetypesFileTypeMap().getContentType(name);
    }

    @Override
    public InputStream getInputStream() throws IOException {
        return new ByteArrayInputStream(buffer.toByteArray());
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public OutputStream getOutputStream() throws IOException {
        throw new IOException("Read-only data");
    }
}

0
投票

我遇到过

InputStream
DataSource
请求两次的情况:使用 logging handlerMTOM feature.

有了这个代理流解决方案,我的实现工作正常:

import org.apache.commons.io.input.CloseShieldInputStream;
import javax.activation.DataHandler;
import javax.activation.DataSource;
...

private static class InputStreamDataSource implements DataSource {
    private InputStream inputStream;

    @Override
    public InputStream getInputStream() throws IOException {
        return new CloseShieldInputStream(inputStream);
    }

    @Override
    public OutputStream getOutputStream() throws IOException {
        throw new UnsupportedOperationException("Not implemented");
    }

    @Override
    public String getContentType() {
        return "application/octet-stream";
    }

    @Override
    public String getName() {
        return "";
    }
}

0
投票

这是专门使用 Spring Boot org.springframework.core.io.Resource 对象的答案,我认为这是我们很多人到达这里的原因。请注意,您可能需要修改以下代码中的内容类型,因为我将 PNG 文件插入到 HTML 格式的电子邮件中。

注意:正如其他人所提到的,仅仅附加一个 InputStream 是不够的,因为它会被多次使用。只需映射到 Resource.getInputStream() 就可以了。

public class SpringResourceDataSource implements DataSource {
    private Resource resource;

    public SpringResourceDataSource(Resource resource) {
        this.resource = resource;
    }

    @Override
    public InputStream getInputStream() throws IOException {
        return resource.getInputStream();
    }

    @Override
    public OutputStream getOutputStream() throws IOException {
        throw new UnsupportedOperationException("Not implemented");
    }

    @Override
    public String getContentType() {
        return "image/png";
    }

    @Override
    public String getName() {
        return "SpringResourceDataSource";
    }
}

类的用法如下所示:

PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
Resource logoImage = pathMatchingResourcePatternResolver.getResource("/static/images/logo.png");
MimeBodyPart logoBodyPart = new MimeBodyPart();
DataSource logoFileDataSource = new SpringResourceDataSource(logoImage);

logoBodyPart.setDataHandler(new DataHandler(logoFileDataSource));

0
投票
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import org.apache.commons.io.IOUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

.
.
.

 DataSource ds = new ByteArrayDataSource(convertHtmlToPdf("<span>html here</span>"), "application/pdf");

 DataHandler dataHandler = new DataHandler(ds);

.
.
.

public static byte[] convertHtmlToPdf(String htmlString) throws IOException, DocumentException {
    Document document = new Document();

    ByteArrayOutputStream out = new ByteArrayOutputStream();

    PdfWriter writer = PdfWriter.getInstance(document, out);
    document.open();

    InputStream in = IOUtils.toInputStream(htmlString);
    XMLWorkerHelper.getInstance().parseXHtml(writer, document, in);
    document.close();

    return out.toByteArray();
}

可能的错误:元标记必须关闭。

<meta></meta>

© www.soinside.com 2019 - 2024. All rights reserved.