将大文件转换为Java中的base64表示形式;OutOfMemory异常
我有一种情况,我需要以这种格式将对象从后端传输到前端:将大文件转换为Java中的base64表示形式;OutOfMemory异常,java,base64,Java,Base64,我有一种情况,我需要以这种格式将对象从后端传输到前端: { filename: "filename", type: "type", src: "src", bytes: "base64Representation" } 对象的bytes属性包含存储在远程服务器存储库中的文件的base64表示形式。到目前为止,我一直在处理1-2MB范围内的小文件,将文件转换为相应的base64表示的代码工作正常。但是现在我面临一些大文件的问题,超过100MB。我已经检查了尝试逐块
{
filename: "filename",
type: "type",
src: "src",
bytes: "base64Representation"
}
对象的bytes属性包含存储在远程服务器存储库中的文件的base64表示形式。到目前为止,我一直在处理1-2MB范围内的小文件,将文件转换为相应的base64表示的代码工作正常。但是现在我面临一些大文件的问题,超过100MB。我已经检查了尝试逐块转换文件的解决方案,但在过程结束时,我仍然需要将所有块连接在一个字符串中,在这一步,我得到了一个OutOfMemory异常。我也看到了一些使用输出流的建议,但是我不能应用它们,因为我需要上面格式的数据。有人对如何绕过这种情况有什么建议吗?您可以通过包装
response.getOutputStream()
在servlet中使用OutputStream并动态处理。我将给出一个使用spring boot的工作示例。我测试过了,它能工作
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Base64;
@RestController
public class Base64Controller {
@RequestMapping(value = "/base64", method = RequestMethod.GET)
public void getBase64File(HttpServletResponse response) throws IOException {
response.setContentType("text/plain");
OutputStream wrap = Base64.getEncoder().wrap(response.getOutputStream());
FileInputStream fis = new FileInputStream("./temp.txt");
int bytes;
byte[] buffer = new byte[2048];
while ((bytes=fis.read(buffer)) != -1) {
wrap.write(buffer, 0, bytes);
}
fis.close();
wrap.close();
}
}
通过包装
response.getOutputStream()
,可以在servlet中动态使用OutputStream和process。我将给出一个使用spring boot的工作示例。我测试过了,它能工作
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Base64;
@RestController
public class Base64Controller {
@RequestMapping(value = "/base64", method = RequestMethod.GET)
public void getBase64File(HttpServletResponse response) throws IOException {
response.setContentType("text/plain");
OutputStream wrap = Base64.getEncoder().wrap(response.getOutputStream());
FileInputStream fis = new FileInputStream("./temp.txt");
int bytes;
byte[] buffer = new byte[2048];
while ((bytes=fis.read(buffer)) != -1) {
wrap.write(buffer, 0, bytes);
}
fis.close();
wrap.close();
}
}
JSON响应在这里是一个难题,Base64的有效负载为每字节6/8,您可以根据需要多传输33%的数据。实际上,JSON DOM对象将服务器和客户端都拉伸过度 因此,将其转换为简单的二进制下载,并将其流式输出;可能因大数据而被限制
这意味着API发生了变化。在这里,JSON响应是一个难题,Base64的有效负载为每字节6/8,因此您可以根据需要多传输33%的数据。实际上,JSON DOM对象将服务器和客户端都拉伸过度 因此,将其转换为简单的二进制下载,并将其流式输出;可能因大数据而被限制
这意味着API发生了变化。我从未使用过struts,所以我不确定这是否可行,但应该是这样的
public class DownloadB64Action extends Action{
private final static BUFFER_SIZE = 1024;
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
response.setContentType("text/plain");
try
{
FileInputStream in =
new FileInputStream(new File("myfile.b64"));
ServletOutputStream out = Base64.getEncoder().wrap(response.getOutputStream());
byte[] buffer = new byte[BUFFER_SIZE];
while(in.read(buffer, 0, BUFFER_SIZE) != -1){
out.write(buffer, 0, BUFFER_SIZE);
}
in.close();
out.flush();
out.close();
}catch(Exception e){
//TODO handle exception
}
return null;
}
}
为了使它像您所需要的JSON结构一样,您可以尝试在b64有效负载之前直接写入response.getOutputStream()
“{\”filename\”:\“filename\”,\“type\”:“type\”,\“src\”:\“src\”,\“bytes\”:\”.getBytes(),在b64有效负载之后写入“\”.getBytes()
}我从未使用过struts,所以我不确定这是否可行,但应该是这样的
public class DownloadB64Action extends Action{
private final static BUFFER_SIZE = 1024;
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
response.setContentType("text/plain");
try
{
FileInputStream in =
new FileInputStream(new File("myfile.b64"));
ServletOutputStream out = Base64.getEncoder().wrap(response.getOutputStream());
byte[] buffer = new byte[BUFFER_SIZE];
while(in.read(buffer, 0, BUFFER_SIZE) != -1){
out.write(buffer, 0, BUFFER_SIZE);
}
in.close();
out.flush();
out.close();
}catch(Exception e){
//TODO handle exception
}
return null;
}
}
为了使它像您所需要的JSON结构一样,您可以尝试在b64有效负载之前直接写入response.getOutputStream()
“{\”filename\”:\“filename\”,\“type\”:“type\”,\“src\”:\“src\”,\“bytes\”:\”.getBytes(),在b64有效负载之后写入“\”.getBytes()
}启动JVM时增加堆的大小。@FedericoklezCulloca不同意,因为这个解决方案不会scale@user902383同意(我的意思是)而不是重新组装,为什么不在每次创建块时将块流式传输到前端?如果无法更改HTTP请求的生成方式,则确实必须将对象作为一个整体序列化—上面已经提到了潜在的问题。在启动JVM时增加堆的大小。@FedericoklezCulloca不同意,因为这个解决方案不会scale@user902383同意(我的意思是同意)与其重新组装,不如每次创建一个块时将块流式传输到前端?如果您无法更改HTTP请求的构建方式,那么您确实必须将对象作为一个整体进行序列化——上面已经提到了潜在的问题。