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 à OutputStreamDataHandler. 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.

21
demandé sur pcorey 2010-05-14 01:49:21

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.

15
répondu Kathy Van Stone 2010-05-13 21:56:49

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;
16
répondu bugs_ 2013-01-16 12:24:36

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!

16
répondu Jorge Pombar 2016-02-22 16:08:20

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

3
répondu Stefan 2011-01-30 23:32:53

(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");
    }

}
1
répondu yurin 2016-02-11 17:03:00

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 "";
    }
}
0
répondu GKislin 2017-05-23 12:34:15

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));
0
répondu Gandalf 2018-02-06 02:04:59