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
How to convert an InputStream to a DataHandler?
提问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 getBytes
on our result set:
我正在开发一个 java web 应用程序,其中的文件将存储在数据库中。最初,我们通过简单地调用getBytes
我们的结果集来检索数据库中已有的文件:
byte[] bytes = resultSet.getBytes(1);
...
This byte array was then converted into a DataHandler
using 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 DataHandler
out of that simply requires too much memory.
这非常有效,直到我们开始尝试存储和检索更大的文件。将整个文件内容转储到一个字节数组中,然后从中构建一个DataHandler
只需要太多内存。
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
...
我的直接想法是检索数据库中的数据流,getBinaryStream
并以某种方式将其InputStream
转换DataHandler
为内存有效的方式。不幸的是,似乎没有直接的方法可以将 anInputStream
转换为DataHandler
. 另一个想法我一直在玩从读取数据块InputStream
,并将其写入OutputStream
的DataHandler
。但是......我找不到一种方法来创建一个“空” DataHandler
,OutputStream
当我打电话时返回一个非空值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 DataSource
that wraps your InputStream
. Then create the DataHandler
giving 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 创建电子邮件附件(来自具有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");
}
}
回答by Grigory Kislin
I've meet situation, when InputStream
requested from DataSource
twice: 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));