Проблемы с загрузкой двоичных файлов на Android
У меня проблемы с загрузкой двоичного файла (видео) в моем приложении из Интернета. В 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();
6 ответов
Я не знаю, является ли это единственной проблемой, но у вас есть классический сбой Java: вы не рассчитываете на то, что read() всегда может вернуть меньше байтов, чем вы просите. Таким образом, ваше чтение может получить менее 1024 байтов, но ваша запись всегда записывает ровно 1024 байта, возможно, включая байты из предыдущей итерации цикла.
Исправить с помощью:
while ( (len1 = in.read(buffer)) > 0 ) {
f.write(buffer,0, len1);
}
Возможно, более высокая задержка в сети или меньший размер пакетов 3G на Android усугубляют эффект?
new DefaultHttpClient().execute(new HttpGet("http://www.path.to/a.mp4?video"))
.getEntity().writeTo(
new FileOutputStream(new File(root,"Video.mp4")));
Одной из проблем является ваше чтение буфера. Если каждое чтение входного потока не является кратным 1024, вы скопируете неверные данные. Использование:
byte[] buffer = new byte[1024];
int len1 = 0;
while ( (len1 = in.read(buffer)) != -1 ) {
f.write(buffer,0, len1);
}
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.");
}
}
Я исправил код на основе предыдущих отзывов в этой теме. Я тестировал с использованием 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();
}
Удачи Алиреза Агамохаммади
Просто используйте метод копирования Apache ( Apache Commons IO) - преимущество использования Java!
IOUtils.copy(is, os);
Не забудьте закрыть потоки в блоке finally:
try{
...
} finally {
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(os);
}