HttpURLConnection считывает InputStream дважды


Я делаю запрос HTTP get к серверу через HttpURLConnection , и мне нужно прочитать ответ (InputStream) дважды: для регистрации и для разбора ответа. Возвращаемый InputStraem является экземпляром org.apache.harmony.luni.internal.net.www.protocol.http.ChunkedInputStream, который не поддерживает маркировку (is.markSupported() return false).

Поэтому я не могу mark() и reset() потоком и после записи ответа в журнал я не могу его разобрать. Конечно, я могу прочитать ответ один раз в String или что-то еще, записать их и позже проанализировать. Но когда я работаю с потоками, я избегаю потенциально OutOfMemomryError, поскольку потоки сделок с буферизации вместо меня.

Какое лучшее решение в данном случае сохранит преимущества использования потоков и поможет достичь желаемого результата: одновременной записи в лог и разбора ответа?

EDIT: решение с записью ответа во временный файл не подходит

3 4

3 ответа:

Я не уверен, что полностью понимаю, что вы хотели бы прочитать InputStream один раз (не совсем дважды, это немного нечисто ИМО, потому что что делать, если ошибка возникает только в потоке журнала, а не в потоке, который вы анализируете?) а потом просто войти и разобрать то же самое InputStream?

Если вышеописанное имеет место здесь псевдо, чтобы показать решение:

InputStream is=...;
byte[] bytes=new byte[1028];
while(is.read(bytes)!=-1) {
log(bytes); //call function to log
parse(bytes);//call function to parse
}

Еще лучше для одновременного ведения журнала и записи было бы создание нового Thread/Runnable для обоих методов запустите их и дождитесь их возвращения с помощью (thread.join();):

InputStream is=...;
byte[] bytes=new byte[1028];
while(is.read(bytes)!=-1) {
Thread t1=new Thread(new Runnable() {
        @Override
        public void run() {
          log(bytes); //call function to log
        }
    });
Thread t2=new Thread(new Runnable() {
        @Override
        public void run() {
           parse(bytes);//call function to parse
        }
    });
     t1.start();
     t2.start();
try {
     t1.join();
     t2.join();
    }catch(Exception ex) {
      ex.printStackTrace();
    }
}

Вам никогда не придется читать входной поток дважды. Регистрируйте его по мере чтения.

Если вы заранее не знаете потенциальный размер потока (или если он слишком велик, чтобы быть помещенным в String или byte[]), то я бы использовал InputStream из HttpURLConnection для ведения журнала (возможно, в отдельном файле, если вам нужно), и я бы использовал файл журнала для целей синтаксического анализа.

Это, вероятно, не самый эффективный способ дублирования InputStream, но, вероятно, один из самых безопасных способов запоминания.