Вопрос

Я делаю HTTP-запрос на веб-сайт для приложения для Android, которое я создаю.

Я использую DefaultHttpClient и HttpGet для выдачи запроса.Я получаю ответ объекта и из него получаю объект InputStream для получения HTML-кода страницы.

Затем я просматриваю ответ, делая следующее:

BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
String x = "";
x = r.readLine();
String total = "";

while(x!= null){
total += x;
x = r.readLine();
}

Однако это ужасно медленно.

Это неэффективно?Я не загружаю большую веб-страницу – www.cokezone.co.uk поэтому размер файла не большой.Есть лучший способ сделать это?

Спасибо

Энди

Это было полезно?

Решение

Проблема в вашем коде в том, что он создает много тяжелых String Объекты, копируя их содержимое и выполняя операции на них. Вместо этого вы должны использовать StringBuilder Чтобы не создавать новые String Объекты в каждом добавлении и избегать копирования массивов ЧАР. Реализация для вашего дела будет чем -то вроде этого:

BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder total = new StringBuilder();
for (String line; (line = r.readLine()) != null; ) {
    total.append(line).append('\n');
}

Теперь вы можете использовать total не преобразуя его в String, но если вам нужен результат как String, просто добавьте:

String result = total.toString ();

Я постараюсь объяснить это лучше ...

  • a += b (или же a = a + b), куда a а также b струны, копируют содержимое оба a а также b к новому объекту (обратите внимание, что вы также копируете a, который содержит накоплен String), и вы делаете эти копии на каждой итерации.
  • a.append(b), куда a это StringBuilder, напрямую добавляет b содержимое a, чтобы вы не копировали накопленную строку на каждой итерации.

Другие советы

Вы пробовали встроенный метод для преобразования потока в строку? Это часть библиотеки Apache Commons (org.apache.commons.io.ioutils).

Тогда ваш код будет этой строкой:

String total = IOUtils.toString(inputStream);

Документацию для этого можно найти здесь:http://commons.apache.org/io/api-1.4/org/apache/commons/io/ioutils.html#tostring%28java.io.inputstream%29

Библиотека Apache Commons IO может быть загружена отсюда:http://commons.apache.org/io/download_io.cgi

Еще одна возможность с гуавой:

Зависимость: compile 'com.google.guava:guava:11.0.2'

import com.google.common.io.ByteStreams;
...

String total = new String(ByteStreams.toByteArray(inputStream ));

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

public static String getStringFromInputStream(InputStream stream) throws IOException
{
    int n = 0;
    char[] buffer = new char[1024 * 4];
    InputStreamReader reader = new InputStreamReader(stream, "UTF8");
    StringWriter writer = new StringWriter();
    while (-1 != (n = reader.read(buffer))) writer.write(buffer, 0, n);
    return writer.toString();
}

Я всегда использую UTF-8. Вы можете, конечно, установить Charset в качестве аргумента, кроме InputStream.

Что насчет этого. Кажется, дает лучшую производительность.

byte[] bytes = new byte[1000];

StringBuilder x = new StringBuilder();

int numRead = 0;
while ((numRead = is.read(bytes)) >= 0) {
    x.append(new String(bytes, 0, numRead));
}

РЕДАКТИРОВАТЬ: На самом деле такого рода охватывает как Steelbytes, так и Maurice Perry's

Возможно, несколько быстрее, чем ответ Хайме Сориано, и без проблем с мультибайтовым кодированием ответа Адриана, я полагаю:

File file = new File("/tmp/myfile");
try {
    FileInputStream stream = new FileInputStream(file);

    int count;
    byte[] buffer = new byte[1024];
    ByteArrayOutputStream byteStream =
        new ByteArrayOutputStream(stream.available());

    while (true) {
        count = stream.read(buffer);
        if (count <= 0)
            break;
        byteStream.write(buffer, 0, count);
    }

    String string = byteStream.toString();
    System.out.format("%d bytes: \"%s\"%n", string.length(), string);
} catch (IOException e) {
    e.printStackTrace();
}

