Ответ 1
Моим подходом было бы написать пользовательский класс, реализующий DataSource
, который обертывает ваш InputStream
. Затем создайте DataHandler
, давая ему созданную DataSource
.
Я работаю над 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
...
Кто-нибудь это сделал? Я был бы признателен за любую помощь, которую вы можете дать мне или ведет в правильном направлении.
Моим подходом было бы написать пользовательский класс, реализующий DataSource
, который обертывает ваш InputStream
. Затем создайте DataHandler
, давая ему созданную DataSource
.
Я также столкнулся с этой проблемой. Если ваши исходные данные являются 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;
Надеюсь, что это поможет!
Реализация ответа от "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;
Обратите внимание, что getInputStream DataSource должен каждый раз возвращать новый InputStream. Это означает, что вам нужно скопировать где-то 1-е место. Для получения дополнительной информации см. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4267294
(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");
}
}
Я встречаю ситуацию, когда 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 "";
}
}