- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我一直在尝试解决Java程序中的内存问题,我们将整个文件加载到内存中,对其进行base64编码,然后将其用作发布请求中的表单参数。这是由于文件太大而导致 OOME。
我正在开发一个解决方案,我可以通过 Base64 编码器将文件流式传输到 Http Post 请求的请求正文中。我在所有流行的编码库(Guava、java.util.Base64、android.util.Base64 和 org.apache.batik.util)中注意到的常见模式之一是如果库支持使用流进行编码,编码始终通过输出流完成,解码始终通过输入流完成。
我无法找到/确定这些决定背后的原因。鉴于许多流行且编写良好的库都与此 api 设计保持一致,我认为这是有原因的。将这些解码器之一调整为输入流或接受输入流似乎并不困难,但我想知道这些编码器以这种方式设计是否有有效的架构原因。
为什么常见的库通过OutputStream进行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 用于使应用程序生成或操作的二进制数据与基于文本的外部环境兼容。 因此外部始终需要 Base 64 编码数据,内部需要解码的二进制数据。
应用程序通常不会对 64 位编码数据本身执行任何操作; 当需要或期望文本接口(interface)时,只需要与另一个应用程序通信二进制数据。
<小时/>如果你想将二进制数据导出到外部,自然你会使用输出流。如果该数据需要以 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 的示例.
请记住,如果您需要缓冲,那么您就做错了。
正如评论中提到的,HTTP POST 不需要 Base 64 编码,但无论如何,现在您知道如何将 Base 64 直接编码到 HTTP 连接。
<小时/>java.util.Base64
具体说明:虽然base 64是文本,但是base64流生成/消耗字节;它只是假设 ASCII 编码(这对于 UTF-16 文本来说可能很有趣)。我个人认为这是一个糟糕的设计决策;他们应该改为包装 Reader
和 Writer
,即使这会稍微减慢编码速度。
为他们辩护,各种 Base 64 标准和 RFC 也犯了这个错误。
关于java - 为什么流行的Java Base64编码库使用OutputStreams进行编码,使用InputStreams进行编码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60121335/
我在一个类中有两个方法: private static InputStream getSongStream(String ip, String id){ try { U
我创建了一个扩展 InputStream 的新类并且必须 @Override read()。我正在尝试使用方法 read(int b),但是当我使用它时,它会转到方法read() 和我不能使用参数,我
我正在尝试编写一个函数,该函数将接受带有压缩文件数据的 InputStream 并返回另一个带有解压缩数据的 InputStream。 压缩后的文件将只包含一个文件,因此不需要创建目录等... 我尝试
我想知道是否有任何理想的方式可以将多个 InputStream 链接到 Java(或 Scala)中的一个连续 InputStream 中。 我需要它来解析我从 FTP 服务器通过网络加载的平面文件。
我想做的是:打开大文件的 InputStream,按 10MB block 读取它,上传一个 block ,读取下一个 block 。 val chunkCount = Math.ceil(total
我不知道怎么理解: { if (inputStream **!= null**) { inputStream.close(); 来自那个例子: public c
我想知道 InputStream 是否为空,但不使用 read() 方法。有没有办法不读取就知道它是否为空? 最佳答案 不,你不能。 InputStream 设计用于处理远程资源,因此在实际读取它之前
我制作了一个蓝牙输入流监听器,只需询问 if(InputStream.isAvailable > 0) 即可检查是否有传入数据,然后创建一个循环将传入数据存储到 int[] 直到没有更多并且它工作完美
这是我的代码流程,文件内容丢失,我认为可能是 IOUtils.toByteArray() 行有问题,请指导这里实际出了什么问题。 文件内容丢失: InputStream stream = someCl
我从 HTTP 请求的响应开始: InputStream responseInputStream = response.getEntityInputStream() 我需要对该响应进行 gzip 压缩
用户将一个大文件上传到我的网站,我想对该文件进行 gzip 压缩并将其存储在 blob 中。所以我有一个未压缩的 InputStream,而 blob 需要一个 InputStream。我知道如何使用
我调用了一个返回压缩文件的服务。我从响应中将数据作为 InputStream(由 javax.activation.DataHandler.getInputStream(); 提供)提供。 我想做的是
我正在尝试压缩一个 InputStream 并返回一个 InputStream: public InputStream compress (InputStream in){ // Read "in
我最近在 Kotlin 中看到了将 InputStream 的全部内容读入 String 的代码,例如: // input is of type InputStream val baos = Byte
我正在尝试使用以下代码从 IHTTPSession.getInputStream() 读取 InputStream,但它每次都给出 Socket TimeOut Exception。 private
如 How to use Jersey interceptors to get request body 中所述,我正在修改 ContainerRequestFilter 中的 EntityInput
我正在编写一个需要与蓝牙 2.1 设备交换数据的应用程序。我已经做过好几次了,但这次发生了一些奇怪的事情。 Log.d("TAG", "connectToDevice"); if(ma
我只是在犹豫这是好主意还是坏主意: InputStreamReader in = new InputStreamReader(socket.getInputStream()); BufferedRea
我正在开发一个 Android 应用程序,它的 View 包含多个图库。图库的内容(位图)是来自 Internet 的红色。 对于第一个画廊,一切正常,但是当尝试下载第二个画廊的第一张图片时,Bitm
在Dart中,我想读取BMP,所以可能是BIG文件。 我这样做是这样的: var inputStream = imageFile.openInputStream(); inputStream.onDa
我是一名优秀的程序员,十分优秀!