Возможно, а затем прочитайте «по одной строке за раз» и присоединяйтесь к струнам, попробуйте «прочитать все доступные», чтобы избежать сканирования на конец линии, а также избежать строковых соединений.

т.е. InputStream.available() а также InputStream.read(byte[] b), int offset, int length)

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

Я смог добиться лучшей производительности, выделяя байтологический массив приличного размера для хранения данных потока, и который итеративно заменяется большим массивом, когда это необходимо, и пытаясь прочитать столько, сколько массив.

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

private static  final   int         kBufferExpansionSize        = 32 * 1024;
private static  final   int         kBufferInitialSize          = kBufferExpansionSize;
private static  final   int         kMillisecondsFactor         = 1000;
private static  final   int         kNetworkActionPeriod        = 12 * kMillisecondsFactor;

private String loadContentsOfReader(Reader aReader)
{
    BufferedReader  br = null;
    char[]          array = new char[kBufferInitialSize];
    int             bytesRead;
    int             totalLength = 0;
    String          resourceContent = "";
    long            stopTime;
    long            nowTime;

    try
    {
        br = new BufferedReader(aReader);

        nowTime = System.nanoTime();
        stopTime = nowTime + ((long)kNetworkActionPeriod * kMillisecondsFactor * kMillisecondsFactor);
        while(((bytesRead = br.read(array, totalLength, array.length - totalLength)) != -1)
        && (nowTime < stopTime))
        {
            totalLength += bytesRead;
            if(totalLength == array.length)
                array = Arrays.copyOf(array, array.length + kBufferExpansionSize);
            nowTime = System.nanoTime();
        }

        if(bytesRead == -1)
            resourceContent = new String(array, 0, totalLength);
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }

    try
    {
        if(br != null)
            br.close();
    }
    catch(IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

РЕДАКТИРОВАТЬ: Оказывается, если вам не нужно перекодировать контент (т.е. вам нужен контент КАК ЕСТЬ) Вы не должны использовать ни одного из подклассов читателя. Просто используйте соответствующий подкласс потока.

Замените начало предыдущего метода соответствующими линиями следующего, чтобы ускорить его дополнительные от 2 до 3 раза.

String  loadContentsFromStream(Stream aStream)
{
    BufferedInputStream br = null;
    byte[]              array;
    int                 bytesRead;
    int                 totalLength = 0;
    String              resourceContent;
    long                stopTime;
    long                nowTime;

    resourceContent = "";
    try
    {
        br = new BufferedInputStream(aStream);
        array = new byte[kBufferInitialSize];

Если файл длинный, вы можете оптимизировать свой код, добавив к StringBuilder вместо использования строковой конкатенации для каждой строки.

    byte[] buffer = new byte[1024];  // buffer store for the stream
    int bytes; // bytes returned from read()

    // Keep listening to the InputStream until an exception occurs
    while (true) {
        try {
            // Read from the InputStream
            bytes = mmInStream.read(buffer);

            String TOKEN_ = new String(buffer, "UTF-8");

            String xx = TOKEN_.substring(0, bytes);

Чтобы преобразовать InputStream в String, мы используем БуфередЧтение.readLine() метод.Мы повторяем до тех пор, пока БуферизованныйReader верните ноль, что означает, что больше нет данных для чтения.Каждая строка будет добавлена ​​к Строитель строк и вернулся как String.

 public static String convertStreamToString(InputStream is) {

        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();

        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
}`

И, наконец, из любого класса, в который вы хотите преобразовать, вызовите функцию

String dataString = Utils.convertStreamToString(in);

полный

Я использую для чтения полных данных:

// inputStream is one instance InputStream
byte[] data = new byte[inputStream.available()];
inputStream.read(data);
String dataString = new String(data);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top