Подтвердить что ты не робот

Как преобразовать InputStream в DataHandler?

Я работаю над Java-приложением, в котором файлы будут храниться в базе данных. Первоначально мы загрузили файлы уже в БД, просто набрав getBytes в нашем результирующем наборе:

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

Затем этот массив байтов был преобразован в DataHandler с использованием очевидного конструктора:

dataHandler=new DataHandler(bytes,"application/octet-stream");

Это сработало отлично, пока мы не начали хранить и извлекать более крупные файлы. Сбрасывая все содержимое файла в массив байтов, а затем выстраивая из него DataHandler, требуется просто слишком много памяти.

Моей непосредственной идеей является получение потока данных в базе данных с помощью getBinaryStream и каким-то образом преобразование этого InputStream в DataHandler эффективным с точки зрения памяти. К сожалению, нет никакого прямого преобразования InputStream в DataHandler. Другая идея, с которой я играл, - чтение фрагментов данных из InputStream и запись их в OutputStream DataHandler. Но... Я не могу найти способ создать "пустой" DataHandler, который возвращает ненулевой OutputStream при вызове getOutputStream...

Кто-нибудь это сделал? Я был бы признателен за любую помощь, которую вы можете дать мне или ведет в правильном направлении.

4b9b3361

Ответ 1

Моим подходом было бы написать пользовательский класс, реализующий DataSource, который обертывает ваш InputStream. Затем создайте DataHandler, давая ему созданную DataSource.

Ответ 2

Я также столкнулся с этой проблемой. Если ваши исходные данные являются byte[], у оси уже есть класс, который обертывает InputStream и создает объект DataHandler. Вот код

//this constructor takes byte[] as input
ByteArrayDataSource rawData= new ByteArrayDataSource(resultSet.getBytes(1));
DataHandler data= new DataHandler(rawData);
yourObject.setData(data);

Связанный импорт

import javax.activation.DataHandler;
import org.apache.axiom.attachments.ByteArrayDataSource;

Надеюсь, что это поможет!

Ответ 3

Реализация ответа от "Kathy Van Stone":

Сначала создайте вспомогательный класс, который создает DataSource из 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";
    }
}

И затем вы можете создать DataHandler из InputStream:

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

Импорт

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

Ответ 4

Обратите внимание, что getInputStream DataSource должен каждый раз возвращать новый InputStream. Это означает, что вам нужно скопировать где-то 1-е место. Для получения дополнительной информации см. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4267294

Ответ 5

(bugs_) код не работает для меня. Я использую DataSource для создания вложений в электронную почту (из объектов, у которых есть имя ввода и имя), и содержимое вложений потеряно. Похоже, что Стефан прав, и новый входной поток должен быть возвращен каждый раз. По крайней мере, в моем конкретном случае. Следующая реализация касается проблемы:

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

}

Ответ 6

Я встречаю ситуацию, когда InputStream запрашивается с DataSource дважды: использование обработчика ведения журнала вместе с функцией MTOM. С этим прокси-потоковым решением моя реализация отлично работает:

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