【问题标题】:Java: Reading a pdf file from URL into Byte array/ByteBuffer in an appletJava:将 pdf 文件从 URL 读取到小程序中的字节数组/字节缓冲区中
【发布时间】:2010-10-12 20:00:18
【问题描述】:

我试图弄清楚为什么这个特殊的 sn-p 代码对我不起作用。我有一个小程序,它应该读取 .pdf 并使用 pdf-renderer 库显示它,但是由于某种原因,当我读取位于我的服务器上的 .pdf 文件时,它们最终会损坏。我已经通过再次写回文件来测试它。

我尝试在 IE 和 Firefox 中查看小程序,但出现了损坏的文件。有趣的是,当我尝试在 Safari(适用于 Windows)中查看小程序时,该文件实际上很好!我知道 JVM 可能会有所不同,但我仍然迷路了。我已经在 J​​ava 1.5 中编译。 JVM 是 1.6。读取文件的sn-p如下。

public static ByteBuffer getAsByteArray(URL url) throws IOException {
        ByteArrayOutputStream tmpOut = new ByteArrayOutputStream();

        URLConnection connection = url.openConnection();
        int contentLength = connection.getContentLength();
        InputStream in = url.openStream();
        byte[] buf = new byte[512];
        int len;
        while (true) {
            len = in.read(buf);
            if (len == -1) {
                break;
            }
            tmpOut.write(buf, 0, len);
        }
        tmpOut.close();
        ByteBuffer bb = ByteBuffer.wrap(tmpOut.toByteArray(), 0,
                                        tmpOut.size());
        //Lines below used to test if file is corrupt
        //FileOutputStream fos = new FileOutputStream("C:\\abc.pdf");
        //fos.write(tmpOut.toByteArray());
        return bb;
}

我一定是错过了什么,我一直在努力想弄清楚。任何帮助是极大的赞赏。谢谢。


编辑: 为了进一步澄清我的情况,我阅读之前的文件与 sn-p 和之后的区别在于,我在阅读后输出的文件比原来的要小得多。打开它们时,它们不会被识别为 .pdf 文件。没有抛出我忽略的异常,并且我尝试刷新无济于事。

这个 sn-p 在 Safari 中工作,这意味着文件被完整地读取,大小没有差异,并且可以用任何 .pdf 阅读器打开。在 IE 和 Firefox 中,文件最终总是被损坏,并且大小始终相同。

我监视了 len 变量(在读取 59kb 文件时),希望查看在每个循环中读取了多少字节。在 IE 和 Firefox 中,在 18kb 处,in.read(buf) 返回 -1,就好像文件已经结束一样。 Safari 不这样做。

我会坚持下去,我很感激到目前为止的所有建议。

【问题讨论】:

  • 当您说文件已损坏时,您究竟是什么意思?如果和原作比较,有什么不同?
  • 请回答 Eddie 问题的第二部分。另外,contentLength 的值是否正确?

标签: java pdf applet


【解决方案1】:

在关闭tmpOut 流之前,您是否尝试过flush() 以确保写出所有字节?

【讨论】:

    【解决方案2】:

    我以为我和你有同样的问题,但事实证明我的问题是我假设你总是得到完整的缓冲区,直到你什么都没得到。但你不认为。 网上的例子(例如java2s/tutorial)使用了一个BufferedInputStream。但这对我没有任何影响。

    你可以检查你是否真的在你的循环中得到了完整的文件。比问题出在 ByteArrayOutputStream 中。

    【讨论】:

      【解决方案3】:

      以防万一这些小改动产生影响,试试这个:

      public static ByteBuffer getAsByteArray(URL url) throws IOException {
          URLConnection connection = url.openConnection();
          // Since you get a URLConnection, use it to get the InputStream
          InputStream in = connection.getInputStream();
          // Now that the InputStream is open, get the content length
          int contentLength = connection.getContentLength();
      
          // To avoid having to resize the array over and over and over as
          // bytes are written to the array, provide an accurate estimate of
          // the ultimate size of the byte array
          ByteArrayOutputStream tmpOut;
          if (contentLength != -1) {
              tmpOut = new ByteArrayOutputStream(contentLength);
          } else {
              tmpOut = new ByteArrayOutputStream(16384); // Pick some appropriate size
          }
      
          byte[] buf = new byte[512];
          while (true) {
              int len = in.read(buf);
              if (len == -1) {
                  break;
              }
              tmpOut.write(buf, 0, len);
          }
          in.close();
          tmpOut.close(); // No effect, but good to do anyway to keep the metaphor alive
      
          byte[] array = tmpOut.toByteArray();
      
          //Lines below used to test if file is corrupt
          //FileOutputStream fos = new FileOutputStream("C:\\abc.pdf");
          //fos.write(array);
          //fos.close();
      
          return ByteBuffer.wrap(array);
      }
      

      如果您的应用程序仍在运行或突然终止,您忘记关闭 fos 可能会导致该文件变短。另外,我添加了创建具有适当初始大小的ByteArrayOutputStream。 (否则 Java 将不得不反复分配新数组并复制,分配新数组并复制,这很昂贵。)将值 16384 替换为更合适的值。 16k 对于 PDF 来说可能很小,但我不知道如何,但“平均”大小是您希望下载的。

      由于您使用了两次toByteArray()(即使其中一次在诊断代码中),所以我将其分配给了一个变量。最后,虽然它不应该有任何区别,但当您将 整个 数组包装在 ByteBuffer 中时,您只需要提供字节数组本身。提供偏移量0 和长度是多余的。

      请注意,如果您以这种方式下载 PDF 文件,请确保您的 JVM 以足够大的堆运行,以便您有足够的空间来存储您预期读取的最大文件大小的几倍.您使用的方法将整个文件保存在内存中,只要您负担得起该内存就可以。 :)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-12-04
        • 2015-07-26
        • 2020-09-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-29
        • 1970-01-01
        相关资源
        最近更新 更多