나는 POST 요청의 형식 매개 변수로 사용하여 다음을 인코딩, 우리는 메모리에 전체 파일을로드하는 자바 프로그램에서 메모리 문제를 해결하기 위해 64 기수를 시도하고있다. 이는 매우 큰 파일 크기 원인 오세요이다.
내가하는 HTTP POST 요청의 요청 본문에, base64로 인코더를 통해 파일을 스트리밍 할 수 있어요 해결책을 일하고 있습니다. 내가 인기 인코딩 라이브러리 (구아바, java.util.Base64, android.util.Base64 및 org.apache.batik.util) 모두에서 발견 한 일반적인 패턴 중 하나는 경우 라이브러리가 지원하는 스트림으로 인코딩, 인코딩 항상의 OutputStream을 통해 수행되고 디코딩은 항상의 InputStream을 통해 이루어집니다.
나는이 결정 뒤에 추론을 결정 / 문제 발견을 데. 이러한 인기와 잘 작성된 라이브러리의 많은 사람들이이 API 디자인에 맞춰, 그래서 나는 이것에 대한 이유가 있다고 가정 감안할. 그것은의 InputStream하게 또는 InputStream를 받아 들일 이러한 디코더 중 하나에 적응하기가 매우 어렵하지 않는 것, 그러나이 인코더는 이러한 방식으로 설계되어 유효한 건축 이유가 있는지 궁금하고있다.
OuputStream 및 Base64로가의 InputStream을 통해 복호화 왜 일반적인 라이브러리를 통해 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]
이를 위해 자연스럽게 출력 스트림을 사용합니다.
이 스트림에 의해 서로 연결 할 수 있습니다 함께 체인 즉, 다른 스트림의 부모로서 하나 개의 스트림을 사용.
여기에 자바의 예입니다. 데이터 클래스 자체 이진 인코더 / 디코더 만들기 비트 추한 참고; 일반적으로 당신은 또 다른 클래스를 사용합니다 - 나는 데모 용으로 충분 바랍니다.
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 또한이 잘못을 얻을.