2

I am reading the list of attachment from a system witch returns the attached document in base 64 encoded string as a zip and My objective is to get the base 64 encoded string for each attached document. Note:- I am trying below code where I am unzipping the zip and writing at my local file system. . But in real I wanted to get the base 64 format for each file without writing the file in local file system.

public class UnzipUtility {
      private static final int BUFFER_SIZE = 4096;

         private static void extractFile(ZipInputStream zipIn, ZipEntry entry) throws IOException {


            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:/Project/"+File.separator+entry.getName()));
            byte[] bytesIn = new byte[BUFFER_SIZE];
            System.out.println("File Name  "+entry.getName());
            int read = 0;
            while ((read = zipIn.read(bytesIn)) != -1) {
                //Hear I dont not want to write the output stream insted I want to get the base64 data for each file.
              bos.write(bytesIn);
            }
            bos.close();
        }
     public static void main(String[] args) throws IOException {
     String attachmentVariable="zip base 64 data"
          byte[] bytedata = attachmentVariable.getBytes("UTF-8");
         byte[] valueDecoded = Base64.decodeBase64(bytedata);
         ZipInputStream zipIn = new ZipInputStream(new ByteArrayInputStream(valueDecoded));
         ZipEntry entry = zipIn.getNextEntry();

            // iterates over entries in the zip file
             while (entry != null) {                    extractFile(zipIn,entry);
                    zipIn.closeEntry();
                    entry = zipIn.getNextEntry();


          }       

        }
}
Andreas
  • 154,647
  • 11
  • 152
  • 247
Upendra Singh
  • 35
  • 1
  • 5

2 Answers2

0

To Base64 encode data as it is being written to an OutputStream, use the Encoder.wrap(OutputStream os) method.

By default, BufferedOutputStream will use a 8192-byte buffer, so if you increase BUFFER_SIZE to 8192, then you won't need the BufferedOutputStream.

You should use try-with-resources, and the newer NIO.2 API.

Which means your code should be:

private static final int BUFFER_SIZE = 8192;

private static void extractFile(ZipInputStream zipIn, ZipEntry entry) throws IOException {
    try ( OutputStream fos = Files.newOutputStream(Paths.get("D:/Project", entry.getName()));
          OutputStream b64os = Base64.getEncoder().wrap(fos); ) {
        System.out.println("File Name  " + entry.getName());
        byte[] buf = new byte[BUFFER_SIZE];
        for (int len = 0; (len = zipIn.read(buf)) != -1; ) {
            b64os.write(buf, 0, len);
        }
    }
}
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • Thanks for your quick response Andreas but i am not sure if i have explain my requirement correctly. As I mentioned above i am reading the the base 64 zip data and finally I am trying to get the output as lets say map (key=name of file value=base 64 string) ,I dont want to write the file anywhere. Thanks For you help. – Upendra Singh May 04 '20 at 17:44
  • from your code i m trying something like below. for (int len = 0; (len = zipIn.read(buf)) != -1; ) { b64os.write(buf, 0, len); } byte[] encoded = java.util.Base64.getEncoder().encode(buf); System.out.println(new String(encoded)); – Upendra Singh May 04 '20 at 17:49
0

So, you have a Base64 encoded string with a zip file, and you want a Map<String, String>, where key is zip entry name and value is the Base64 encoded content.

In Java 9+, that is easily done like this:

String base64ZipFile = "zip base 64 data";
Map<String, String> base64Entries = new LinkedHashMap<>();
try (ZipInputStream zipIn = new ZipInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(base64ZipFile)))) {
    Encoder encoder = Base64.getEncoder();
    for (ZipEntry entry; (entry = zipIn.getNextEntry()) != null; ) {
        base64Entries.put(entry.getName(), encoder.encodeToString(zipIn.readAllBytes()));
    }
}
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • Thanks Andreas, This is what I was looking for :-), Is there any possibility to achieve this in java 8 ? As our client does not have java 8+ environment. Thanks for your help and quick response. – Upendra Singh May 05 '20 at 12:05
  • @UpendraSingh Yeah, you just need to do your own loop to do what `readAllBytes()` does. Or use a third-party library that has a method doing it. – Andreas May 05 '20 at 12:24
  • Thank You Andreas. – Upendra Singh May 05 '20 at 16:43