web-dev-qa-db-ja.com

InputStreamをDataHandlerに変換する方法は?

私はファイルをデータベースに保存するJava Webアプリケーションに取り組んでいます。もともとは、結果セットでgetBytesを呼び出すだけで、DBに既にファイルを取得していました。

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

次に、このバイト配列は、明白なコンストラクターを使用してDataHandlerに変換されました。

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

これは、大きなファイルを保存および取得しようとするまではうまくいきました。ファイルの内容全体をバイト配列にダンプし、その中からDataHandlerを作成するには、必要なメモリが多すぎます。

私の当面のアイデアは、getBinaryStreamを使用してデータベース内のデータのストリームを取得し、そのInputStreamをメモリ効率の良い方法でDataHandlerに変換することです。残念ながら、InputStreamDataHandlerに直接変換する方法はないようです。私が遊んでいたもう1つのアイデアは、InputStreamからデータのチャンクを読み取り、OutputStreamDataHandlerに書き込むことです。しかし... DataHandlerを呼び出したときにnull以外のOutputStreamを返す「空の」getOutputStreamを作成する方法が見つかりません。

誰もこれをしましたか?あなたが私に与えることができるか、正しい方向に導くことができるどんな助けでも感謝します。

23
pcorey

私のアプローチは、DataSourceをラップするInputStreamを実装するカスタムクラスを記述することです。次に、DataHandlerを作成し、作成されたDataSourceを指定します。

16
Kathy Van Stone

「Kathy Van Stone」からの回答の実装:

最初に、InputStreamからDataSourceを作成するヘルパークラスを作成します。

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

そして、InputStreamからDataHandlerを作成できます。

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

インポート

import javax.activation.DataSource;
import Java.io.OutputStream;
import Java.io.InputStream;
17
bugs_

私もこの問題に遭遇しました。ソースデータがbyte[] Axisにはすでに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;

それが役に立てば幸い!

16
Jorge Pombar

DataSourceのgetInputStreamは、呼び出されるたびに新しいInputStreamを返す必要があることに注意してください。つまり、1番目のどこかにコピーする必要があります。詳細については、 http://bugs.Sun.com/bugdatabase/view_bug.do?bug_id=4267294 を参照してください

3
Stefan

(bugs_)codeが機能しません。 DataSourceを使用して、電子メールへの添付ファイル(inputStreamおよびnameを持つオブジェクトから)および添付ファイルのコンテンツを失います。 Stefanは正しいようで、毎回新しいinputStreamを返す必要があります。少なくとも私の特定のケースでは。次の実装では問題に対処します。

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
yurin

ここでは、Spring Boot org.springframework.core.io.Resourceオブジェクトを具体的に操作するための答えを示します。 html形式の電子メールにpngファイルを挿入しているため、以下のコードでコンテンツタイプを変更する必要がある場合があることに注意してください。

注:他の人が述べたように、InputStreamをアタッチするだけでは複数回使用されるので十分ではなく、Resource.getInputStream()にマッピングするだけでうまくいきます。

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

クラスの使用法は次のようになります。

    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
Gandalf

InputStreamDataSourceから2回要求されたとき、私は状況に遭遇しました:MTOM機能と一緒にLogging Handlerを使用します。 このプロキシストリームソリューション を使用すると、実装は正常に動作します。

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
GKislin