Comment convertir un InputStream en DataHandler?
je travaille sur une application web java dans lequel les fichiers seront stockés dans une base de données. A l'origine, nous avons récupéré des fichiers déjà dans la base de données en appelant simplement getBytes
sur notre jeu de résultats:
byte[] bytes = resultSet.getBytes(1);
...
ce tableau byte a ensuite été converti en DataHandler
à l'aide de l'évident constructeur:
dataHandler=new DataHandler(bytes,"application/octet-stream");
cela a bien fonctionné jusqu'à ce que nous commencions à essayer de stocker et de récupérer des fichiers plus gros. Jeter tout le contenu du fichier dans un tableau d'octets et ensuite construire un DataHandler
de cette nécessite tout simplement trop de mémoire.
Mon idée est de récupérer un flux de données dans la base de données getBinaryStream
et en quelque sorte de les convertir InputStream
dans un DataHandler
d'une manière efficace pour la mémoire. Malheureusement, il ne semble pas qu'il y ait un moyen direct de convertir un InputStream
dans un DataHandler
. Une autre idée que j'ai joué avec est de lire des morceaux de données de la InputStream
et les écrire à OutputStream
DataHandler
. Mais... Je ne peux pas trouver un moyen de créer un "vide" DataHandler
qui renvoie une valeur non null OutputStream
lorsque j'appelle getOutputStream
...
quelqu'un A fait cela? J'apprécierais toute aide que vous pouvez me donner ou mène dans la bonne direction.
7 réponses
mon approche serait d'écrire une implémentation de classe personnalisée DataSource
qui entoure votre InputStream
. Puis créer le DataHandler
lui donner le Créé DataSource
.
Une mise en œuvre de la réponse "Kathy Van de Pierre":
d'abord créer la classe helper, qui crée DataSource à partir 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";
}
}
et ensuite vous pouvez créer DataHandler à partir de InputStream:
DataHandler dataHandler = new DataHandler(new InputStreamDataSource(inputStream))
importations:
import javax.activation.DataSource;
import java.io.OutputStream;
import java.io.InputStream;
j'ai aussi rencontré ce problème. Si vos données source est un byte[]
Axis a déjà une classe qui enveloppe L'entrée et crée un objet DataHandler. Voici le code
//this constructor takes byte[] as input
ByteArrayDataSource rawData= new ByteArrayDataSource(resultSet.getBytes(1));
DataHandler data= new DataHandler(rawData);
yourObject.setData(data);
importations connexes
import javax.activation.DataHandler;
import org.apache.axiom.attachments.ByteArrayDataSource;
j'Espère que ça aide!
notez que le getInputStream de la source de données doit retourner un nouveau InputStream chaque fois qu'il est appelé. Ce qui veut dire que tu dois copier quelque part en premier. Pour plus d'info, voir http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4267294
(bugs_)le code ne fonctionne pas pour moi. J'utilise DataSource pour créer des pièces jointes à l'email (à partir d'objets qui ont inputStream et nom) et le contenu des pièces jointes perdu. On dirait que Stefan a raison et que la nouvelle entrée doit être retournée à chaque fois. Au moins dans mon cas précis. De mise en œuvre suivante traite du problème:
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");
}
}
j'ai rencontré la situation, quand InputStream
demande DataSource
deux fois: Utilisation du Gestionnaire de journalisation avec la fonctionnalité MTOM.
ce proxy flux de solution mon application fonctionne très 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 "";
}
}
Note: Comme d'autres l'ont mentionné, il ne suffit pas de simplement joindre un flux entrant, car il est utilisé plusieurs fois, il suffit de faire une correspondance avec la ressource.getInputStream() ne le astuce.
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";
}
}
Utilisation de la classe ressemble à ceci:
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));