programing

입력 스트림에서 효율적으로 Android 읽기

prostudy 2022. 7. 7. 22:20
반응형

입력 스트림에서 효율적으로 Android 읽기

제가 만들고 있는 안드로이드 앱에 대해 웹사이트에 HTTP get 요청을 하고 있습니다.

DefaultHttpClient를 사용하고 HttpGet을 사용하여 요청을 발행하고 있습니다.엔티티 응답을 받고 여기서 페이지의 html을 가져오기 위한 InputStream 개체를 가져옵니다.

그 후, 다음과 같이 회신을 순환합니다.

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오브젝트가 추가되어 char 배열이 복사되지 않도록 합니다.고객의 경우 구현은 다음과 같습니다.

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 추가 , 가::

문자열 결과 = total.toString();

제가 더 잘 설명해 드릴게요.

  • a += b (오류)a = a + b서 ), 「」a ★★★★★★★★★★★★★★★★★」b스트링, 양쪽의 내용을 복사합니다. a ... b해 주세요).a누적된 데이터를 포함합니다. String를 반복할 때마다 이러한 복사를 수행합니다.
  • a.append(b)서, snowledge.a는 입니다.StringBuilder , " " "b<고객명> 님의 a따라서 반복할 때마다 누적된 문자열을 복사하지 않습니다.

스트림을 문자열로 변환하기 위해 내장된 메서드를 사용해 본 적이 있습니까?Apache Commons 라이브러리(org.apache.commons.io의 일부입니다.IOTils)

그러면 코드는 다음과 같습니다.

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 에서 다운로드할 수 있습니다.

Guava의 또 다른 가능성:

"Dependency: "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을 사용하고 있습니다.InputStream 이외에 charset을 인수로 설정할 수도 있습니다.

이건 어때?성능이 더 좋은 것 같습니다.

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

편집: 실제로 이것은 스틸바이트와 Maurice Perry의 양쪽 모두를 포함합니다.

Jaime Soriano의 답변보다 다소 빠를 수 있으며 Adrian의 답변의 멀티바이트 인코딩 문제가 없을 경우 다음과 같이 제안합니다.

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)

텍스트를 한 번에 한 줄씩 읽고 해당 행을 문자열에 개별적으로 추가하는 것은 각 행을 추출하는 데 시간과 많은 메서드 호출의 오버헤드가 소요됩니다.

스트림 데이터를 저장하는 적절한 크기의 바이트 어레이를 할당하고 필요할 때 큰 어레이로 반복적으로 대체하여 어레이가 유지할 수 있는 만큼 읽기를 시도함으로써 더 나은 성능을 얻을 수 있었습니다.

HTTPUrlConnection에서 반환된 InputStream을 코드가 사용했을 때 Android가 파일 전체를 다운로드하지 못했기 때문에 파일 전체를 가져오거나 전송을 취소하기 위해 BufferedReader와 핸드롤 타임아웃 메커니즘을 모두 사용해야 했습니다.

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

편집: 콘텐츠를 다시 인코딩할 필요가 없는 경우(즉, 콘텐츠를 그대로 사용할 필요가 있는 경우) Reader 서브클래스를 사용하지 않는 것이 좋습니다.적절한 Stream 서브클래스를 사용합니다.

앞의 방법의 선두를 다음의 대응하는 행으로 치환하고, 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];

파일이 긴 경우 각 줄에 String 연결을 사용하는 대신 String Builder에 추가함으로써 코드를 최적화할 수 있습니다.

    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으로 변환하려면 BufferedReader.readLine() 메서드를 사용합니다.BufferedReader가 null을 반환할 때까지 반복하면 읽을 데이터가 없어집니다.각 행은 String Builder에 추가되어 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);

이는 디스크에 저장된 파일에 적용되며 기본 크기가 없는 스트림에는 적용되지 않습니다.

언급URL : https://stackoverflow.com/questions/2492076/android-reading-from-an-input-stream-efficiently

반응형