2011-07-21 19 views
1

状況:ArrayList<String>には画像へのリンクが多数含まれています(http:/www.foo.com/bar/image1.jpg、http:/www.foo.com/bar/image2 .PNG、...など)より効率的にURLから画像をダウンロードする

私はそれらを一つずつダウンロードするために、コードの作業部分を発見した:

public void run() { 
     try { 
      int counter = 1; 
      for (String image : imagesList) { 
       controller.setDownloadStatusTextArea("Downloading image " + counter + " of " + imagesList.size()); 
       URL u = new URL(image); 
       URLConnection uc = u.openConnection(); 
       String contentType = uc.getContentType(); 
       int contentLength = uc.getContentLength(); 
       InputStream raw = uc.getInputStream(); 
       InputStream in = new BufferedInputStream(raw); 
       byte[] data = new byte[contentLength]; 
       int bytesRead; 
       int offset = 0; 
       while (offset < contentLength) { 
        bytesRead = in.read(data, offset, data.length - offset); 
        if (bytesRead == -1) 
         break; 
        offset += bytesRead; 
       } 
       in.close(); 
       if (offset != contentLength) { 
        throw new IOException("Only read " + offset + " bytes; Expected " + contentLength + " bytes"); 
       } 
       String[] tmp = image.split("/"); 
       String filename = tmp[tmp.length - 1]; 
       FileOutputStream out = new FileOutputStream(filename); 
       out.write(data); 
       out.flush(); 
       out.close(); 
       counter++; 
      } 
      controller.setDownloadStatusTextArea("Download complete"); 
     } catch (Exception ex) { 
      controller.setDownloadStatusTextArea("Download failed"); 
     } 
    } 

これは私がJavaでこのような何かをやって初めてですそして、私はこのコードがforループの外でたくさんの変数を動かすことによってはるかに効率的であると感じています。しかし、機能性やパフォーマンスに悪影響を及ぼすことなく、どちらが安全に外に移動できるかはわかりません(どちらも否定的または肯定的な方法で)。このような状況の洞察は非常に高く評価されます。 また、ファイルのダウンロード先を指定することはできますか?今はプロジェクトフォルダに表示されているので、ユーザは自分のダウンロードフォルダを変更できるようにしたいと思う。

ありがとうございます。

答えて

4

このコードは、はるかに時間効率を上げることはできません。

このように考えてみましょう。最後の不要なオペコードをすべて研磨しても、JVMがこのコード部分を実行するのにかかる時間はまったく重要ではありません。実際の遅延は、データがネットワークを介して到着するのを待つことになります。

もっとスペース効率がよいかもしれませんが、それは必要ではないと思います。

編集:あなたはスレッドを使用して、複数の画像を同時にダウンロードされる何ができますか。しかし、上のコードが複雑に見える場合、私はそれに反対します:言語の周りに自分の道を学ぶためにもう少し時間をかけてください。

+0

だから、私が繰り返し使うたびに私が使用するオブジェクトを作成して破壊することは本当に重要ではありませんか? – Matthias

+0

問題になる可能性のあるオブジェクトはアレイだけです。私が間違っていないと、Javaはその配列をゼロ初期化します。これは大きなファイルにとっては煩わしいことがあります。私はそれがあなたの場合だとは思わない。 – slezica

+1

必要になる前に最適化しないでください。このコードが後で問題を引き起こし、もっと速くしたいのであれば、バッファ(配列)をループ外に移動し、快適な数でサイズを修正し、いっぱいになるたびにファイルに書き込むことができます。 – slezica

1

ユーザーがディレクトリを選択できるようにするSwingアプリケーションでは、setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY)JFileChooserをインスタンス化します。

各繰り返しで正しく初期化されているかぎり、すべての変数宣言をループ外に移動できます。あなたは、ファイルをダウンロードして保存するのにかかる時間に比べて、多くの時間を節約しません。

+0

スイングアプリケーションです。そして、心配しないで、すべてのバリデーションがどこかで起こっています。 – Matthias

+0

私の答えを更新しました。 – Paul

+0

ありがとうございます。私はJFileChooserについて知っていましたが、DIRECTORIES_ONLYについては知りませんでした。そして、ちょうど私がちょうど私が別の場所にファイルを保存するためにファイル名にパスを追加する必要があります:) – Matthias

2

イメージ全体にバイト配列を割り当てる必要はありません。小さいバッファのみが必要です。 8kB。 次に、接続から8 KBを読み取り、FileOutputStreamにループで書き込みます。

コード全体を簡単にする(ループを蹴る)には、たとえば次のようなコードを使用できます。 Commons-IO (全体のjavadocを表示するには、「フレーム」リンクをクリックしてください)。

+0

よかった、チップのおかげで。それは実際にはそれほど大きな違いを作りますか? – Matthias

+0

@Matthias:JVMのヒープメモリよりも大きい可能性のあるイメージをダウンロードしている場合は、間違いなく違いがあります。さもなければ、エンドユーザは 'OutOfMemoryError'に直面します。 – BalusC

+0

私は公共のイメージボードからそれらをダウンロードしていますが、どれも非常に大きくはありません。 – Matthias

関連する問題