Pregunta

Estoy haciendo una solicitud get HTTP a un sitio web para una aplicación de android que estoy haciendo.

Estoy usando un DefaultHttpClient y el uso de HttpGet para la emisión de la solicitud.Puedo obtener la respuesta de la entidad y de esta obtener un objeto InputStream para obtener el código html de la página.

Yo, a continuación, ciclo a través de la respuesta haciendo de la siguiente manera:

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

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

Sin embargo, esto es horriblemente lento.

Es este ineficiente?No estoy de carga, una gran página web - www.cokezone.co.uk por lo que el tamaño del archivo no es grande.Hay una manera mejor de hacer esto?

Gracias

Andy

¿Fue útil?

Solución

El problema en tu código es que es la creación de un montón de pesados String los objetos, con copia de sus contenidos y la realización de operaciones sobre ellos.En su lugar, debe utilizar StringBuilder para evitar la creación de nuevas String los objetos en cada anexar y para evitar la copia de el char matrices.La aplicación para tu caso sería algo como esto:

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

Ahora puede utilizar total sin convertirlo a String, pero si usted necesita el resultado como un String, simplemente añadir:

String resultado = total.toString();

Voy a tratar de explicarlo mejor...

  • a += b (o a = a + b), donde a y b son Cadenas de texto, copia el contenido de ambos a y b a un nuevo objeto (tenga en cuenta que usted está copiando a, que contiene el acumulado String), y que están haciendo esas copias en cada iteración.
  • a.append(b), donde a es un StringBuilder, directamente anexa b contenido a, por lo que no copia el acumulado de cadena en cada iteración.

Otros consejos

¿Usted ha intentado el construido en el método para convertir una corriente a una cadena? Es parte de la biblioteca Apache Commons (org.apache.commons.io.IOUtils).

A continuación, el código sería así de una línea:

String total = IOUtils.toString(inputStream);

La documentación de que se puede encontrar aquí: http : //commons.apache.org/io/api-1.4/org/apache/commons/io/IOUtils.html#toString%28java.io.InputStream%29

La biblioteca de Apache Commons IO se puede descargar desde aquí: http://commons.apache.org/io/download_io.cgi

Otra posibilidad con la guayaba:

dependencia: compile 'com.google.guava:guava:11.0.2'

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

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

Creo que esto es lo suficientemente eficiente ... para obtener una cadena de un InputStream, que yo llamaría el método siguiente:

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

Siempre use UTF-8. Podría, por supuesto, set de juego de caracteres como argumento, además de InputStream.

¿Qué hay de esto. Parece dar un mejor rendimiento.

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

Edit: En realidad este tipo de Steelbytes abarca tanto y de Maurice Perry

Posiblemente algo más rápido que la respuesta de Jaime Soriano, y sin la codificación multi-byte problemas de respuesta de Adrian, sugiero:

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

Tal vez en lugar de leer 'una línea a la vez' y unirse a las cuerdas, trate de 'leer todos disponibles' a fin de evitar la exploración de fin de línea, y también para evitar la cadena se une.

es decir, InputStream.available() y InputStream.read(byte[] b), int offset, int length)

Lectura una línea de texto a la vez, y anexar dicha línea en una cadena individual es mucho tiempo tanto en la extracción de cada línea y la sobrecarga de tantas invocaciones de métodos.

Yo era capaz de conseguir un mejor rendimiento mediante la asignación de una matriz de bytes de tamaño decente para mantener los datos del flujo, y que está iterativa reemplazada con una matriz más grande cuando sea necesario, y tratando de leer tanto como la matriz podía sostener.

Por alguna razón, Android fracasó varias veces para descargar el archivo completo cuando el código utiliza el InputStream devuelto por HttpURLConnection, así que tuve que recurrir al uso tanto de un BufferedReader y un mecanismo de tiempo de espera de enrollado a mano para asegurar Me gustaría obtener ya sea la totalidad archivo o cancelar la transferencia.

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

EDIT: Resulta que si usted no necesita tener el contenido re-codificada (es decir, desea que el contenido de COMO ES ) que no debería utilizar cualquiera de las subclases del lector. Sólo tiene que utilizar la subclase corriente adecuada.

Reemplazar el principio del método anterior con las líneas correspondientes de la siguiente para acelerarlo un adicionales 2 a 3 veces .

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

Si el archivo es largo, puede optimizar su código añadiendo a un StringBuilder en lugar de utilizar una concatenación de cadenas para cada línea.

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

Para convertir el InputStream a la Cadena que se utiliza el Clases bufferedreader.readLine() método.Repetimos hasta que el Clases bufferedreader retornar null, lo que significa que no hay más datos que leer.Cada línea se anexa a un StringBuilder y se devuelve como una Cadena.

 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();
    }
}`

Y, finalmente, de cualquier clase en la que desea convertir llamar a la función

String dataString = Utils.convertStreamToString(in);

completa

Soy uso para leer los datos completos:

// inputStream is one instance InputStream
byte[] data = new byte[inputStream.available()];
inputStream.read(data);
String dataString = new String(data);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top