효율적으로 입력 스트림에서 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)
, wherea
isStringBuilder
는에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에서 String을 얻으려면 다음 메소드를 호출합니다.
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));
}
편집 : 실제로이 종류는 스틸 바이트와 모리스 페리 모두를 포함합니다.
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)
한 번에 한 줄의 텍스트를 읽고 해당 줄을 개별적으로 문자열에 추가하는 것은 각 줄을 추출하고 너무 많은 메소드 호출의 오버 헤드 모두에서 시간 소모적입니다.
I was able to get better performance by allocating a decent-sized byte array to hold the stream data, and which is iteratively replaced with a larger array when needed, and trying to read as much as the array could hold.
For some reason, Android repeatedly failed to download the entire file when the code used the InputStream returned by HTTPUrlConnection, so I had to resort to using both a BufferedReader and a hand-rolled timeout mechanism to ensure I would either get the whole file or cancel the transfer.
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: It turns out that if you don't need to have the content re-encoded (ie, you want the content AS IS) you shouldn't use any of the Reader subclasses. Just use the appropriate Stream subclass.
Replace the beginning of the preceding method with the corresponding lines of the following to speed it up an extra 2 to 3 times.
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];
If the file is long, you can optimize your code by appending to a StringBuilder instead of using a String concatenation for each line.
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);
To convert the InputStream to String we use the BufferedReader.readLine() method. We iterate until the BufferedReader return null which means there's no more data to read. Each line will appended to a StringBuilder and returned as 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();
}
}`
And finally from any class where you want to convert call the function
String dataString = Utils.convertStreamToString(in);
complete
I am use to read full data:
// 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
'Programing' 카테고리의 다른 글
네이티브 반응 :“다음”키보드 버튼을 누른 후 다음 TextInput을 선택하는 방법? (0) | 2020.06.14 |
---|---|
소문자를 대문자로 또는 그 반대로 변환하는 ^ = 32의 아이디어는 무엇입니까? (0) | 2020.06.14 |
Info.plist에서 iOS 9“fbauth2”가 누락되었습니다 (0) | 2020.06.14 |
bash 스크립트에서 소스를 사용할 때 '소스 : 찾을 수 없음'오류 표시 (0) | 2020.06.14 |
왜 Git이 지정된 파일을 무시하지 않습니까? (0) | 2020.06.14 |