如何将 InputStream 转换为 DataHandler?

发布于 2024-09-01 11:14:39 字数 841 浏览 3 评论 0 原文

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

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

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

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

这非常有效,直到我们开始尝试存储和检索更大的文件。将整个文件内容转储到字节数组中,然后从中构建 DataHandler 只需要太多内存。

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

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

I'm working on a Java web application in which files will be stored in a database. Originally, we retrieved files already in the DB by simply calling getBytes on our result set:

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

This byte array was then converted into a DataHandler using the obvious constructor:

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

This worked great until we started trying to store and retrieve larger files. Dumping the entire file contents into a byte array and then building a DataHandler out of that simply requires too much memory.

My immediate idea is to retrieve a stream of the data in the database with getBinaryStream and somehow convert that InputStream into a DataHandler in a memory-efficient way. Unfortunately it doesn't seem like there's a direct way to convert an InputStream into a DataHandler. Another idea I've been playing with is reading chunks of data from the InputStream and writing them to the OutputStream of the DataHandler. But... I can't find a way to create an "empty" DataHandler that returns a non-null OutputStream when I call getOutputStream...

Has anyone done this? I'd appreciate any help you can give me or leads in the right direction.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

北方的巷 2024-09-08 11:14:39

Kathy Van Stone 的答案的实现< /a>:

首先,创建一个帮助器类,该类从输入流创建数据源:

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";
    }
}

然后您可以从输入流创建数据处理程序:

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

导入

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

An implementation of the answer from Kathy Van Stone:

At first, create a helper class, which creates a DataSource from an 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";
    }
}

And then you can create a DataHandler from an InputStream:

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

imports:

import javax.activation.DataSource;
import java.io.OutputStream;
import java.io.InputStream;
你与昨日 2024-09-08 11:14:39

我也遇到了这个问题。如果您的源数据是 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;

I also ran into this issue. If your source data is a byte[], Axis already has a class that wraps the InputStream and creates a DataHandler object. Here is the code

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

Related imports

import javax.activation.DataHandler;
import org.apache.axiom.attachments.ByteArrayDataSource;
指尖凝香 2024-09-08 11:14:39

我的方法是编写一个自定义类,实现包装您的InputStreamDataSource。然后创建 DataHandler,为其提供创建的 DataSource

My approach would be to write a custom class implementing DataSource that wraps your InputStream. Then create the DataHandler giving it the created DataSource.

清风夜微凉 2024-09-08 11:14:39

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

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

Note that the getInputStream of the DataSource must return a new InputStream every time called. This means you need to copy it somewhere first.

For more information, see
https://bugs.java.com/bugdatabase/view_bug?bug_id=4267294

秋叶绚丽 2024-09-08 11:14:39

bugs_的代码不起作用为我。我使用 DataSource 创建电子邮件附件(来自具有 inputStream 和 name 的对象),并且附件内容丢失。

看起来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");
    }
}

bugs_'s code doesn't work for me. I use DataSource to create attachments to email (from objects that have inputStream and name) and content of attachments lost.

It looks like Stefan is right and a new inputStream must be returned every time. At least in my specific case. The following implementation deals with the problem:

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");
    }
}
梅窗月明清似水 2024-09-08 11:14:39

InputStreamDataSource 请求两次时,我遇到过这种情况:将日志处理程序MTOM 功能。

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

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 "";
    }
}

I've met the situation when InputStream requested from DataSource twice: using a logging handler together with MTOM feature.

With this proxy stream solution, my implementation works fine:

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 "";
    }
}
若水般的淡然安静女子 2024-09-08 11:14:39

这是专门使用 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));

Here is an answer for specifically working with the Spring Boot org.springframework.core.io.Resource object which is, I think, how a lot of us are getting here. Note that you might need to modify the content type in the code below as I'm inserting a PNG file into an HTML formatted email.

Note: As others have mentioned, merely attaching an InputStream isn't enough as it gets used multiple times. Just mapping through to Resource.getInputStream() does the trick.

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";
    }
}

Usage of the class looks like this:

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));
洒一地阳光 2024-09-08 11:14:39
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();
}

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

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();
}

possible error: the meta tag must be closed. <meta></meta>

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文