【问题标题】:PDF to byte array and vice versaPDF 到字节数组,反之亦然
【发布时间】:2010-11-10 23:51:39
【问题描述】:

我需要将 pdf 转换为字节数组,反之亦然。

谁能帮帮我?

这就是我转换为字节数组的方式

public static byte[] convertDocToByteArray(String sourcePath) {

    byte[] byteArray=null;
    try {
        InputStream inputStream = new FileInputStream(sourcePath);


        String inputStreamToString = inputStream.toString();
        byteArray = inputStreamToString.getBytes();

        inputStream.close();
    } catch (FileNotFoundException e) {
        System.out.println("File Not found"+e);
    } catch (IOException e) {
                System.out.println("IO Ex"+e);
    }
    return byteArray;
}

如果我使用以下代码将其转换回文档,则会创建 pdf。但它说的是'Bad Format. Not a pdf'

public static void convertByteArrayToDoc(byte[] b) {          

    OutputStream out;
    try {       
        out = new FileOutputStream("D:/ABC_XYZ/1.pdf");
        out.close();
        System.out.println("write success");
    }catch (Exception e) {
        System.out.println(e);
    }

【问题讨论】:

    标签: java arrays pdf


    【解决方案1】:

    Java 7 引入了Files.readAllBytes(),它可以像这样将PDF 读入byte[]

    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.nio.file.Files;
    
    Path pdfPath = Paths.get("/path/to/file.pdf");
    byte[] pdf = Files.readAllBytes(pdfPath);
    

    编辑:

    感谢 Farooque 指出:这适用于阅读任何类型的文件,而不仅仅是 PDF。所有文件最终都只是一堆字节,因此可以读入byte[]

    【讨论】:

    • 感谢@Farooque 的导入编辑! “通常它可以将任何给定文件读入字节[]”是什么意思?
    • 我测试了完美运行的 pdf、jpg、gif、png、txt 文件。由于它支持所有类型的文件,如果有人需要所有类型,那么“通常它可以将任何给定文件读入字节 []”信息将很有帮助
    【解决方案2】:

    您基本上需要一个辅助方法来将流读入内存。这很好用:

    public static byte[] readFully(InputStream stream) throws IOException
    {
        byte[] buffer = new byte[8192];
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
    
        int bytesRead;
        while ((bytesRead = stream.read(buffer)) != -1)
        {
            baos.write(buffer, 0, bytesRead);
        }
        return baos.toByteArray();
    }
    

    然后你会调用它:

    public static byte[] loadFile(String sourcePath) throws IOException
    {
        InputStream inputStream = null;
        try 
        {
            inputStream = new FileInputStream(sourcePath);
            return readFully(inputStream);
        } 
        finally
        {
            if (inputStream != null)
            {
                inputStream.close();
            }
        }
    }
    

    不要混淆文本和二进制数据——这只会让人流泪。

    【讨论】:

    • 我猜在 readFully while 语句中需要一个额外的括号 .. 比如 while ((bytesRead = stream.read(buffer)) != -1)
    • @JonSkeet - 您初始化为 8192 的大小 - 这适用于多大的 PDF 文件?我知道这就像问“一段字符串有多长”,但如果你知道的话,也许是一个通用的指导方针?我的 PDF 大概有 20 页长。
    • @notyou:这只是一个不是很大的缓冲区大小,但足够大以避免“每个字节的系统调用”。基本上,这是一个合理的默认值。
    【解决方案3】:

    问题是您在 InputStream 对象本身上调用 toString()。这将返回 InputStream 对象的 String 表示,而不是实际的 PDF 文档。

    您只想将 PDF 读取为字节,因为 PDF 是二进制格式。然后,您将能够写出相同的 byte 数组,并且它将是一个有效的 PDF,因为它没有被修改。

    例如以字节读取文件

    File file = new File(sourcePath);
    InputStream inputStream = new FileInputStream(file); 
    byte[] bytes = new byte[file.length()];
    inputStream.read(bytes);
    

    【讨论】:

    • 即使这会将 InputStream 对象而不是 PDF 转换为字节数组
    【解决方案4】:

    您可以使用Apache Commons IO 来做到这一点,而不必担心内部细节。

    使用org.apache.commons.io.FileUtils.readFileToByteArray(File file),它返回byte[]类型的数据。

    Click here for Javadoc

    【讨论】:

      【解决方案5】:
      public static void main(String[] args) throws FileNotFoundException, IOException {
              File file = new File("java.pdf");
      
              FileInputStream fis = new FileInputStream(file);
              //System.out.println(file.exists() + "!!");
              //InputStream in = resource.openStream();
              ByteArrayOutputStream bos = new ByteArrayOutputStream();
              byte[] buf = new byte[1024];
              try {
                  for (int readNum; (readNum = fis.read(buf)) != -1;) {
                      bos.write(buf, 0, readNum); //no doubt here is 0
                      //Writes len bytes from the specified byte array starting at offset off to this byte array output stream.
                      System.out.println("read " + readNum + " bytes,");
                  }
              } catch (IOException ex) {
                  Logger.getLogger(genJpeg.class.getName()).log(Level.SEVERE, null, ex);
              }
              byte[] bytes = bos.toByteArray();
      
              //below is the different part
              File someFile = new File("java2.pdf");
              FileOutputStream fos = new FileOutputStream(someFile);
              fos.write(bytes);
              fos.flush();
              fos.close();
          }
      

      【讨论】:

        【解决方案6】:

        这对我有用。我没有使用任何第三方库。只是 Java 附带的那些。

        import java.io.*;
        import java.nio.file.Files;
        import java.nio.file.Path;
        import java.nio.file.Paths;
        
        public class PDFUtility {
        
        public static void main(String[] args) throws IOException {
            /**
             * Converts byte stream into PDF.
             */
            PDFUtility pdfUtility = new PDFUtility();
            byte[] byteStreamPDF = pdfUtility.convertPDFtoByteStream();
            FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\aseem\\Desktop\\BlaFolder\\BlaFolder2\\aseempdf.pdf");
            fileOutputStream.write(byteStreamPDF);
            fileOutputStream.close();
            System.out.println("File written successfully");
        }
        
        /**
         * Creates PDF to Byte Stream
         *
         * @return
         * @throws IOException
         */
        protected byte[] convertPDFtoByteStream() throws IOException {
            Path path = Paths.get("C:\\Users\\aseem\\aaa.pdf");
            return Files.readAllBytes(path);
        }
        
        }
        

        【讨论】:

          【解决方案7】:

          你不是在创建 pdf 文件,但实际上没有写回字节数组吗?因此,您无法打开 PDF。

          out = new FileOutputStream("D:/ABC_XYZ/1.pdf");
          out.Write(b, 0, b.Length);
          out.Position = 0;
          out.Close();
          

          这是在 PDF 中正确读取字节数组的补充。

          【讨论】:

          • out.position=0 ??没看懂
          • 这可能没有用,因为您将其保存到文件中,但我遇到了将字节数组放入 MemoryStream 对象并将其下载到客户端的问题。我必须将 Position 设置回 0 才能正常工作。
          【解决方案8】:

          InputStream 上调用toString() 并没有你认为的那样。即使是这样,PDF 也包含二进制数据,因此您不会想先将其转换为字符串。

          您需要做的是从流中读取,将结果写入ByteArrayOutputStream,然后通过调用toByteArray()ByteArrayOutputStream 转换为实际的byte 数组:

          InputStream inputStream = new FileInputStream(sourcePath);
          ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
          
          int data;
          while( (data = inputStream.read()) >= 0 ) {
              outputStream.write(data);
          }
          
          inputStream.close();
          return outputStream.toByteArray();
          

          【讨论】:

          • 一次读取一个字节的效率不是很高。最好一次复制一个块。
          • @Jon - 是的,但我试图保持简单。另外,FileInputStream 不会在内部进行缓冲以缓解这种情况吗?
          【解决方案9】:

          将 pdf 转换为 byteArray

          public byte[] pdfToByte(String filePath)throws JRException {
          
                   File file = new File(<filePath>);
                   FileInputStream fileInputStream;
                   byte[] data = null;
                   byte[] finalData = null;
                   ByteArrayOutputStream byteArrayOutputStream = null;
          
                   try {
                      fileInputStream = new FileInputStream(file);
                      data = new byte[(int)file.length()];
                      finalData = new byte[(int)file.length()];
                      byteArrayOutputStream = new ByteArrayOutputStream();
          
                      fileInputStream.read(data);
                      byteArrayOutputStream.write(data);
                      finalData = byteArrayOutputStream.toByteArray();
          
                      fileInputStream.close(); 
          
                  } catch (FileNotFoundException e) {
                      LOGGER.info("File not found" + e);
                  } catch (IOException e) {
                      LOGGER.info("IO exception" + e);
                  }
          
                  return finalData;
          
              }
          

          【讨论】:

            【解决方案10】:

            这对我有用:

            try(InputStream pdfin = new FileInputStream("input.pdf");OutputStream pdfout = new FileOutputStream("output.pdf")){
                byte[] buffer = new byte[1024];
                int bytesRead;
                while((bytesRead = pdfin.read(buffer))!=-1){
                    pdfout.write(buffer,0,bytesRead);
                }
            }
            

            但是如果按照以下方式使用,乔恩的回答对我不起作用:

            try(InputStream pdfin = new FileInputStream("input.pdf");OutputStream pdfout = new FileOutputStream("output.pdf")){
            
                int k = readFully(pdfin).length;
                System.out.println(k);
            }
            

            输出零作为长度。这是为什么 ?

            【讨论】:

              【解决方案11】:

              这些都不适合我们,可能是因为我们的inputstream 是来自休息电话的bytes,而不是来自本地托管的 pdf 文件。有效的是使用RestAssured 将PDF 作为输入流读取,然后使用Tika pdf 阅读器对其进行解析,然后调用toString() 方法。

              import com.jayway.restassured.RestAssured;
              import com.jayway.restassured.response.Response;
              import com.jayway.restassured.response.ResponseBody;
              
              import org.apache.tika.exception.TikaException;
              import org.apache.tika.metadata.Metadata;
              import org.apache.tika.parser.AutoDetectParser;
              import org.apache.tika.parser.ParseContext;
              import org.apache.tika.sax.BodyContentHandler;
              import org.apache.tika.parser.Parser;
              import org.xml.sax.ContentHandler;
              import org.xml.sax.SAXException;
              
                          InputStream stream = response.asInputStream();
                          Parser parser = new AutoDetectParser(); // Should auto-detect!
                          ContentHandler handler = new BodyContentHandler();
                          Metadata metadata = new Metadata();
                          ParseContext context = new ParseContext();
              
                          try {
                              parser.parse(stream, handler, metadata, context);
                          } finally {
                              stream.close();
                          }
                          for (int i = 0; i < metadata.names().length; i++) {
                              String item = metadata.names()[i];
                              System.out.println(item + " -- " + metadata.get(item));
                          }
              
                          System.out.println("!!Printing pdf content: \n" +handler.toString());
                          System.out.println("content type: " + metadata.get(Metadata.CONTENT_TYPE));
              

              【讨论】:

                【解决方案12】:

                我也在我的应用程序中实现了类似的行为,没有失败。以下是我的代码版本,它可以正常工作。

                    byte[] getFileInBytes(String filename) {
                    File file  = new File(filename);
                    int length = (int)file.length();
                    byte[] bytes = new byte[length];
                    try {
                        BufferedInputStream reader = new BufferedInputStream(new 
                    FileInputStream(file));
                    reader.read(bytes, 0, length);
                    System.out.println(reader);
                    // setFile(bytes);
                
                    } catch (FileNotFoundException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                
                    return bytes;
                    }
                

                【讨论】:

                  【解决方案13】:
                  public String encodeFileToBase64Binary(String fileName)
                          throws IOException {
                          System.out.println("encodeFileToBase64Binary: "+ fileName);
                      File file = new File(fileName);
                      byte[] bytes = loadFile(file);
                      byte[] encoded = Base64.encodeBase64(bytes);
                      String encodedString = new String(encoded);
                      System.out.println("ARCHIVO B64: "+encodedString);
                  
                  
                      return encodedString;
                  }
                  
                  @SuppressWarnings("resource")
                  public static byte[] loadFile(File file) throws IOException {
                      InputStream is = new FileInputStream(file);
                  
                      long length = file.length();
                      if (length > Integer.MAX_VALUE) {
                          // File is too large
                      }
                      byte[] bytes = new byte[(int)length];
                  
                      int offset = 0;
                      int numRead = 0;
                      while (offset < bytes.length
                              && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
                          offset += numRead;
                      }
                  
                      if (offset < bytes.length) {
                          throw new IOException("Could not completely read file "+file.getName());
                      }
                  
                      is.close();
                      return bytes;
                  }
                  

                  【讨论】:

                  • 我认为提问者不需要base64转换。他使用toString 只是因为他不知道如何将文件读取到字节。
                  【解决方案14】:

                  PDF 可能包含二进制数据,当您执行 ToString 时,它可能会被破坏。 在我看来,你想要这个:

                          FileInputStream inputStream = new FileInputStream(sourcePath);
                  
                          int numberBytes = inputStream .available();
                          byte bytearray[] = new byte[numberBytes];
                  
                          inputStream .read(bytearray);
                  

                  【讨论】:

                  • 这是一种可怕的数据读取方式——请不要假设 available() 将包含流中的所有数据。
                  • @Jon - 附议。 available() 将(通常)返回可以立即读取而不会阻塞的字节数。它与文件中实际有多少数据无关..
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-02-14
                  • 2014-04-16
                  • 1970-01-01
                  • 2011-05-16
                  • 2011-07-02
                  • 2012-03-06
                  • 2014-01-09
                  相关资源
                  最近更新 更多