Java: чтение файла PDF из URL в массив байтов / ByteBuffer в апплете - PullRequest
7 голосов
/ 12 марта 2009

Я пытаюсь выяснить, почему этот фрагмент кода не работает для меня. У меня есть апплет, который должен читать .pdf и отображать его с помощью библиотеки pdf-рендерера, но по какой-то причине, когда я читаю в файлах .pdf, которые находятся на моем сервере, они оказываются поврежденными. Я проверил это, записав файлы обратно.

Я попытался просмотреть апплет в IE и Firefox, и появились поврежденные файлы. Самое смешное, что когда я пытаюсь просмотреть апплет в Safari (для Windows), файл на самом деле в порядке! Я понимаю, что JVM может быть другим, но я все еще потерялся. Я скомпилировал в Java 1.5. JVM 1.6. Фрагмент, который читает файл ниже.

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;
}

Я, должно быть, что-то упустил, и я бился головой, пытаясь понять это. Любая помощь очень ценится. Спасибо.


Edit: Для дальнейшего разъяснения моей ситуации, разница в файле до того, как я прочитал его, затем с помощью фрагмента и после, состоит в том, что те, которые я выводил после чтения, значительно меньше, чем они были изначально. При их открытии они не распознаются как файлы .pdf. Нет никаких исключений, которые я игнорирую, и я попытался промыть безрезультатно.

Этот фрагмент работает в Safari, что означает, что файлы читаются полностью, без разницы в размере, и могут быть открыты с помощью любого читателя .pdf. В IE и Firefox файлы всегда оказываются поврежденными, постоянно одинакового меньшего размера.

Я контролировал переменную len (при чтении файла 59 КБ), надеясь увидеть, сколько байтов считывается в каждом цикле. В IE и Firefox, в 18 КБ, in.read (buf) возвращает -1, как если бы файл закончился. Safari не делает этого.

Я буду продолжать, и я ценю все предложения до сих пор.

Ответы [ 3 ]

11 голосов
/ 12 марта 2009

На всякий случай, если эти небольшие изменения имеют значение, попробуйте это:

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 работает с достаточно большой кучей, чтобы у вас было достаточно места в несколько раз больше, чем вы ожидаете прочитать. Метод, который вы используете, сохраняет весь файл в памяти, и это нормально, пока вы можете себе позволить эту память. :)

0 голосов
/ 03 мая 2010

Я думал, что у меня та же проблема, что и у вас, но оказалось, что моя проблема в том, что я предполагал, что вы всегда получаете полный буфер, пока не получите ничего. Но вы не предполагаете это. Примеры в сети (например, java2s / tutorial ) используют BufferedInputStream. Но это не имеет никакого значения для меня.

Вы можете проверить, действительно ли вы получили полный файл в цикле. Чем проблема будет в ByteArrayOutputStream.

0 голосов
/ 12 марта 2009

Пробовали ли вы flush() перед закрытием потока tmpOut, чтобы обеспечить запись всех байтов?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...