私は、我々はファイル全体をメモリにロードしているJavaプログラムでメモリの問題を解決しようとしているbase64では、それをコードして、ポストの要求におけるフォームパラメータとしてそれを使用します。これは非常に大きなファイルサイズに原因OOMEです。
私は、私は、HTTP POSTリクエストのリクエストボディに、base64でエンコーダを通じてファイルをストリーミングすることができる午前ソリューションに取り組んでいます。私は人気のエンコーディングライブラリ(グアバ、java.util.Base64、android.util.Base64とorg.apache.batik.util)のすべてに気づいた一般的なパターンの一つということであれば、ライブラリサポートはストリームでエンコード、エンコーディングいつものOutputStreamを介して行われ、デコードはいつものInputStreamを介して行われます。
私はこれらの決定の背後にある理由を決定/トラブル発見を持っています。これらの人気があり、よく書かれたライブラリの多くは、このAPIの設計に合わせて、私はこの理由があることを前提としていることを考えます。入力ストリームになるかInputStreamを受け入れるためにこれらのデコーダのいずれかを適応させることは非常に困難でいないようですが、これらのエンコーダは、このように設計されている有効なアーキテクチャの理由がある場合、私は疑問に思って。
なぜ共通ライブラリは、InputStreamを使用してデコードOuputStreamとのBase64てBase64エンコードを行うのですか?
私の主張をバックアップする例:
java.util.Base64
- Base64.Decoder.wrap(InputStream stream)
- Base64.Encoder.wrap(OutputStream stream)
android.util.Base64
- Base64InputStream // An InputStream that does Base64 decoding on the data read through it.
- Base64OutputStream // An OutputStream that does Base64 encoding
google.common.io.BaseEncoding
- decodingStream(Reader reader)
- encodingStream(Writer writer)
org.apache.batik.util
- Base64DecodeStream implements InputStream
- Base64EncodeStream implements OutputStream
まあ、はい、あなたはそれを逆にすることができますが、これは最も理にかなっています。BASE64を作るために使用されるバイナリデータをアプリケーションによって上に生成または操作- -テキストベースの外部環境との互換性。ベース64符号化されたデータに常に外側に必要とされ、復号されたバイナリデータを内部に必要とされます。
アプリケーションは、一般に、ベース64上の任意の操作を行わない符号化されたデータ自体; ちょうど別のアプリケーションとバイナリデータを通信するために必要とされるテキストインタフェースが必要または予想される場合。
あなたは外にあなたのバイナリデータをエクスポートする場合は、当然、あなたは、出力ストリームを使用します。そのデータのニーズがベース64でエンコードされている場合は、必ずベース64にエンコードすることを出力ストリームにデータを送信します。
あなたが外からあなたのバイナリデータをインポートしたいなら、あなたは、入力ストリームを使用します。そのデータは、ベース64でエンコードされている場合は、必ずバイナリストリームとして、それを処理する前に、それをデコードしますので、あなたが最初の必要性は、それを復号化します。
画像のビットを作成することができます。あなたは、テキスト指向の環境で動作しますが、バイナリデータ上で動作するアプリケーションを持っていると言います。重要な部分は、左のアプリケーションのコンテキストから矢印の方向です。
そして、あなたは(呼び出しを読む)入力を取得します:
{APPLICATION} <- (binary data decoding) <- (base64 decoding) <- (file input stream) <- [BASE 64 ENCODED FILE]
このために、あなたは自然に入力ストリームを使用します。
だから、出力(書込みコール)での見てみましょう:
{APPLICATION} -> (binary data encoding) -> (base64 encoding) -> (file output stream) -> [BASE 64 ENCODED FILE]
このために、あなたは自然に出力ストリームを使用しています。
これらのストリームはによって相互に接続することができ、それらを一緒にチェーン化、すなわち、他のストリームの親として一つのストリームを使用して。
ここではJavaでの例です。データクラス自体にバイナリエンコーダ/デコーダを作成するビット醜いであることに注意してください。一般的に、あなたはそのために別のクラスを使用します - 私はそれがデモの目的には十分で願っています。
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Base64;
public class BinaryHandlingApplication {
/**
* A data class that encodes to binary output, e.g. to interact with an application in another language.
*
* Binary format: [32 bit int element string size][UTF-8 element string][32 bit element count]
* The integers are signed, big endian values.
* The UTF-8 string should not contain a BOM.
* Note that this class doesn't know anything about files or base 64 encoding.
*/
public static class DataClass {
private String element;
private int elementCount;
public DataClass(String element) {
this.element = element;
this.elementCount = 1;
}
public String getElement() {
return element;
}
public void setElementCount(int count) {
this.elementCount = count;
}
public int getElementCount() {
return elementCount;
}
public String toString() {
return String.format("%s count is %d", element, elementCount);
}
public void save(OutputStream out) throws IOException {
DataOutputStream dataOutputStream = new DataOutputStream(out);
// so here we have a chain of:
// a dataoutputstream on a base 64 encoding stream on a fileoutputstream
byte[] utf8EncodedString = element.getBytes(UTF_8);
dataOutputStream.writeInt(utf8EncodedString.length);
dataOutputStream.write(utf8EncodedString);
dataOutputStream.writeInt(elementCount);
}
public void load(InputStream in) throws IOException {
DataInputStream dataInputStream = new DataInputStream(in);
// so here we have a chain of:
// a datainputstream on a base 64 decoding stream on a fileinputstream
int utf8EncodedStringSize = dataInputStream.readInt();
byte[] utf8EncodedString = new byte[utf8EncodedStringSize];
dataInputStream.readFully(utf8EncodedString);
this.element = new String(utf8EncodedString, UTF_8);
this.elementCount = dataInputStream.readInt();
}
}
/**
* Create the a base 64 output stream to a file; the file is the text oriented
* environment.
*/
private static OutputStream createBase64OutputStreamToFile(String filename) throws FileNotFoundException {
FileOutputStream textOutputStream = new FileOutputStream(filename);
return Base64.getUrlEncoder().wrap(textOutputStream);
}
/**
* Create the a base 64 input stream from a file; the file is the text oriented
* environment.
*/
private static InputStream createBase64InputStreamFromFile(String filename) throws FileNotFoundException {
FileInputStream textInputStream = new FileInputStream(filename);
return Base64.getUrlDecoder().wrap(textInputStream);
}
public static void main(String[] args) throws IOException {
// this text file acts as the text oriented environment for which we need to encode
String filename = "apples.txt";
// create the initial class
DataClass instance = new DataClass("them apples");
System.out.println(instance);
// perform some operation on the data
int newElementCount = instance.getElementCount() + 2;
instance.setElementCount(newElementCount);
// write it away
try (OutputStream out = createBase64OutputStreamToFile(filename)) {
instance.save(out);
}
// read it into another instance, who cares
DataClass changedInstance = new DataClass("Uh yeah, forgot no-parameter constructor");
try (InputStream in = createBase64InputStreamFromFile(filename)) {
changedInstance.load(in);
}
System.out.println(changedInstance);
}
}
特に、任意のバッファが存在しない場合のストリームの、そしてもちろんの連鎖に注意一切を。私は(場合には、HTTP GETの代わりに使用したい)URLセーフベース64を使用しました。
あなたのケースでは、もちろん、あなたがURLと使ってHTTP POSTリクエスト生成することができ、直接エンコード、検索にOutputStream
それをラップすることにより、ストリームを。何ベース64の符号化データは、(広く)する必要はありませんそのように緩衝化。取得する方法の例を参照してくださいOutputStream
ここに。
あなたがバッファリングする必要がある場合、あなたはそれが間違ってやっている、覚えておいてください。
コメントで述べたように、HTTP POSTは、今あなたがHTTP接続に直接ベース64をコード化することができる方法を知って、ベース64のエンコーディングが、何を必要としません。
java.util.Base64
特定注:ベース64はテキストであるが、BASE64ストリームは/消費バイトを生成します。それは単にASCIIエンコーディング(UTF-16テキストについては、このことができる楽しさ)を前提としています。個人的に私は、これはひどい設計上の決定だと思います。彼らはラップしているはずですReader
し、Writer
代わりに、ダウンそれが遅くなるが、わずかにエンコードする場合でも。
彼らの防衛に、様々なベース64の規格とRFCも、この間違ったを取得します。