Java 如何将 InputStream 转换为 DataHandler?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2830561/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 13:22:08  来源:igfitidea点击:

How to convert an InputStream to a DataHandler?

javainputstreamoutputstream

提问by pcorey

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 getByteson our result set:

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

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

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

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

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 DataHandlerout of that simply requires too much memory.

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

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

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

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

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

采纳答案by Kathy Van Stone

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

我的方法是编写一个自定义类来实现DataSource包装您的InputStream. 然后创建DataHandler给它 created DataSource

回答by Jorge Pombar

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

我也遇到了这个问题。如果您的源数据是byte[]Axis,则Axis 已经有一个类来包装 InputStream 并创建一个 DataHandler 对象。这是代码

//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;

Hope it helps!

希望能帮助到你!

回答by Stefan

Note that the getInputStream of the DataSource must return a new InputStream everytime called. This means, you need to copy somewhere 1st. For more info, see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4267294

请注意,DataSource 的 getInputStream 必须在每次调用时返回一个新的 InputStream。这意味着,您需要在第一个地方复制。有关详细信息,请参阅 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4267294

回答by bugs_

An implementation of answer from "Kathy Van Stone":

“Kathy Van Stone”答案的实现:

At first create helper class, which create DataSource from InputStream:

首先创建 helper 类,它从 InputStream 创建 DataSource:

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 DataHandler from InputStream:

然后你可以从 InputStream 创建 DataHandler:

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

imports:

进口

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

回答by yurin

(bugs_)code doesn't works for me. I use DataSource to create Attachments to email (from objects that have inputStreamand name) and content of attachments lost. Looks like Stefan is right and new inputStream must be returned every time. At least in my specific case. Next implementation deals with problem:

(bugs_) 代码对我不起作用。我使用 DataSource 创建电子邮件附件(来自具有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");
    }

}

回答by Grigory Kislin

I've meet situation, when InputStreamrequested from DataSourcetwice: using Logging Handler together with MTOM feature. With this proxy stream solutionmy implementation works fine:

我遇到过两次InputStream请求时的情况DataSource:将日志处理程序与 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 "";
    }
}

回答by Gandalf

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.

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

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.

注意:正如其他人提到的,仅仅附加一个 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";
    }
}   

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