作成しているAndroidアプリケーションのWebサイトに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
は文字列で、botha
andb
を新しいオブジェクトにコピーします(accumulateda
を含むString
もコピーしていることに注意してください)各反復でコピーします。a.append(b)
(a
はStringBuilder
である)は、b
の内容をa
に直接追加するため、各反復で蓄積された文字列をコピーしません。ストリームを文字列に変換する組み込みメソッドを試しましたか?これは、Apache Commonsライブラリ(org.Apache.commons.io.IOUtils)の一部です。
その場合、コードは次の1行になります。
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を使用します。もちろん、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();
}
むしろ、「一度に1行」を読んで文字列を結合し、「行末のスキャンを回避し、文字列の結合を回避するために、「利用可能なすべてを読み取る」ことを試みてください。
すなわち、InputStream.available()
およびInputStream.read(byte[] b), int offset, int length)
一度に1行のテキストを読み取り、その行を個別に文字列に追加することは、各行の抽出と非常に多くのメソッド呼び出しのオーバーヘッドの両方に時間がかかります。
適切なサイズのバイト配列を割り当ててストリームデータを保持し、必要に応じて繰り返し大きな配列に置き換えて、配列が保持できる限りの読み取りを試みることで、パフォーマンスを向上させることができました。
何らかの理由で、コードが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();
}
}
編集:コンテンツを再エンコードする必要がない場合(つまり、コンテンツが必要な場合IS)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];
ファイルが長い場合は、各行に文字列連結を使用する代わりに、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に変換するには、BufferedReader.readLine()メソッドを使用します。 BufferedReaderがnullを返すまで繰り返します。これは、読み込むデータがもうないことを意味します。各行はStringBuilderに追加され、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);
完全