왜 인기있는 자바 Base64로 인코딩 라이브러리는 인코딩을위한 OutputStreams과에는 InputStream는 인코딩 사용합니까?

M. 월러스 :

나는 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

마틴 Bodewes :

음, 그래, 당신은 그것을 되돌릴 수 있지만, 이것은 가장 의미가 있습니다. 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 또한이 잘못을 얻을.

추천

출처http://10.200.1.11:23101/article/api/json?id=478601&siteId=1