java - bytearraydatasource - ¿Cómo convertir un InputStream a un DataHandler?
datahandler java (7)
Aquí hay una respuesta para trabajar específicamente con el objeto Spring Boot org.springframework.core.io.Resource que es, creo, cómo muchos de nosotros estamos llegando aquí. Tenga en cuenta que es posible que deba modificar el tipo de contenido en el código a continuación, ya que estoy insertando un archivo png en un correo electrónico con formato html.
Nota: Como han mencionado otros, simplemente adjuntar un InputStream no es suficiente, ya que se usa varias veces, solo el mapeo a través de Resource.getInputStream () hace el truco.
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";
}
}
El uso de la clase se ve así:
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));
Estoy trabajando en una aplicación web java en la que los archivos se almacenarán en una base de datos. Originalmente, recuperamos archivos que ya se encontraban en la base de datos simplemente llamando a getBytes
en nuestro conjunto de resultados:
byte[] bytes = resultSet.getBytes(1);
...
Esta matriz de bytes se convirtió luego en un DataHandler
usando el constructor obvio:
dataHandler=new DataHandler(bytes,"application/octet-stream");
Esto funcionó muy bien hasta que comenzamos a tratar de almacenar y recuperar archivos más grandes. Volcar todo el contenido del archivo en una matriz de bytes y luego construir un DataHandler
partir de eso simplemente requiere demasiada memoria.
Mi idea inmediata es recuperar un flujo de datos en la base de datos con getBinaryStream
y de alguna manera convertir ese InputStream
en un DataHandler
de una manera eficiente en memoria. Desafortunadamente, no parece que haya una forma directa de convertir un InputStream
en un DataHandler
. Otra idea con la que he estado jugando es leer fragmentos de datos de InputStream
y escribirlos en OutputStream
del DataHandler
. Pero ... no puedo encontrar una manera de crear un DataHandler
"vacío" que devuelva un OutputStream
no sea nulo cuando llamo a getOutputStream
...
¿Alguien ha hecho esto? Apreciaría cualquier ayuda que me pueda dar o dirija en la dirección correcta.
El código (bugs_) no funciona para mí. Uso DataSource para crear archivos adjuntos al correo electrónico (de objetos que tienen inputStream y nombre ) y se perdió el contenido de los archivos adjuntos. Parece que Stefan tiene razón y que se debe devolver el nuevo inputStream cada vez. Al menos en mi caso específico. La siguiente implementación trata con el problema:
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");
}
}
Me encontré con la situación, cuando InputStream
solicitó a DataSource
dos veces: usar Logging Handler junto con la función MTOM. Con esta solución de transmisión proxy mi implementación funciona bien:
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 "";
}
}
Mi enfoque sería escribir una clase personalizada implementando DataSource
que envuelva su InputStream
. Luego crea el DataHandler
dándole el DataSource
creado.
También me encontré con este problema. Si sus datos de origen son un byte[]
Axis ya tiene una clase que envuelve el InputStream y crea un objeto DataHandler. Aquí está el código
//this constructor takes byte[] as input
ByteArrayDataSource rawData= new ByteArrayDataSource(resultSet.getBytes(1));
DataHandler data= new DataHandler(rawData);
yourObject.setData(data);
Importaciones relacionadas
import javax.activation.DataHandler;
import org.apache.axiom.attachments.ByteArrayDataSource;
¡Espero eso ayude!
Tenga en cuenta que el getInputStream del DataSource debe devolver un nuevo InputStream cada vez que se llame. Esto significa que necesitas copiar en algún lugar 1er. Para obtener más información, consulte http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4267294
Una implementación de la respuesta de "Kathy Van Stone":
Al principio, cree la clase auxiliar, que crea DataSource de 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";
}
}
Y luego puedes crear DataHandler desde InputStream:
DataHandler dataHandler = new DataHandler(new InputStreamDataSource(inputStream))
importaciones :
import javax.activation.DataSource;
import java.io.OutputStream;
import java.io.InputStream;