base64编码处理大文件

在做项目的时候遇到需要将文件转为base64编码,并存储在文件中。

在将文件转为base64编码是会将文件读入内存,进行base64编码,输出到文件中。代码入下:

FileInputStream stream = new FileInputStream("D:\\桌面\\程序员-第4版.pdf");
     ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
     byte[] b = new byte[1024];
     int n;
     while ((n = stream.read(b)) != -1) {
         out.write(b, 0, n);
     }
     stream.close();
     out.close();
     System.out.println(new String(Base64.encodeBase64(out.toByteArray())));

但是大文件在进行base64编码的时候就会遇到OOM(OOM为out of memory的简称,称之为内存溢出)。

  产生OOM的原因:

  • 文件太大,超出了内存
  • 文件可以正常读入内存,由于base64编码后的文件比原来的文件大1/3,在编码的过程中超出内存

由于3个常规字符可以转换为4个base64编码字符,所以使用3的公倍数作为缓冲区大小。

所以在对大文件进行base64编码时可以采用分段编码,进行输出。代码入下:

//使用分段上传的读取文件的方式将大文件转换为base64编码数据
        ByteArrayOutputStream os1 = new ByteArrayOutputStream();
        InputStream file1 = new FileInputStream("D:\\桌面\\程序员-第4版.pdf");
        byte[] byteBuf = new byte[3 * 1024 * 1024];
        byte[] base64ByteBuf;
        int count1; //每次从文件中读取到的有效字节数
        while ((count1 = file1.read(byteBuf)) != -1) {
            if (count1 != byteBuf.length) {//如果有效字节数不为3*1000,则说明文件已经读到尾了,不够填充满byteBuf了
                byte[] copy = Arrays.copyOf(byteBuf, count1); //从byteBuf中截取包含有效字节数的字节段
                base64ByteBuf = Base64.encodeBase64(copy); //对有效字节段进行编码
            } else {
                base64ByteBuf = Base64.encodeBase64(byteBuf);
            }
            os1.write(base64ByteBuf, 0, base64ByteBuf.length);
            os1.flush();
        }
        file1.close();
        System.out.println(os1.toString());

以上代码是将编码后的数据输出至控制台。其实最好是将文件分段进行编码,分段输出,这样不管文件多大,都可以进行编码,并且不会OOM。以下是将文件输出至txt文档中:

       ByteArrayOutputStream os1 = new ByteArrayOutputStream();
       InputStream file1 = new FileInputStream("D:\\桌面\\程序员-第4版.pdf");
       byte[] byteBuf = new byte[3 * 1024 * 1024];
       byte[] base64ByteBuf;
       int count1; //每次从文件中读取到的有效字节数
       File file = new File("D:\\1.txt");
       while ((count1 = file1.read(byteBuf)) != -1) {
           if (count1 != byteBuf.length) {//如果有效字节数不为3*1000,则说明文件已经读到尾了,不够填充满byteBuf了
               byte[] copy = Arrays.copyOf(byteBuf, count1); //从byteBuf中截取包含有效字节数的字节段
               base64ByteBuf = Base64.encodeBase64(copy); //对有效字节段进行编码
           } else {
               base64ByteBuf = Base64.encodeBase64(byteBuf);
           }
           FileUtils.writeByteArrayToFile(file, base64ByteBuf, true); // 将转换后的数据写入文件中,该方法会自动创建文件
           os1.flush();
       }
       file1.close();

 


        <!-- https://mvnrepository.com/artifact/org.apache.directory.studio/org.apache.commons.codec -->
        <dependency>
            <groupId>org.apache.directory.studio</groupId>
            <artifactId>org.apache.commons.codec</artifactId>
            <version>1.8</version>
        </dependency>
    public static void main(String[] args) throws IOException {
        //使用分段上传的读取文件的方式将大文件转换为base64编码数据
        ByteArrayOutputStream os1 = new ByteArrayOutputStream();
        InputStream file1 = new FileInputStream("/3.txt");
        byte[] byteBuf = new byte[3 * 1024 * 1024];
        byte[] base64ByteBuf = null;
        int count1; //每次从文件中读取到的有效字节数
        while ((count1 = file1.read(byteBuf)) != -1) {
            if (count1 != byteBuf.length) {//如果有效字节数不为3*1000,则说明文件已经读到尾了,不够填充满byteBuf了
                byte[] copy = Arrays.copyOf(byteBuf, count1); //从byteBuf中截取包含有效字节数的字节段
                base64ByteBuf = Base64.encodeBase64(copy); //对有效字节段进行编码
            } else {
                base64ByteBuf = Base64.encodeBase64(byteBuf);
            }
            os1.write(base64ByteBuf, 0, base64ByteBuf.length);
            os1.flush();
        }
        file1.close();
        byte2File(Base64.decodeBase64(base64ByteBuf),"/"+System.currentTimeMillis()+".txt");
    }

    public static void byte2File(byte[] b, String outputFile) {
        File file = null;
        FileOutputStream output = null;
        try {
            file = new File(outputFile);
            if (file.exists()) {
                file.delete();
            }
            output = new FileOutputStream(file);
            output.write(b);
            output.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

本文参考文档:java http方式上传大文件(文件流分段上传、base64分段转码)_李梦成的博客-CSDN博客_java 分块上传

base64解码大文件请参考:BASE64编码字符串解码时堆内存溢出_GAMELOFT9----纸上得来终觉浅,绝知此事要躬行-CSDN博客_base64 oom,没有实际操作,原理上应该是可以的。

posted @ 2022-07-17 12:12  小大宇  阅读(1003)  评论(0编辑  收藏  举报