`
AnhuiOSS技术分享
  • 浏览: 35378 次
  • 性别: Icon_minigender_1
社区版块
存档分类
最新评论

Android 文件下载

阅读更多

    Android开发中经常会遇到文件的下载,而下载的时间与网络状态和被下载文件的大小等因素有关。本文会对单线程下载和多线程下载做简要说明。无论哪种操作,最终都是基于HTTP(HTTPS)的网络访问。

 

    先看看基本的一个操作流程,然后对于每一个操作步骤逐一实现就可以了。

    基本流程:

  1. 设置连接属性;
  2. 建立连接;
  3. 获得需要的资源;
  4. 释放资源;

    说明:这个流程是相对的,每个人可以根据具体情况而定。:)

 

    1、在普通Java项目中下载文件: 为了简化问题,我们先不考虑在Android中实现过程,仅仅实现一个下载并保存网络资源的操作。

    代码如下:

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class FileDownload {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		downloadFile("http://image.tianjimedia.com/uploadImages/2012/153/2H4Y79KZF2X3.jpg", "image.jpg");
		downloadFile("http://www.google.com", "message.txt");
		
	}
	
	private static void downloadFile(String urlPath, String filePath) {
		
		InputStream inputStream = null;
		ByteArrayOutputStream byteArrayOutputStream = null;
		byte[] data = null;
		try {
			URL url = new URL(urlPath);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("GET");
			conn.setConnectTimeout(6 * 1000);
                        conn.connect();
                        if (conn.getResponseCode() == 200) {
				inputStream = conn.getInputStream();
				byteArrayOutputStream = new ByteArrayOutputStream();
				byte[] buffer = new byte[1024];
				int length = -1;
				while ((length = inputStream.read(buffer)) != -1) {
					byteArrayOutputStream.write(buffer, 0, length);
				}
				data = byteArrayOutputStream.toByteArray();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
			if (byteArrayOutputStream != null) {
				try {
					byteArrayOutputStream.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		}
		
		if (data != null) {
			File file = new File(filePath);
			FileOutputStream outputStream = null;
			try {
				outputStream = new FileOutputStream(file);
				outputStream.write(data);
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				if (outputStream != null) {
					try {
						outputStream.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
		
	}

}

     说明:

        1、InputStream inputStream = null;和ByteArrayOutputStream byteArrayOutputStream = null;之所以在try-catch外定义,是为了可以在finally代码块中可以访问,并释放该资源。在回收资源时,最好把不同资源放在单独的try-catch块中做资源释放操作,否则可能造成资源泄漏。

		InputStream inputStream = null;
		ByteArrayOutputStream byteArrayOutputStream = null;
		try {

			......

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
                                if (inputStream != null) {
			        	inputStream.close();
		        	}
			        if (byteArrayOutputStream != null) {
				        byteArrayOutputStream.close();
			         }
                        } catch (Exception e) {
                                 e.printStackTrace();
                        }
		}

     如果采用上述资源释放代码,当inputStream和byteArrayOutputStream都不为null时,如果inputStream.close();发生异常,将导致byteArrayOutputStream.close();不被执行,从而没有释放该资源。

        2、conn.setRequestMethod("GET");和conn.setConnectTimeout(6 * 1000);是设置连接属性。还有其它属性,如果需要的话,可以进行设定。

        3、conn.connect();建立连接。

        4、conn.getInputStream();获得连接后的输入流,从中可以获得数据。

        5、在finally代码块中对申请的资源进行释放。

    运行该项目,会在项目的根目录下看到两个文件,image.jpg和message.txt,如图所示:



    2、在Android项目中下载文件:

    a、对UI的设计:



    主Activity中有两个Button,分别启动另外的两个Activity,来实现图片的下载显示和网页内容的获得并显示。布局文件就补贴出来了,会在附件中提供源码。

    b、主Activity没有什么好说的,下面对另外两个Activity做详细说明:

    DownloadImageActivity:

package com.anhuioss.download;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;

public class DownloadImageActivity extends Activity implements OnClickListener {
	
	private EditText filePathEditText;
	private Button downloadButton;
	private ImageView imageDisplay;
	
	private Handler handler = new Handler();
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_download_image);
		
		filePathEditText = (EditText) findViewById(R.id.adi_image_path);
		downloadButton = (Button) findViewById(R.id.adi_button_download);
		imageDisplay = (ImageView) findViewById(R.id.adi_image);
		
		downloadButton.setOnClickListener(this);
		
	}

	@Override
	public void onClick(View v) {
		if (v == downloadButton) {
			if (!Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
				return;
			}
			String path = filePathEditText.getText().toString();
			if (!TextUtils.isEmpty(path)) {
				downloadButton.setEnabled(false);
				imageDisplay.setImageDrawable(null);
				downloadFile(path, Environment.getExternalStorageDirectory() + File.separator + "image.jpg");
			}
		}
	}
	
	private void downloadFile(final String urlPath, final String filePath) {
		
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				
				InputStream inputStream = null;
				ByteArrayOutputStream byteArrayOutputStream = null;
				byte[] data = null;
				try {
					URL url = new URL(urlPath);
					HttpURLConnection conn = (HttpURLConnection) url.openConnection();
					conn.setRequestMethod("GET");
					conn.setConnectTimeout(6 * 1000);
					conn.connect();
					if (conn.getResponseCode() == 200) {
						inputStream = conn.getInputStream();
						byteArrayOutputStream = new ByteArrayOutputStream();
						byte[] buffer = new byte[1024];
						int length = -1;
						while ((length = inputStream.read(buffer)) != -1) {
							byteArrayOutputStream.write(buffer, 0, length);
						}
						data = byteArrayOutputStream.toByteArray();
					}
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					if (inputStream != null) {
						try {
							inputStream.close();
						} catch (IOException e1) {
							e1.printStackTrace();
						}
					}
					if (byteArrayOutputStream != null) {
						try {
							byteArrayOutputStream.close();
						} catch (IOException e1) {
							e1.printStackTrace();
						}
					}
				}
				
				if (data != null) {
					File file = new File(filePath);
					FileOutputStream outputStream = null;
					try {
						outputStream = new FileOutputStream(file);
						outputStream.write(data);
						handler.post(new Runnable() {
							
							@Override
							public void run() {
								
								downloadButton.setEnabled(true);
								Drawable drawable = null;
								try {
									drawable = Drawable.createFromPath(filePath);
								} catch (Error e) {
									e.printStackTrace();
								}
								imageDisplay.setImageDrawable(drawable);
								
							}
						});
					} catch (Exception e) {
						e.printStackTrace();
					} finally {
						if (outputStream != null) {
							try {
								outputStream.close();
							} catch (IOException e) {
								e.printStackTrace();
							}
						}
					}
				}
				
			}
		}).start();
		
	}
	
}

    说明:

        1、private Handler handler = new Handler();handler的作用是在下载线程中完成下载后在UI线程里面更新UI。

        2、由于示例中需要用到SDCARD,所以在做下载操作时,如果没有挂载SDCARD时,不进行下载处理:

if (!Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) {
      return;
}

        3、

handler.post(new Runnable() {
	
	@Override
	public void run() {
		
		downloadButton.setEnabled(true);
		Drawable drawable = null;
		try {
			drawable = Drawable.createFromPath(filePath);
		} catch (Error e) {
			e.printStackTrace();
		}
		imageDisplay.setImageDrawable(drawable);
		
	}
});

     利用handler的post方法,在UI线程里面更新UI。首先使能按钮,其次创建drawable,最后显示图片。

 

    3、运行项目,查看效果: 在运行前,不要忘记在Manifest文件中添加网络访问和访问SDCARD的权限哦!

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

     下载图片的效果如下:



 

    获取网页内容的页面效果:


 

 

 

 

    4、多线程文件下载,直接看普通Java项目中相关操作的代码:

import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;

public class FileDownloadMultiThread {

	public static void main(String[] args) {
		
		downloadFile();
		
	}
	
	private static void downloadFile() {
		
		String fileName = "mysql.chm";
		String urlPath = "http://192.168.1.106/mysql.chm";
		
		// 下载开始前,创建RandomAccessFile并设置文件大小
		RandomAccessFile file = null;
		try {
			
			// 创建URL对象
			URL url = new URL(urlPath);
			
			// 创建HttpURL连接
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			
			// 设置请求属性
			conn.setConnectTimeout(6 * 1000);
			conn.setRequestMethod("GET");
			
			// 连接
			conn.connect();
			
			// 需要下载文件的长度
			int fileLength = conn.getContentLength();
			
			// 创建RandomAccessFile并设置文件大小
			file = new RandomAccessFile(fileName, "rw");
			file.setLength(fileLength);
			
			// 启动的线程数量
			int threadCount = 6;
			
			// 计算每个线程需要下载数据的长度
			int threadDownloadLength = fileLength % 3 == 0 ? fileLength / 3 : fileLength / 3 + 1;
			
			// 创建threadCount个下载线程
			for (int i = 0; i < threadCount; i++) {
				// 计算开始位置
				int startPosition = i * threadDownloadLength;
				// 创建匿名下载线程对象
				new MultiDownloadThread(fileName, urlPath, startPosition).start();
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 资源释放
			if (file != null) {
				 try {
					file.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
		
	}
	
	static class MultiDownloadThread extends Thread {
		
		private String urlPath;
		private int startPosition;
		private RandomAccessFile accessFile;
		
		public MultiDownloadThread(String fileName, String urlPath, int startPosition) {
			this.urlPath = urlPath;
			this.startPosition = startPosition;
			try {
				accessFile = new RandomAccessFile(fileName, "rw");
				accessFile.seek(startPosition);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		public void run () {
			
			InputStream inputStream = null;
			try {
				
				URL url = new URL(urlPath);
				HttpURLConnection conn = (HttpURLConnection) url.openConnection();
				conn.setConnectTimeout(6 * 1000);
				conn.setRequestMethod("GET");
				
				// 设置HTTP的Range字段,指定该线程从文件的什么位置开始下载
				conn.setRequestProperty("Range", "bytes=" + startPosition + "-");
				
				conn.connect();
				inputStream = conn.getInputStream();
				
				byte[] buffer = new byte[1024];
				int readLength = -1;
				int totalLength = 0;
				while ((readLength = inputStream.read(buffer)) != -1) {
					accessFile.write(buffer, 0, readLength);
					totalLength = totalLength + readLength;
				}
				
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				if (accessFile != null) {
					try {
						accessFile.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				if (inputStream != null) {
					try {
						inputStream.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
			
		}
		
	}

}

     说明:

        1、RandomAccessFile类创建目标文件并设置文件大小;

        2、HttpURLConnection.setRequestProperty("Range", "bytes=" + startPosition + "-");方法指定下载位置;

        3、RandomAccessFile.seek();设置文件指针偏移量,保存下载内容到指定位置;

        4、由于线程的创建和销毁过程,线程之间的上下文切换等都需要系统资源,所以threadCount不是越大越好,而是根据具体情况进行设定;

        4、在Android上实现多线程下载的方法类似,注意Android环境的特性就可以了,再次不再赘述!:)

 

        5、多说一句: HTTP(HTTPS)的连接到网络上的数据资源的方式和设置多种多样,本例仅仅是从一个角度进行说明,希望对你有所帮助!如果需要Android项目源码,请查看附件!:)

 

 

  • 大小: 11.6 KB
  • 大小: 29 KB
  • 大小: 27.7 KB
  • 大小: 25.2 KB
  • 大小: 145.8 KB
  • 大小: 20.6 KB
  • 大小: 19.5 KB
  • 大小: 65.5 KB
分享到:
评论

相关推荐

    一个Android文件下载Download程序示例

    一个Android文件下载Download程序示例,文件会下载至local端,远程安装程序(请输入URL),取得远程文件,取得URL,创建连接,InputStream 下载文件,创建临时文件,取得站存盘案路径,将文件写入暂存盘,在手机上打开文件的...

    Android文件下载(实现断点续传)

    综上所述,实现Android文件的断点续传下载主要依赖于Java的RandomAccessFile类和多线程技术,通过精确控制文件的读写位置和下载范围,确保下载的连续性和可靠性。这种技术不仅提高了用户的下载体验,也在一定程度上...

    Android文件下载示例

    与网上流传一个itcast的多线程下载的示例不同, ...可能需要进一步优化,本示例下载同样大小的文件需要6-7秒(下载速度都是200K左右) 暂不支持断点、多个文件同时下载, 架构清晰,可重复利用,如有问题欢迎斧正

    Android文件下载Demo(可断点续传)

    本示例"Android文件下载Demo(可断点续传)"提供了一个实现多线程下载并且支持断点续传功能的源代码DEMO。下面将详细解释这个Demo中涉及的关键知识点。 1. **多线程下载**: 在Android中,为了提高文件下载速度,...

    android下载word文档并打开

    在Android平台上,开发一个应用程序以实现下载Word文档并顺利打开是一项常见的需求。下面将详细讲解这一过程中的关键知识点,以及如何结合给定的资源进行操作。 1. **Android权限管理**: 在Android中,访问网络和...

    android文件下载(实现断点续传)

    在Android平台上,文件下载是一项常见的任务,特别是在处理大型文件或多媒体资源时,为了提升用户体验,开发者通常会采用多线程下载并实现断点续传功能。断点续传允许用户在下载过程中暂停、恢复,避免因网络问题或...

    安卓文件下载上传解压相关-android文件下载存储demo.rar

    最后,这个压缩包中的“android文件下载存储demo”项目,尽管可能需要自行调试才能运行,但它提供了一种基础结构,你可以从中学习如何组织代码、如何处理网络请求,以及如何在Android环境中实现文件的存取和解压。...

    android文件下载

    十分有用的共享资源十分有用的共享资源十分有用的共享资源。

    java和android文件下载 断点续传概要.pdf

    Java 和 Android 文件下载断点续传概要 在本文中,我们将对 Java 和 Android 文件下载断点续传的概要进行详细的介绍。断点续传是一种常用的文件下载技术,它可以在下载过程中发生意外中断时,继续从中断的地方继续...

    Java和Android文件下载断点续传和图片下载

    java和Android文件下载断点续传和图片下载代码实现, 可直接复制代码, 实现多种文件下载,

    Downloader,下载程序是一个轻量级的强大的android文件下载库。.zip

    下载程序下载器,下载管理器、文件下载管理器、文件下载管理器、文件下载管理器、文件下载管理器、文件下载管理器、文件下载管理器、文件下载管理器、文件下载管理器、文件下载管理器、文件下载管理器、文件下载管理...

    android文档下载

    在Android平台上实现文档下载功能,特别是对于Word文档的下载,是一项常见的需求,尤其对于移动应用开发者来说。这个“android文档下载”主题主要涉及到以下几个关键知识点: 1. **Android权限管理**: 在Android...

    Android文件断点下载案例

    在Android开发中,断点下载是一项重要的功能,它允许用户在中断网络连接后从上次停止的位置继续下载大文件,如应用程序、音乐或视频。本文将深入探讨如何在Android平台上实现断点下载,包括其原理、步骤以及核心代码...

    Android 平台文件下载框架 Aria-3.8.10 源码

    Aria 是一个高性能、轻量级、易于使用的文件下载框架,主要应用于 Android 平台,目前在 GitHub 上有超过 5600 个 Star。 Aria 提供了丰富的 API,让用户可以方便地管理下载任务,包括添加、暂停、取消以及查询等...

    Android利用Http下载文件

    在Android平台上,利用Http协议进行文件下载是一项常见的任务,它涉及到网络编程、多线程、文件操作等多个技术领域。本文将深入探讨如何在Android中实现这个功能,主要围绕标题“Android利用Http下载文件”和提供的...

    android通过Service进行文件下载,后台下载

    本教程将深入探讨如何利用Service组件在Android设备上实现文件的后台下载,确保即使用户退出应用程序,文件下载也能继续进行。 ### 1. Android Service基础知识 Service是Android四大组件之一,它在后台运行,没有...

    android文件下载存储demo

    这个demo演示从网上下载文件并保存到手机,demo中可以下载一个XML文件并在Console窗口输出,还可以下载一个MP3文件并保存到手机存储目录中的BoBoMusic文件夹中,下载保存成功会返回:0。(XML和MP3文件我已经传到...

    Android开发文档6.0(最新)-分卷1

    官网最新Android API开发文档,为不方便下载的亲打包上传,一共6个分卷,解压任意一个,文档无加密。文档为HTML类型。

    Android API中文文档

    Android API 中文文档 Android API 中文文档 Android API 中文文档 Android API 中文文档 Android API 中文文档 Android API 中文文档 Android API 中文文档 Android Android API 中文文档 中文文档Android API ...

    Android 端本地预览 PDF 文件

    Android 端本地预览 PDF 文件,使用 AS2.3.3 Gradle 4.1 下载下来可以直接编译运行,内部支持加载本地 File ,也可以加载一个 URL 类型的 PDF 文件,如果恰恰你的 APP 不想调用第三方软件的话 这个 DEMO 非常适合你...

Global site tag (gtag.js) - Google Analytics