2009-02-23 9 views
68

私のアプリでバイナリファイル(ビデオ)をインターネットからダウンロードする際に問題が発生しています。 Quicktimeでは、それを直接ダウンロードしてもうまく動作しますが、何らかの形で私のアプリを通して(テキストエディタではまったく同じに見えますが)うんざりしてしまいます。ここに例があります:Androidでバイナリファイルの問題をダウンロードする

URL u = new URL("http://www.path.to/a.mp4?video"); 
    HttpURLConnection c = (HttpURLConnection) u.openConnection(); 
    c.setRequestMethod("GET"); 
    c.setDoOutput(true); 
    c.connect(); 
    FileOutputStream f = new FileOutputStream(new File(root,"Video.mp4")); 


    InputStream in = c.getInputStream(); 

    byte[] buffer = new byte[1024]; 
    int len1 = 0; 
    while ((len1 = in.read(buffer)) > 0) { 
     f.write(buffer); 
    } 
    f.close(); 

答えて

91

それが唯一の問題だ場合、私は知りませんが、あなたがそこに従来のJavaのグリッチを持っている:あなたは(読み事実に数えていない)は、常にに許可されていますあなたが求めるものよりも少ないバイト数を返します。したがって、読み込みは1024バイト未満になる可能性がありますが、書き込みは前回のループ反復からのバイトを含む正確に1024バイトを常に書き出します。

正しい:

while ((len1 = in.read(buffer)) > 0) { 
     f.write(buffer,0, len1); 
} 

はおそらく、高いレイテンシーのネットワーキングやAndroid上の3Gの小さなパケットサイズが効果を悪化させていますか?

+4

なんて愚かな間違い...ありがとう!これは、チュートリアルを正しく読まないと起こることです。 –

+3

ありがとう...助けてくれました。 –

+0

バッファの初期化はどうですか?例外に対する保護はどうですか?リソースを解放するのはどうですか?私はそれが良いが、完全な答えではないと思う。他のより完全な答えがここにあります。 –

16

バッファーの読み取りが1つの問題です。入力ストリームのすべての読み込みが1024の倍数でない場合、不正なデータがコピーされます。用途:

byte[] buffer = new byte[1024]; 
int len1 = 0; 
while ((len1 = in.read(buffer)) != -1) { 
    f.write(buffer,0, len1); 
} 
+0

、あなたはlenは、LEN1はない意味ですか? –

+0

私はRy4anの例を見て、あなたがlen1を意味すると仮定します - ありがとう。 –

14
public class download extends Activity { 

    private static String fileName = "file.3gp"; 
    private static final String MY_URL = "Your download url goes here"; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 

     try { 
      URL url = new URL(MY_URL); 
      HttpURLConnection c = (HttpURLConnection) url.openConnection(); 
      c.setRequestMethod("GET"); 
      c.setDoOutput(true); 
      c.connect(); 

      String PATH = Environment.getExternalStorageDirectory() 
       + "/download/"; 
      Log.d("Abhan", "PATH: " + PATH); 
      File file = new File(PATH); 
      if(!file.exists()) { 
       file.mkdirs(); 
      } 
      File outputFile = new File(file, fileName); 
      FileOutputStream fos = new FileOutputStream(outputFile); 
      InputStream is = c.getInputStream(); 
      byte[] buffer = new byte[1024]; 
      int len1 = 0; 
      while ((len1 = is.read(buffer)) != -1) { 
       fos.write(buffer, 0, len1); 
      } 
      fos.flush(); 
      fos.close(); 
      is.close(); 
     } catch (IOException e) { 
      Log.e("Abhan", "Error: " + e); 
     } 
     Log.i("Abhan", "Check Your File."); 
    } 
} 
+0

この回答はうまくいきません。メインスレッド上のネットワーク接続は 'android.os.NetworkOnMainThreadException'を投げます。 – JBirdVegas

+0

@JBirdVegasメインスレッドでネットワーク関連の操作を実行しないでください。親切にワーカースレッドを作成します。 –

+0

try {} catchコードを実行するには、AsyncTask doInBackgroundを使用します。そこからsetDoOutput(true)を削除します。 – Nepster

2

Javaを使用する利点は、Apacheのコピー方法(Apache Commons IO)を使用するだけです。

IOUtils.copy(is, os); 

はfinallyブロック内のストリームを閉じることを忘れないでください:

try{ 
     ... 
} finally { 
    IOUtils.closeQuietly(is); 
    IOUtils.closeQuietly(os); 
} 
+2

また、川を渡ってはいけません。 –

+2

ファイルをダウンロードするだけの200kライブラリ..... –

4

私はこのスレッドで、以前のフィードバックに基づいてコードを修正しました。私はeclipseと複数の大きなファイルを使ってテストしました。それは正常に動作しています。これをコピーして自分の環境に貼り付け、httpパスとファイルをダウンロードしたい場所を変更するだけです。 4行目で

try { 
    //this is the file you want to download from the remote server 
    String path ="http://localhost:8080/somefile.zip"; 
    //this is the name of the local file you will create 
    String targetFileName 
     boolean eof = false; 
    URL u = new URL(path); 
    HttpURLConnection c = (HttpURLConnection) u.openConnection(); 
    c.setRequestMethod("GET"); 
    c.setDoOutput(true); 
    c.connect(); 
    FileOutputStream f = new FileOutputStream(new File("c:\\junk\\"+targetFileName)); 
     InputStream in = c.getInputStream(); 
     byte[] buffer = new byte[1024]; 
     int len1 = 0; 
     while ((len1 = in.read(buffer)) > 0) { 
     f.write(buffer,0, len1); 
       } 
    f.close(); 
    } catch (MalformedURLException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
    } catch (ProtocolException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
    } catch (FileNotFoundException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
    } catch (IOException e) { 
    // TODO Auto-generated catch block 
    e.printStackTrace(); 
} 

幸運 アリレザAghamohammadi

+0

このようにして、同じファイルがダウンロードされます。ファイルが既にダウンロードされている場合は、アラートが表示されますか? – Loshi

+0

setDoOutput(true)を削除します。コード – Nepster

28
new DefaultHttpClient().execute(new HttpGet("http://www.path.to/a.mp4?video")) 
     .getEntity().writeTo(
       new FileOutputStream(new File(root,"Video.mp4"))); 
+3

からワンラインソリューション。ニース – Santhosh

+1

私は1行のソリューションも好きです。ただし、ファイルに書き込む前にエンティティをチェックする必要があります。そうしないと、ダウンロードに問題があってもファイルが作成されます。次回は、破損したファイルを開こうとするかもしれません。 – thanhbinh84

+0

ダウンロードしたファイルの名前を元のファイル名と同じようにするにはどうすればよいですか? –

関連する問題