Java Android下载二进制文件问题
我从internet下载应用程序中的二进制文件(视频)时遇到问题。在Quicktime中,如果我直接下载它,它可以正常工作,但通过我的应用程序,它会变得一团糟(即使它们在文本编辑器中看起来完全相同)。以下是一个例子:Java Android下载二进制文件问题,java,android,download,httpurlconnection,fileoutputstream,Java,Android,Download,Httpurlconnection,Fileoutputstream,我从internet下载应用程序中的二进制文件(视频)时遇到问题。在Quicktime中,如果我直接下载它,它可以正常工作,但通过我的应用程序,它会变得一团糟(即使它们在文本编辑器中看起来完全相同)。以下是一个例子: URL u = new URL("http://www.path.to/a.mp4?video"); HttpURLConnection c = (HttpURLConnection) u.openConnection(); c.setRequestMeth
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();
一个问题是缓冲区的读取。如果输入流的每次读取不是1024的精确倍数,则会复制坏数据。使用:
byte[] buffer = new byte[1024];
int len1 = 0;
while ( (len1 = in.read(buffer)) != -1 ) {
f.write(buffer,0, len1);
}
我不知道这是否是唯一的问题,但这里有一个典型的Java故障:read()总是被允许返回比您要求的更少的字节。因此,您的读取可以得到少于1024个字节,但您的写入总是准确地写出1024个字节,可能包括来自上一个循环迭代的字节 更正为:
while ( (len1 = in.read(buffer)) > 0 ) {
f.write(buffer,0, len1);
}
也许Android上3G的延迟网络更高或数据包更小会加剧这种影响?只需使用apache的复制方法()——使用Java的优势
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.");
}
}
IOUtils.copy(is, os);
不要忘记关闭finally块中的流:
try{
...
} finally {
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(os);
}
我修复了基于此线程先前反馈的代码。我使用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多么愚蠢的错误。。。谢谢如果您没有正确阅读教程,就会发生这种情况:)初始化缓冲区怎么样?如何防止异常?释放资源怎么样?我认为这是一个很好的答案,但不是一个完整的答案。这里还有其他更完整的答案。我想指出,>0测试可能会过早地结束阅读。文档说明在流的末尾返回-1。@Clint:true,但文档还说明(从java 5开始),除非'len'参数为0,否则不能返回0(如果没有可用的字节(…)-1,否则至少读取一个字节)。在java 2中,0可以返回。你知道你是耶稣吗?你刚刚把我从地狱里救了出来:)而且也不要跨流。这样,将下载相同的文件。我的意思是,如果文件已经下载,它会发出警报吗?我也喜欢单线解决方案。但是,您应该在写入文件之前检查实体,否则即使下载有问题,也会创建文件。因此,下一次,您可能会尝试打开一个损坏的文件。如何动态地将下载的文件命名为与原始文件名相同的名称?使用该方法,您需要添加一些内容,例如获取包含文件名的Content Disposition标头。真棒。。(+1).. 这在reli中运行良好。下载的pdf也从未损坏。@doreamon-如何检查实体??使用contentLength方法?请协助,这个答案行不通。主线程上的网络连接将抛出
android.os.NetworkOnMainThreadException
@JBirdVegas不在主线程上运行与网络相关的操作。请创建一个工作线程。使用AsyncTask doInBackground执行try{}catch代码。并从中删除setDoOutput(true)。
new DefaultHttpClient().execute(new HttpGet("http://www.path.to/a.mp4?video"))
.getEntity().writeTo(
new FileOutputStream(new File(root,"Video.mp4")));