How to convert an InputStream to a DataHandler?

80,569

Solution 1

My approach would be to write a custom class implementing DataSource that wraps your InputStream. Then create the DataHandler giving it the created DataSource.

Solution 2

An implementation of answer from "Kathy Van Stone":

At first create helper class, which create DataSource from 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";
    }
}

And then you can create DataHandler from InputStream:

DataHandler dataHandler = new DataHandler(new InputStreamDataSource(inputStream))

imports:

import javax.activation.DataSource;
import java.io.OutputStream;
import java.io.InputStream;

Solution 3

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

//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!

Solution 4

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

Solution 5

(bugs_)code doesn't works for me. I use DataSource to create Attachments to email (from objects that have inputStream and 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:

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

}
Share:
80,569
pcorey
Author by

pcorey

Updated on April 16, 2021

Comments

  • pcorey
    pcorey about 3 years

    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:

    byte[] bytes = resultSet.getBytes(1);
    ...
    

    This byte array was then converted into a DataHandler using the obvious constructor:

    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.

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

    Has anyone done this? I'd appreciate any help you can give me or leads in the right direction.