72

我在从 Internet 下载我的应用程序中的二进制文件(视频)时遇到问题。在 Quicktime 中,如果我直接下载它,它可以正常工作,但是通过我的应用程序它会变得一团糟(即使它们在文本编辑器中看起来完全一样)。这是一个例子:

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

6 回答 6

93

我不知道这是否是唯一的问题,但你有一个经典的 Java 故障:你没有指望 read()总是允许返回比你要求的字节少的事实。因此,您的读取可能会获得少于 1024 个字节,但您的写入始终会准确地写出 1024 个字节,可能包括来自前一个循环迭代的字节。

正确:

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

也许 Android 上更高延迟的网络或更小的 3G 数据包大小正在加剧这种影响?

于 2009-02-23T04:45:10.313 回答
29
new DefaultHttpClient().execute(new HttpGet("http://www.path.to/a.mp4?video"))
        .getEntity().writeTo(
                new FileOutputStream(new File(root,"Video.mp4")));
于 2011-05-12T15:04:30.133 回答
16

一个问题是您对缓冲区的读取。如果输入流的每次读取都不是 1024 的精确倍数,您将复制错误数据。采用:

byte[] buffer = new byte[1024];
int len1 = 0;
while ( (len1 = in.read(buffer)) != -1 ) {
  f.write(buffer,0, len1);
}
于 2009-02-23T04:43:42.830 回答
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.");
    } 
}
于 2010-12-10T06:13:42.483 回答
3

我根据之前对该线程的反馈修复了代码。我使用 eclipse 和多个大文件进行了测试。它工作正常。只需将其复制并粘贴到您的环境中,然后更改 http 路径和您希望将文件下载到的位置。

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

祝你好运 Alireza Aghamohammadi

于 2011-04-20T17:59:31.573 回答
2

只需使用 apache 的复制方法(Apache Commons IO)——使用 Java 的优势!

IOUtils.copy(is, os);

不要忘记在 finally 块中关闭流:

try{
      ...
} finally {
  IOUtils.closeQuietly(is);
  IOUtils.closeQuietly(os);
}
于 2011-04-20T10:41:03.010 回答