嗯,是的,您可以反转它,但这是最有意义的。 Base64 用于使 二进制数据 - 由应用程序生成或操作 - 与基于文本的外部环境兼容。 所以外部总是需要base 64编码的数据,内部需要解码的二进制数据。
应用程序通常不会对 base 64 编码数据本身执行任何操作;它只需要与另一个应用程序进行二进制数据通信当需要或期望文本接口时。
如果要将二进制数据导出到外部,自然会使用输出流。如果该数据需要以 base 64 编码,请确保将数据发送到编码为 base 64 的输出流。
如果您想从外部导入二进制数据,那么您将使用输入流。如果该数据以 base 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);
}
}
特别注意流的链接,当然也没有任何缓冲区随便。我使用了 URL 安全的 base 64(如果您想使用 HTTP GET 代替)。
当然,在您的情况下,您可以使用 URL 生成 HTTP POST 请求,并直接编码到检索到的 OutputStream 流,方法是包装它。这样就不需要(广泛)缓冲 base 64 编码数据。查看有关如何访问OutputStream here 的示例。
记住,如果你需要缓冲,那你就错了。
如 cmets 中所述,HTTP POST 不需要 base 64 编码,但无论如何,现在您知道如何将 base 64 直接编码为 HTTP 连接了。
java.util.Base64具体说明:
虽然 base 64 是文本,但 base64 流生成/消耗字节;
它只是假设 ASCII 编码(这对于 UTF-16 文本可能很有趣)。
我个人认为这是一个糟糕的设计决定。他们应该包装一个 Reader 和 Writer 代替,即使这会稍微减慢编码速度。
为了他们的辩护,各种 base 64 标准和 RFC 也犯了这个错误。