Файл хорошо передается без буферизации, но частично передается во время буферизации

Я написал код, который передает байты с другого сервера на мой сервер, а затем записываю это содержимое в свой локальный файл. Он отлично работает, когда я использую метод read(), который не буферизует данные. Но когда я использую буферизацию (намерение состоит в том, что я считаю, что потоковая передача будет быстрее для больших файлов), я использую метод read(byte[]), и он получает только частичные данные во время потоковой передачи. Выкладываю код. Может ли кто-нибудь указать на ошибку или концепцию, которую мне не хватает.

Следующий код работает нормально. (без потоковой передачи)

    private void doViewDocument(HttpServletRequest request,
            HttpServletResponse response, DocumentServletService servletService) throws GEMException, MalformedURLException, ProtocolException, IOException {

        final String objectID = request.getParameter(PARAM_OBJECT_ID);

        LOGGER.info("For Viewing Document objectID received from Request == " + objectID);

        if (GEMSharedUtil.isValidObjectId(objectID)) {

            String ebesDocDownloadURL = servletService.getDocumentDownloadUrl(objectID);

            if (!GEMSharedUtil.isValidString(ebesDocDownloadURL)) {             
                //response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
                response.setHeader("ResponseStatus", "Not_OK");
                throw new GEMException();
            } else {
                HttpURLConnection con = null;
                BufferedInputStream bin = null;
                BufferedOutputStream bout = null;

                try {
                    con = (HttpURLConnection) new URL(ebesDocDownloadURL).openConnection();

                    WASSecurity.preauthenticateWithLTPACookie(con);
                    con.setRequestMethod(REQUEST_METHOD_GET);
                    con.setDoOutput(true); // Triggers POST but since we have set request method so it will override it
                    con.setDoInput(true);
                    con.setUseCaches(false);
                    con.setRequestProperty("Connection", "Keep-Alive");
                    con.setAllowUserInteraction(false);
                //  con.setRequestProperty("Content-Type",
                //  "application/octet-stream");

                    response.setBufferSize(1024);
                    response.setContentType(con.getContentType());
                    response.setContentLength(con.getContentLength());
                    response.setHeader("ResponseStatus", "OK");
                    response.setHeader("Content-Disposition", con
                            .getHeaderField("Content-Disposition"));

                    bin = new BufferedInputStream((InputStream)
                            con.getInputStream(), 1024);

                    bout = new BufferedOutputStream(
                            response.getOutputStream(), 1024);

                    byte[] byteRead = new byte[1024];


                    File file = new File("C:\\Documents and Settings\\weakStudent\\Desktop\\streamed\\testStream.pdf");

                    FileOutputStream fos = new FileOutputStream(file);

                    if(file.length() > 0) {
                        file.delete();
                    }
                    file.createNewFile();

                    BufferedOutputStream fbout = new BufferedOutputStream((OutputStream) fos);
                    int c;
                    while((c= bin.read()) != -1) {
                        bout.write(c);
                        fbout.write(c);
                    }
fos.close();
                    bout.flush();
                    fbout.flush();
                    fbout.close();
                    LOGGER.info("con.getResponseCode():" + con.getResponseCode());

                } finally {
                    try {
                        if (bout != null) {
                            bout.close();
                        }
                    } catch (IOException e) {
                        LOGGER.log(Level.SEVERE, e.getMessage(), e);
                        throw new RuntimeException(e);
                    } finally {
                        try {
                            if (bin != null) {
                                bin.close();
                            }
                        } catch (IOException e) {
                            LOGGER.log(Level.SEVERE, e.getMessage(), e);
                            throw new RuntimeException(e);
                        } finally {
                            if (con != null) {
                                con.disconnect();
                            }
                        }
                    }
                }
            }

        }   //if ends

    }

Теперь, если у меня есть следующий цикл while, он работает неправильно.

                while(bin.read(byteRead) != -1) {
                    bout.write(byteRead);
                    fbout.write(byteRead);
                }

Q2) Также хотелось бы знать, обязательно ли использовать BufferedInputStream/BufferedOutputStream для потоковой передачи. Например, если я использую следующий фрагмент кода, он работает

    BufferedInputStream bin = null;

    try {
        //in = request.getInputStream();        

        bin = new BufferedInputStream((InputStream) request
                .getInputStream(), 1024);

        int respcode = HttpURLConnection.HTTP_OK;
        con = createConnection(uploadURL, REQUEST_METHOD_POST);
        con.setRequestProperty("X-File-Name",fileName);

        conOut = con.getOutputStream();
        bout = new BufferedOutputStream(conOut);
        byte[] byteRead = new byte[1024];       

        while (bin.read(byteRead) != -1) {
            bout.write(byteRead);
        }
        bout.flush(); 
        respcode = con.getResponseCode();    

Но следующие потоки снова частично (здесь не используется BufferedInputStream)

    ServletInputStream in = null;

    try {
        in = request.getInputStream();      

        int respcode = HttpURLConnection.HTTP_OK;
        con = createConnection(uploadURL, REQUEST_METHOD_POST);
        con.setRequestProperty("X-File-Name",fileName);

        conOut = con.getOutputStream();
        bout = new BufferedOutputStream(conOut);
        byte[] byteRead = new byte[1024];       

        while (in.read(byteRead) != -1) {
            bout.write(byteRead);
        }
        bout.flush(); 
        respcode = con.getResponseCode();    

person abhihello123    schedule 12.07.2012    source источник
comment
close() каждый поток, который вы открываете. Вы не закрываете фос   -  person rizzz86    schedule 12.07.2012


Ответы (1)


А1. Вы отбрасываете количество прочитанных байтов, сообщая выходному потоку о необходимости записи всего содержимого буфера byteRead, который может содержать данные из предыдущего чтения

int bytesIn = -1;
while((bytesIn = bin.read(byteRead)) != -1) {
    bout.write(byteRead, 0, bytesIn);
    fbout.write(byteRead, 0, bytesIn);
}

ОБНОВЛЕНИЕ По сути, все ваши примеры страдают от одной и той же проблемы. Ваш буфер имеет длину n байтов, но чтение может возвращать от 0 до n байтов в буфере, вам нужно принять к сведению количество байтов, которое возвращает метод чтения, чтобы знать, сколько нужно записать

person MadProgrammer    schedule 12.07.2012
comment
Привет @user99, то, что ты говоришь, абсолютно правильно. Я пропустил это. Это означает, что если я, например, передаю документ размером 2048 байт, он будет работать правильно, даже если мой код содержит ошибки. Поскольку весь массив байтов будет записан, и предыдущих байтов не будет, что приведет к повреждению файла. Я прав ?? - person abhihello123; 12.07.2012
comment
Вам не нужно инициализировать bytesIn. - person user207421; 12.07.2012
comment
@weakstudent Это канонический способ копирования потока в Java. Запомните это. Это всегда работает. - person user207421; 12.07.2012
comment
Кроме того, почему часть 1 Q2) работает? Есть ли у вас какие-либо идеи. Он также имеет глючный код .. - person abhihello123; 12.07.2012
comment
@EJP, спасибо. Использовал стримы через много-много дней, так что забыл :P.. Не могли бы вы сказать мне, почему часть 1 из Q2) где, когда это не сделано должным образом. - person abhihello123; 12.07.2012
comment
@weakstudent Часть 1 вопроса 2 не работает, если только размер файла не кратен 1024. - person user207421; 12.07.2012
comment
@EJP, я экспериментировал с тем же документом. И это не кратно 1024. В любом случае лучше использовать только правильный код. Спасибо. - person abhihello123; 12.07.2012