Массив байтов в файл в java без перезаписи,

Код ниже получает массив байтов из HTTP-запроса и сохраняет его в bytes[], окончательные данные будут сохранены в message[].

Я проверяю, содержит ли он заголовок, преобразуя его в String[]. Если это так, я читаю некоторую информацию из заголовка, а затем вырезаю ее, сохраняя байты после заголовка в message[].

Затем я пытаюсь вывести message[] в файл с помощью FileOutputStream, и он немного работает, но сохраняет только 10 КБ информации, одну итерацию цикла while (кажется, перезаписывает), и если я устанавливаю FileOutputStream(file, true) на добавьте информацию, она работает... один раз, затем файл просто добавляется в следующий раз, когда я его запускаю, а это не то, чего я хочу. Как мне записать в один и тот же файл несколько фрагментов байтов на каждой итерации, но при этом полностью перезаписать файл, если я снова запущу программу?

byte bytes[] = new byte[(10*1024)];
            while (dis.read(bytes) > 0)
            {
                //Set all the bytes to the message
                byte message[] = bytes;
                String string = new String(bytes, "UTF-8");

                //Does bytes contain header?
                if (string.contains("\r\n\r\n")){
                    String theByteString[] = string.split("\r\n\r\n");
                    String theHeader = theByteString[0];
                    String[] lmTemp = theHeader.split("Last-Modified: ");
                    String[] lm = lmTemp[1].split("\r\n");
                    String lastModified = lm[0];
                    //Cut off the header and save the rest of the data after it
                    message = theByteString[1].getBytes("UTF-8");

                    //cache
                    hm.put(url, lastModified);
                }

                //Output message[] to file.
                File f = new File(hostName + path);
                f.getParentFile().mkdirs(); 
                f.createNewFile();
                try (FileOutputStream fos = new FileOutputStream(f)) {
                    fos.write(message);
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }

            }
        }

person john stamos    schedule 14.10.2016    source источник


Ответы (3)


Вы открываете новый FileOutputStream на каждой итерации цикла. Не делай этого. Откройте его вне цикла, затем зациклите и напишите, как делаете, затем закройте в конце цикла. (Если вы используете оператор try-with-resources с вашим циклом while внутри него, это будет нормально.)

Однако это только часть проблемы — вы также делаете все остальное на каждой итерации цикла, включая проверку заголовков. Это будет настоящей проблемой, если массив байтов, который вы читаете, содержит часть набора заголовков или даже часть разделителя заголовков.

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

По сути, вам нужно либо прочитать целый ответ в массив байтов для начала — что легко сделать, но потенциально неэффективно в памяти — или принять тот факт, что вы имеете дело с потоком, и напишите более сложный код для обнаружения конца заголовков.

Однако лучше, IMO, использовать HTTP-библиотеку, которая уже понимает всю эту обработку заголовков, так что вам не нужно делать это самостоятельно. Если вы сами не пишете низкоуровневую HTTP-библиотеку, вам не следует иметь дело с низкоуровневыми деталями HTTP, вам следует полагаться на хорошую библиотеку.

person Jon Skeet    schedule 14.10.2016
comment
Обновлено с вашими предложениями. Я просто жду ответа от EJP о том, как установить строку. - person john stamos; 15.10.2016

Откройте файл перед циклом.

NB вам нужно сохранить результат read() в переменной и передать эту переменную new String() в качестве длины. В противном случае вы конвертируете мусор в буфере за пределы того, что было фактически прочитано.

person user207421    schedule 14.10.2016
comment
В мою новую строку байтов? Как установить длину строки? - person john stamos; 15.10.2016
comment
@johnstamos: вы бы вызвали конструктор строк, взяв его: new String(bytes, 0, length, StandardCharsets.UTF_8). - person Jon Skeet; 15.10.2016
comment
Это только часть ответа и не очень полезная, поскольку обработка заголовков при каждом чтении из inputStream также может привести к записи мусора в файл. - person Krzysztof Cichocki; 15.10.2016

Есть проблема с чтением данных - вы читаете только часть ответа (поскольку на тот момент вам еще не все данные были переданы) - так что, очевидно, вы пишете только эту часть.

проверьте этот ответ, чтобы узнать, как читать полные данные из InputStream:

Преобразование InputStream в массив байтов в Java

person Krzysztof Cichocki    schedule 14.10.2016
comment
while (dis.read(bytes) > 0) похоже, что он читает мне все данные. Он просто читает его несколькими фрагментами и повторно открывает файл для вывода на каждой итерации. - person Jon Skeet; 14.10.2016
comment
Но посмотрев еще раз, это еще не все, я согласен. - person Jon Skeet; 15.10.2016
comment
@Jon Skeet хорошо :) извините за -1, но поскольку вы удалили свой пост, я не могу его отменить, я проголосую в следующий раз, когда мы встретимся здесь, если вы напишите что-нибудь полезное - я уверен, что вы это сделаете :) . Ваше здоровье! - person Krzysztof Cichocki; 15.10.2016
comment
Я удалил его, чтобы дать более полный ответ. Скоро будем восстанавливать. (сделано сейчас...) - person Jon Skeet; 15.10.2016