Je travaille sur une application Web Java dans laquelle 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
dans notre jeu de résultats:
byte[] bytes = resultSet.getBytes(1);
...
Ce tableau d'octets a ensuite été converti en DataHandler
à l'aide du constructeur évident:
dataHandler=new DataHandler(bytes,"application/octet-stream");
Cela a très bien fonctionné jusqu'à ce que nous essayions de stocker et de récupérer des fichiers plus volumineux. Déposer tout le contenu du fichier dans un tableau d'octets, puis créer un DataHandler
à partir de cela nécessite simplement trop de mémoire.
Mon idée immédiate est de récupérer un flux de données dans la base de données avec getBinaryStream
et de convertir en quelque sorte ce InputStream
en un DataHandler
de manière à économiser la mémoire. Malheureusement, il ne semble pas qu'il existe un moyen direct de convertir un InputStream
en un DataHandler
. Une autre idée à laquelle je joue est de lire des fragments de données de InputStream
et de les écrire dans le OutputStream
du DataHandler
. Mais ... je ne trouve pas le moyen de créer un DataHandler
"vide" qui renvoie un OutputStream
non nul lorsque j'appelle getOutputStream
...
Quelqu'un l'a-t-il fait? J'apprécierais toute aide que vous pouvez me donner ou qui mène dans la bonne direction.
Mon approche serait d'écrire une classe personnalisée implémentant DataSource
qui enveloppe votre InputStream
. Créez ensuite la DataHandler
en lui donnant la DataSource
créée.
Une implémentation de la réponse de "Kathy Van Stone":
Au début, créez la classe d'assistance, 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 vous pouvez ensuite 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 sont un byte[]
, Axis a déjà une classe qui englobe InputStream 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 du DataSource doit renvoyer un nouveau InputStream appelé à chaque fois. Cela signifie que vous devez copier quelque part 1st . Pour plus d'informations, 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 à un courrier électronique (à partir d'objets qui ont inputStream etnom ) et le contenu des pièces jointes perdues . On dirait que Stefan a raison et qu'un nouveau inputStream doit être renvoyé à chaque fois. Au moins dans mon cas particulier. La prochaine implémentation 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");
}
}
Voici une réponse pour travailler spécifiquement avec l’objet Spring Boot org.springframework.core.io.Resource, ce qui est, selon moi, à quel point nous sommes nombreux à en arriver là. Notez que vous devrez peut-être modifier le type de contenu dans le code ci-dessous, car j'insère un fichier png dans un courrier électronique au format HTML.
Remarque: comme d'autres l'ont mentionné, le simple fait de connecter un InputStream n'est pas suffisant, car il est utilisé plusieurs fois. Un mappage vers Resource.getInputStream () suffit.
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";
}
}
L'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));
J'ai rencontré une situation où InputStream
a demandé deux fois à DataSource
: utiliser Logging Handler avec la fonction MTOM . Avec this solution de flux proxy , ma mise en œuvre fonctionne 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 "";
}
}