当前位置: 首页 > news >正文

珠海网站建设兼职wordpress 添加钩子

珠海网站建设兼职,wordpress 添加钩子,icp备案网站接入信息 ip地址段,青海建设厅官方网站在实际开发涉及文件上传不会自己写上传代码#xff0c;一般 会集成第三网络库来做图片上传#xff0c;比如android-async-http#xff0c;okhttp等#xff0c;另外还有七牛也提供 了下载和上传的API。 1.项目用到的图片上传的关键方法#xff1a; 这里用到一个第三方的库…在实际开发涉及文件上传不会自己写上传代码一般 会集成第三网络库来做图片上传比如android-async-httpokhttp等另外还有七牛也提供 了下载和上传的API。 1.项目用到的图片上传的关键方法 这里用到一个第三方的库 android-async-http.jar自己到github下下这个库~然后调用一下下面的方法即可自己改下url! 上传图片的核心方法如下 private void sendImage(Bitmap bm) {ByteArrayOutputStream stream new ByteArrayOutputStream();bm.compress(Bitmap.CompressFormat.PNG, 60, stream);byte[] bytes stream.toByteArray();String img new String(Base64.encodeToString(bytes, Base64.DEFAULT));AsyncHttpClient client new AsyncHttpClient();RequestParams params new RequestParams();params.add(img, img);client.post(http:xxx/postIcon, params, new AsyncHttpResponseHandler() {Overridepublic void onSuccess(int i, Header[] headers, byte[] bytes) {Toast.makeText(MainActivity.this, Upload Success!, Toast.LENGTH_LONG).show();}Overridepublic void onFailure(int i, Header[] headers, byte[] bytes, Throwable throwable) {Toast.makeText(MainActivity.this, Upload Fail!, Toast.LENGTH_LONG).show();}}); } 2.使用HttpConnection上传文件 public class SocketHttpRequester { /** * 发送xml数据 * param path 请求地址 * param xml xml数据 * param encoding 编码 * return * throws Exception */ public static byte[] postXml(String path, String xml, String encoding) throws Exception{ byte[] data xml.getBytes(encoding); URL url new URL(path); HttpURLConnection conn (HttpURLConnection)url.openConnection(); conn.setRequestMethod(POST); conn.setDoOutput(true); conn.setRequestProperty(Content-Type, text/xml; charset encoding); conn.setRequestProperty(Content-Length, String.valueOf(data.length)); conn.setConnectTimeout(5 * 1000); OutputStream outStream conn.getOutputStream(); outStream.write(data); outStream.flush(); outStream.close(); if(conn.getResponseCode()200){ return readStream(conn.getInputStream()); } return null; } /** * 直接通过HTTP协议提交数据到服务器,实现如下面表单提交功能: * FORM METHODPOST ACTIONhttp://192.168.0.200:8080/ssi/fileload/test.do enctypemultipart/form-data INPUT TYPEtext NAMEname INPUT TYPEtext NAMEid input typefile nameimagefile/ input typefile namezip/ /FORM * param path 上传路径(注避免使用localhost或127.0.0.1这样的路径测试 * 因为它会指向手机模拟器你可以使用http://www.baidu.com或http://192.168.1.10:8080这样的路径测试) * param params 请求参数 key为参数名,value为参数值 * param file 上传文件 */ public static boolean post(String path, MapString, String params, FormFile[] files) throws Exception { //数据分隔线 final String BOUNDARY ---------------------------7da2137580612; //数据结束标志---------------------------7da2137580612-- final String endline -- BOUNDARY --/r/n; //下面两个for循环都是为了得到数据长度参数依据表单的类型而定 //首先得到文件类型数据的总长度(包括文件分割线) int fileDataLength 0; for(FormFile uploadFile : files) { StringBuilder fileExplain new StringBuilder(); fileExplain.append(--); fileExplain.append(BOUNDARY); fileExplain.append(/r/n); fileExplain.append(Content-Disposition: form-data;name/ uploadFile.getParameterName()/;filename/ uploadFile.getFilname() //r/n); fileExplain.append(Content-Type: uploadFile.getContentType()/r/n/r/n); fileExplain.append(/r/n); fileDataLength fileExplain.length(); if(uploadFile.getInStream()!null){ fileDataLength uploadFile.getFile().length(); }else{ fileDataLength uploadFile.getData().length; } } //再构造文本类型参数的实体数据 StringBuilder textEntity new StringBuilder(); for (Map.EntryString, String entry : params.entrySet()) { textEntity.append(--); textEntity.append(BOUNDARY); textEntity.append(/r/n); textEntity.append(Content-Disposition: form-data; name/ entry.getKey() //r/n/r/n); textEntity.append(entry.getValue()); textEntity.append(/r/n); } //计算传输给服务器的实体数据总长度(文本总长度数据总长度分隔符) int dataLength textEntity.toString().getBytes().length fileDataLength endline.getBytes().length; URL url new URL(path); //默认端口号其实可以不写 int port url.getPort()-1 ? 80 : url.getPort(); //建立一个Socket链接 Socket socket new Socket(InetAddress.getByName(url.getHost()), port); //获得一个输出流从Android流到web OutputStream outStream socket.getOutputStream(); //下面完成HTTP请求头的发送 String requestmethod POST url.getPath() HTTP/1.1/r/n; outStream.write(requestmethod.getBytes()); //构建accept String accept Accept: image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xamlxml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*/r/n; outStream.write(accept.getBytes()); //构建language String language Accept-Language: zh-CN/r/n; outStream.write(language.getBytes()); //构建contenttype String contenttype Content-Type: multipart/form-data; boundary BOUNDARY /r/n; outStream.write(contenttype.getBytes()); //构建contentlength String contentlength Content-Length: dataLength /r/n; outStream.write(contentlength.getBytes()); //构建alive String alive Connection: Keep-Alive/r/n; outStream.write(alive.getBytes()); //构建host String host Host: url.getHost() : port /r/n; outStream.write(host.getBytes()); //写完HTTP请求头后根据HTTP协议再写一个回车换行 outStream.write(/r/n.getBytes()); //把所有文本类型的实体数据发送出来 outStream.write(textEntity.toString().getBytes()); //把所有文件类型的实体数据发送出来 for(FormFile uploadFile : files) { StringBuilder fileEntity new StringBuilder(); fileEntity.append(--); fileEntity.append(BOUNDARY); fileEntity.append(/r/n); fileEntity.append(Content-Disposition: form-data;name/ uploadFile.getParameterName()/;filename/ uploadFile.getFilname() //r/n); fileEntity.append(Content-Type: uploadFile.getContentType()/r/n/r/n); outStream.write(fileEntity.toString().getBytes()); //边读边写 if(uploadFile.getInStream()!null) { byte[] buffer new byte[1024]; int len 0; while((len uploadFile.getInStream().read(buffer, 0, 1024))!-1) { outStream.write(buffer, 0, len); } uploadFile.getInStream().close(); } else { outStream.write(uploadFile.getData(), 0, uploadFile.getData().length); } outStream.write(/r/n.getBytes()); } //下面发送数据结束标志表示数据已经结束 outStream.write(endline.getBytes()); BufferedReader reader new BufferedReader(new InputStreamReader(socket.getInputStream())); //读取web服务器返回的数据判断请求码是否为200如果不是200代表请求失败 if(reader.readLine().indexOf(200)-1) { return false; } outStream.flush(); outStream.close(); reader.close(); socket.close(); return true; } /** * 提交数据到服务器 * param path 上传路径(注避免使用localhost或127.0.0.1这样的路径测试因为它会指向手机模拟器你可以使用http://www.baidu.com或http://192.168.1.10:8080这样的路径测试) * param params 请求参数 key为参数名,value为参数值 * param file 上传文件 */ public static boolean post(String path, MapString, String params, FormFile file) throws Exception { return post(path, params, new FormFile[]{file}); } /** * 提交数据到服务器 * param path 上传路径(注避免使用localhost或127.0.0.1这样的路径测试因为它会指向手机模拟器你可以使用http://www.baidu.com或http://192.168.1.10:8080这样的路径测试) * param params 请求参数 key为参数名,value为参数值 * param encode 编码 */ public static byte[] postFromHttpClient(String path, MapString, String params, String encode) throws Exception { //用于存放请求参数 ListNameValuePair formparams new ArrayListNameValuePair(); for(Map.EntryString, String entry : params.entrySet()) { formparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } UrlEncodedFormEntity entity new UrlEncodedFormEntity(formparams, encode); HttpPost httppost new HttpPost(path); httppost.setEntity(entity); //看作是浏览器 HttpClient httpclient new DefaultHttpClient(); //发送post请求 HttpResponse response httpclient.execute(httppost); return readStream(response.getEntity().getContent()); } /** * 发送请求 * param path 请求路径 * param params 请求参数 key为参数名称 value为参数值 * param encode 请求参数的编码 */ public static byte[] post(String path, MapString, String params, String encode) throws Exception { //String params methodsavename URLEncoder.encode(老毕, UTF-8) age28;//需要发送的参数 StringBuilder parambuilder new StringBuilder(); if(params!null !params.isEmpty()) { for(Map.EntryString, String entry : params.entrySet()) { parambuilder.append(entry.getKey()).append() .append(URLEncoder.encode(entry.getValue(), encode)).append(); } parambuilder.deleteCharAt(parambuilder.length()-1); } byte[] data parambuilder.toString().getBytes(); URL url new URL(path); HttpURLConnection conn (HttpURLConnection)url.openConnection(); //设置允许对外发送请求参数 conn.setDoOutput(true); //设置不进行缓存 conn.setUseCaches(false); conn.setConnectTimeout(5 * 1000); conn.setRequestMethod(POST); //下面设置http请求头 conn.setRequestProperty(Accept, image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xamlxml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*); conn.setRequestProperty(Accept-Language, zh-CN); conn.setRequestProperty(User-Agent, Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)); conn.setRequestProperty(Content-Type, application/x-www-form-urlencoded); conn.setRequestProperty(Content-Length, String.valueOf(data.length)); conn.setRequestProperty(Connection, Keep-Alive); //发送参数 DataOutputStream outStream new DataOutputStream(conn.getOutputStream()); outStream.write(data);//把参数发送出去 outStream.flush(); outStream.close(); if(conn.getResponseCode()200) { return readStream(conn.getInputStream()); } return null; } /** * 读取流 * param inStream * return 字节数组 * throws Exception */ public static byte[] readStream(InputStream inStream) throws Exception { ByteArrayOutputStream outSteam new ByteArrayOutputStream(); byte[] buffer new byte[1024]; int len -1; while( (leninStream.read(buffer)) ! -1) { outSteam.write(buffer, 0, len); } outSteam.close(); inStream.close(); return outSteam.toByteArray(); } } 3.普通单线程下载文件 直接使用URLConnection.openStream()打开网络输入流,然后将流写入到文件中 核心方法 public static void downLoad(String path,Context context)throws Exception {URL url new URL(path);InputStream is url.openStream();//截取最后的文件名String end path.substring(path.lastIndexOf(.));//打开手机对应的输出流,输出到文件中OutputStream os context.openFileOutput(Cache_System.currentTimeMillis()end, Context.MODE_PRIVATE);byte[] buffer new byte[1024];int len 0;//从输入六中读取数据,读到缓冲区中while((len is.read(buffer)) 0){os.write(buffer,0,len);}//关闭输入输出流is.close();os.close(); } 4.普通多线程下载 我们都知道使用多线程下载文件可以更快地完成文件的下载,但是为什么呢? 答因为抢占的服务器资源多,假设服务器最多服务100个用户,服务器中的一个线程 对应一个用户100条线程在计算机中并发执行,由CPU划分时间片轮流执行,加入a有99条线程 下载文件,那么相当于占用了99个用户资源,自然就有用较快的下载速度 PS:当然不是线程越多就越好,开启过多线程的话,app需要维护和同步每条线程的开销, 这些开销反而会导致下载速度的降低,另外还和你的网速有关! 多线程下载的流程 获取网络连接 本地磁盘创建相同大小的空文件 计算每条线程需从文件哪个部分开始下载结束 依次创建启动多条线程来下载网络资源的指定部分 PS:这里直接创建一个Java项目然后在JUnit里运行指定方法即可 核心代码如下 public class Downloader {//添加Test标记是表示该方法是Junit测试的方法,就可以直接运行该方法了Testpublic void download() throws Exception{//设置URL的地址和下载后的文件名String filename meitu.exe;String path http://10.13.20.32:8080/Test/XiuXiu_Green.exe;URL url new URL(path);HttpURLConnection conn (HttpURLConnection) url.openConnection();conn.setConnectTimeout(5000);conn.setRequestMethod(GET);//获得需要下载的文件的长度(大小)int filelength conn.getContentLength();System.out.println(要下载的文件长度filelength);//生成一个大小相同的本地文件RandomAccessFile file new RandomAccessFile(filename, rwd);file.setLength(filelength);file.close();conn.disconnect();//设置有多少条线程下载int threadsize 3;//计算每个线程下载的量int threadlength filelength % 3 0 ? filelength/3:filelength1;for(int i 0;i threadsize;i){//设置每条线程从哪个位置开始下载int startposition i * threadlength;//从文件的什么位置开始写入数据RandomAccessFile threadfile new RandomAccessFile(filename, rwd);threadfile.seek(startposition);//启动三条线程分别从startposition位置开始下载文件new DownLoadThread(i,startposition,threadfile,threadlength,path).start();}int quit System.in.read();while(q ! quit){Thread.sleep(2000);}}private class DownLoadThread extends Thread {private int threadid;private int startposition;private RandomAccessFile threadfile;private int threadlength;private String path;public DownLoadThread(int threadid, int startposition,RandomAccessFile threadfile, int threadlength, String path) {this.threadid threadid;this.startposition startposition;this.threadfile threadfile;this.threadlength threadlength;this.path path;}public DownLoadThread() {}Overridepublic void run() {try{URL url new URL(path);HttpURLConnection conn (HttpURLConnection) url.openConnection();conn.setConnectTimeout(5000);conn.setRequestMethod(GET);//指定从什么位置开始下载conn.setRequestProperty(Range, bytesstartposition-);//System.out.println(conn.getResponseCode());if(conn.getResponseCode() 206){InputStream is conn.getInputStream();byte[] buffer new byte[1024];int len -1;int length 0;while(length threadlength (len is.read(buffer)) ! -1){threadfile.write(buffer,0,len);//计算累计下载的长度length len;}threadfile.close();is.close();System.out.println(线程(threadid1) 已下载完成);}}catch(Exception ex){System.out.println(线程(threadid1) 下载出错 ex);}}} } 注意事项 int filelength conn.getContentLength(); //获得下载文件的长度(大小) RandomAccessFile file new RandomAccessFile(filename, “rwd”); //该类运行对文件进行读写,是多线程下载的核心 nt threadlength filelength % 3 0 ? filelength/3:filelength1; //计算每个线程要下载的量 conn.setRequestProperty(“Range”, “bytes”startposition“-”); //指定从哪个位置开始读写,这个是URLConnection提供的方法 //System.out.println(conn.getResponseCode()); //这个注释了的代码是用来查看conn的返回码的,我们前面用的都是200, 而针对多线程的话,通常是206,必要时我们可以通过调用该方法查看返回码 int quit System.in.read();while(‘q’ ! quit){Thread.sleep(2000);} //这段代码是做延时操作的,因为我们用的是本地下载,可能该方法运行完了,而我们的 线程还没有开启,这样会引发异常,这里的话,让用户输入一个字符,如果是’q’的话就退出 5.使用DownloadManager更新应用并覆盖安装 下面的代码可以直接用加入到项目后记得为这个内部广播注册一个过滤器 AndroidManifest.xml import android.app.DownloadManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.support.v7.app.AppCompatActivity;/*** Created by Jay on 2015/9/9 0009.*/ public class UpdateAct extends AppCompatActivity {//这个更新的APK的版本部分我们是这样命名的:xxx_v1.0.0_xxxxxxxxx.apk//这里我们用的是git提交版本的前九位作为表示private static final String FILE_NAME ABCDEFGHI;Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);String endpoint ;try {//这部分是获取AndroidManifest.xml里的配置信息的包名以及Meta_data里保存的东西ApplicationInfo info getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);//我们在meta_data保存了xxx.xxx这样一个数据是https开头的一个链接这里替换成httpendpoint info.metaData.getString(xxxx.xxxx).replace(https,http);} catch (PackageManager.NameNotFoundException e) {e.printStackTrace();}//下面的都是拼接apk更新下载url的path是保存的文件夹路径final String _Path this.getIntent().getStringExtra(path);final String _Url endpoint _Path;final DownloadManager _DownloadManager (DownloadManager) getSystemService(DOWNLOAD_SERVICE);DownloadManager.Request _Request new DownloadManager.Request(Uri.parse(_Url));_Request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, FILE_NAME .apk);_Request.setTitle(this.getString(R.string.app_name));//是否显示下载对话框_Request.setShowRunningNotification(true);_Request.setMimeType(application/com.trinea.download.file);//将下载请求放入队列_DownloadManager.enqueue(_Request);this.finish();}//注册一个广播接收器当下载完毕后会收到一个android.intent.action.DOWNLOAD_COMPLETE//的广播,在这里取出队列里下载任务进行安装public static class Receiver extends BroadcastReceiver {public void onReceive(Context context, Intent intent) {final DownloadManager _DownloadManager (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);final long _DownloadId intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);final DownloadManager.Query _Query new DownloadManager.Query();_Query.setFilterById(_DownloadId);final Cursor _Cursor _DownloadManager.query(_Query);if (_Cursor.moveToFirst()) {final int _Status _Cursor.getInt(_Cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS));final String _Name _Cursor.getString(_Cursor.getColumnIndexOrThrow(local_filename));if (_Status DownloadManager.STATUS_SUCCESSFUL _Name.indexOf(FILE_NAME) ! 0) {Intent _Intent new Intent(Intent.ACTION_VIEW);_Intent.setDataAndType(Uri.parse(_Cursor.getString(_Cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_LOCAL_URI))),application/vnd.android.package-archive);_Intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);context.startActivity(_Intent);}}_Cursor.close();}} } 6.Android多线程断点下载的代码流程解析 实现流程全解析 Step 1创建一个用来记录线程下载信息的表 创建数据库表,于是乎我们创建一个数据库的管理器类,继承SQLiteOpenHelper类 重写onCreate()与onUpgrade()方法,我们创建的表字段如下: DBOpenHelper.java package com.jay.example.db; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper;public class DBOpenHelper extends SQLiteOpenHelper {public DBOpenHelper(Context context) {super(context, downs.db, null, 1);}Overridepublic void onCreate(SQLiteDatabase db) {//数据库的结构为:表名:filedownlog 字段:id,downpath:当前下载的资源,//threadid:下载的线程iddownlength:线程下载的最后位置db.execSQL(CREATE TABLE IF NOT EXISTS filedownlog (id integer primary key autoincrement, downpath varchar(100), threadid INTEGER, downlength INTEGER));}Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {//当版本号发生改变时调用该方法,这里删除数据表,在实际业务中一般是要进行数据备份的db.execSQL(DROP TABLE IF EXISTS filedownlog);onCreate(db);}} Step 2创建一个数据库操作类 我们需要创建什么样的方法呢 ①我们需要一个根据URL获得每条线程当前下载长度的方法 ②接着,当我们的线程新开辟后,我们需要往数据库中插入与该线程相关参数的方法 ③还要定义一个可以实时更新下载文件长度的方法 ④我们线程下载完,还需要根据线程id,删除对应记录的方法 FileService.java package com.jay.example.db;import java.util.HashMap; import java.util.Map; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase;/** 该类是一个业务bean类,完成数据库的相关操作* */public class FileService {//声明数据库管理器private DBOpenHelper openHelper;//在构造方法中根据上下文对象实例化数据库管理器public FileService(Context context) {openHelper new DBOpenHelper(context);}/*** 获得指定URI的每条线程已经下载的文件长度* param path* return * */public MapInteger, Integer getData(String path){//获得可读数据库句柄,通常内部实现返回的其实都是可写的数据库句柄SQLiteDatabase db openHelper.getReadableDatabase();//根据下载的路径查询所有现场的下载数据,返回的Cursor指向第一条记录之前Cursor cursor db.rawQuery(select threadid, downlength from filedownlog where downpath?,new String[]{path});//建立一个哈希表用于存放每条线程已下载的文件长度MapInteger,Integer data new HashMapInteger, Integer();//从第一条记录开始遍历Cursor对象cursor.moveToFirst();while(cursor.moveToNext()){//把线程id与该线程已下载的长度存放到data哈希表中data.put(cursor.getInt(0), cursor.getInt(1));data.put(cursor.getInt(cursor.getColumnIndexOrThrow(threadid)),cursor.getInt(cursor.getColumnIndexOrThrow(downlength)));}cursor.close();//关闭cursor,释放资源;db.close();return data;}/*** 保存每条线程已经下载的文件长度* param path 下载的路径* param map 现在的di和已经下载的长度的集合*/public void save(String path,MapInteger,Integer map){SQLiteDatabase db openHelper.getWritableDatabase();//开启事务,因为此处需要插入多条数据db.beginTransaction();try{//使用增强for循环遍历数据集合for(Map.EntryInteger, Integer entry : map.entrySet()){//插入特定下载路径特定线程ID已经下载的数据db.execSQL(insert into filedownlog(downpath, threadid, downlength) values(?,?,?),new Object[]{path, entry.getKey(), entry.getValue()});}//设置一个事务成功的标志,如果成功就提交事务,如果没调用该方法的话那么事务回滚//就是上面的数据库操作撤销db.setTransactionSuccessful();}finally{//结束一个事务db.endTransaction();}db.close();}/*** 实时更新每条线程已经下载的文件长度* param path* param map*/public void update(String path,int threadId,int pos){SQLiteDatabase db openHelper.getWritableDatabase();//更新特定下载路径下特定线程已下载的文件长度db.execSQL(update filedownlog set downlength? where downpath? and threadid?,new Object[]{pos, path, threadId});db.close();}/***当文件下载完成后删除对应的下载记录*param path */public void delete(String path){SQLiteDatabase db openHelper.getWritableDatabase();db.execSQL(delete from filedownlog where downpath?, new Object[]{path});db.close();}} Step 3创建一个文件下载器类 好了,数据库管理器与操作类都完成了接着就该弄一个文件下载器类了,在该类中又要完成 什么操作呢要做的事就多了 ①定义一堆变量,核心是线程池threads和同步集合ConcurrentHashMap,用于缓存线程下载长度的 ②定义一个获取线程池中线程数的方法; ③定义一个退出下载的方法, ④获取当前文件大小的方法 ⑤累计当前已下载长度的方法,这里需要添加一个synchronized关键字,用来解决并发访问的问题 ⑥更新指定线程最后的下载位置,同样也需要用同步 ⑦在构造方法中完成文件下载,线程开辟等操作 ⑧获取文件名的方法:先截取提供的url最后的’/后面的字符串,如果获取不到,再从头字段查找,还是 找不到的话,就使用网卡标识数字cpu的唯一数字生成一个16个字节的二进制作为文件名 ⑨开始下载文件的方法 ⑩获取http响应头字段的方法 ⑪打印http头字段的方法 12.打印日志信息的方法 FileDownloadered.java: package com.jay.example.service;import java.io.File; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; import java.util.LinkedHashMap; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern;import android.content.Context; import android.util.Log;import com.jay.example.db.FileService;public class FileDownloadered {private static final String TAG 文件下载类; //设置一个查log时的一个标志private static final int RESPONSEOK 200; //设置响应码为200,代表访问成功private FileService fileService; //获取本地数据库的业务Beanprivate boolean exited; //停止下载的标志private Context context; //程序的上下文对象private int downloadedSize 0; //已下载的文件长度private int fileSize 0; //开始的文件长度private DownloadThread[] threads; //根据线程数设置下载的线程池private File saveFile; //数据保存到本地的文件中private MapInteger, Integer data new ConcurrentHashMapInteger, Integer(); //缓存个条线程的下载的长度private int block; //每条线程下载的长度private String downloadUrl; //下载的路径/*** 获取线程数*/public int getThreadSize(){//return threads.length;return 0;}/*** 退出下载* */public void exit(){this.exited true; //将退出的标志设置为true;}public boolean getExited(){return this.exited;}/*** 获取文件的大小* */public int getFileSize(){return fileSize;}/*** 累计已下载的大小* 使用同步锁来解决并发的访问问题* */protected synchronized void append(int size){//把实时下载的长度加入到总的下载长度中downloadedSize size;}/*** 更新指定线程最后下载的位置* param threadId 线程id* param pos 最后下载的位置* */protected synchronized void update(int threadId,int pos){//把指定线程id的线程赋予最新的下载长度,以前的值会被覆盖掉this.data.put(threadId, pos);//更新数据库中制定线程的下载长度this.fileService.update(this.downloadUrl, threadId, pos);}/*** 构建文件下载器* param downloadUrl 下载路径* param fileSaveDir 文件的保存目录* param threadNum 下载线程数* return */public FileDownloadered(Context context,String downloadUrl,File fileSaveDir,int threadNum){try {this.context context; //获取上下文对象,赋值this.downloadUrl downloadUrl; //为下载路径赋值fileService new FileService(this.context); //实例化数据库操作的业务Bean类,需要传一个context值URL url new URL(this.downloadUrl); //根据下载路径实例化URLif(!fileSaveDir.exists()) fileSaveDir.mkdir(); //如果文件不存在的话指定目录,这里可创建多层目录this.threads new DownloadThread[threadNum]; //根据下载的线程数量创建下载的线程池HttpURLConnection conn (HttpURLConnection) url.openConnection(); //创建远程连接句柄,这里并未真正连接conn.setConnectTimeout(5000); //设置连接超时事件为5秒conn.setRequestMethod(GET); //设置请求方式为GET//设置用户端可以接收的媒体类型conn.setRequestProperty(Accept, image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xamlxml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*);conn.setRequestProperty(Accept-Language, zh-CN); //设置用户语言conn.setRequestProperty(Referer, downloadUrl); //设置请求的来源页面,便于服务端进行来源统计conn.setRequestProperty(Charset, UTF-8); //设置客户端编码//设置用户代理conn.setRequestProperty(User-Agent, Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729));conn.setRequestProperty(Connection, Keep-Alive); //设置connection的方式conn.connect(); //和远程资源建立正在的链接,但尚无返回的数据流printResponseHeader(conn); //打印返回的Http的头字段集合//对返回的状态码进行判断,用于检查是否请求成功,返回200时执行下面的代码if(conn.getResponseCode() RESPONSEOK){this.fileSize conn.getContentLength(); //根据响应获得文件大小if(this.fileSize 0)throw new RuntimeException(不知道文件大小); //文件长度小于等于0时抛出运行时异常String filename getFileName(conn); //获取文件名称this.saveFile new File(fileSaveDir,filename); //根据文件保存目录和文件名保存文件MapInteger,Integer logdata fileService.getData(downloadUrl); //获取下载记录//如果存在下载记录if(logdata.size() 0){//遍历集合中的数据,把每条线程已下载的数据长度放入data中for(Map.EntryInteger, Integer entry : logdata.entrySet()){data.put(entry.getKey(), entry.getValue());}}//如果已下载的数据的线程数和现在设置的线程数相同时则计算所有现场已经下载的数据总长度if(this.data.size() this.threads.length){//遍历每条线程已下载的数据for(int i 0;i this.threads.length;i){this.downloadedSize this.data.get(i1);}print(已下载的长度 this.downloadedSize 个字节);}//使用条件运算符求出每个线程需要下载的数据长度this.block (this.fileSize % this.threads.length) 0?this.fileSize / this.threads.length:this.fileSize / this.threads.length 1;}else{//打印错误信息print(服务器响应错误: conn.getResponseCode() conn.getResponseMessage());throw new RuntimeException(服务器反馈出错);}}catch (Exception e) {print(e.toString()); //打印错误throw new RuntimeException(无法连接URL);}}/*** 获取文件名* */private String getFileName(HttpURLConnection conn){//从下载的路径的字符串中获取文件的名称String filename this.downloadUrl.substring(this.downloadUrl.lastIndexOf(/) 1);if(filename null || .equals(filename.trim())){ //如果获取不到文件名称for(int i 0;;i) //使用无限循环遍历{String mine conn.getHeaderField(i); //从返回的流中获取特定索引的头字段的值if (mine null) break; //如果遍历到了返回头末尾则退出循环//获取content-disposition返回字段,里面可能包含文件名if(content-disposition.equals(conn.getHeaderFieldKey(i).toLowerCase())){//使用正则表达式查询文件名Matcher m Pattern.compile(.*filename(.*)).matcher(mine.toLowerCase());if(m.find()) return m.group(1); //如果有符合正则表达式规则的字符串,返回}}filename UUID.randomUUID() .tmp;//如果都没找到的话,默认取一个文件名//由网卡标识数字(每个网卡都有唯一的标识号)以及CPU时间的唯一数字生成的一个16字节的二进制作为文件名}return filename;}/*** 开始下载文件* param listener 监听下载数量的变化,如果不需要了解实时下载的数量,可以设置为null* return 已下载文件大小* throws Exception*///进行下载,如果有异常的话,抛出异常给调用者public int download(DownloadProgressListener listener) throws Exception{try {RandomAccessFile randOut new RandomAccessFile(this.saveFile, rwd);//设置文件大小if(this.fileSize0) randOut.setLength(this.fileSize);randOut.close(); //关闭该文件,使设置生效URL url new URL(this.downloadUrl);if(this.data.size() ! this.threads.length){//如果原先未曾下载或者原先的下载线程数与现在的线程数不一致this.data.clear();//遍历线程池for (int i 0; i this.threads.length; i) {this.data.put(i1, 0);//初始化每条线程已经下载的数据长度为0}this.downloadedSize 0; //设置已经下载的长度为0}for (int i 0; i this.threads.length; i) {//开启线程进行下载int downLength this.data.get(i1); //通过特定的线程id获取该线程已经下载的数据长度//判断线程是否已经完成下载,否则继续下载 if(downLength this.block this.downloadedSizethis.fileSize){//初始化特定id的线程this.threads[i] new DownloadThread(this, url, this.saveFile, this.block, this.data.get(i1), i1);//设置线程优先级,Thread.NORM_PRIORITY 5;//Thread.MIN_PRIORITY 1;Thread.MAX_PRIORITY 10,数值越大优先级越高this.threads[i].setPriority(7); this.threads[i].start(); //启动线程}else{this.threads[i] null; //表明线程已完成下载任务}}fileService.delete(this.downloadUrl); //如果存在下载记录删除它们然后重新添加fileService.save(this.downloadUrl, this.data); //把下载的实时数据写入数据库中boolean notFinish true; //下载未完成while (notFinish) { // 循环判断所有线程是否完成下载Thread.sleep(900);notFinish false; //假定全部线程下载完成for (int i 0; i this.threads.length; i){if (this.threads[i] ! null !this.threads[i].isFinish()) {//如果发现线程未完成下载notFinish true; //设置标志为下载没有完成if(this.threads[i].getDownLength() -1){ //如果下载失败,再重新在已下载的数据长度的基础上下载//重新开辟下载线程,设置线程的优先级this.threads[i] new DownloadThread(this, url, this.saveFile, this.block, this.data.get(i1), i1);this.threads[i].setPriority(7);this.threads[i].start();}}} if(listener!null) listener.onDownloadSize(this.downloadedSize);//通知目前已经下载完成的数据长度}if(downloadedSize this.fileSize) fileService.delete(this.downloadUrl);//下载完成删除记录} catch (Exception e) {print(e.toString());throw new Exception(文件下载异常);}return this.downloadedSize;}/*** 获取Http响应头字段* param http* return*/public static MapString, String getHttpResponseHeader(HttpURLConnection http) {//使用LinkedHashMap保证写入和便利的时候的顺序相同,而且允许空值MapString, String header new LinkedHashMapString, String();//此处使用无线循环,因为不知道头字段的数量for (int i 0;; i) {String mine http.getHeaderField(i); //获取第i个头字段的值if (mine null) break; //没值说明头字段已经循环完毕了,使用break跳出循环header.put(http.getHeaderFieldKey(i), mine); //获得第i个头字段的键}return header;}/*** 打印Http头字段* param http*/public static void printResponseHeader(HttpURLConnection http){//获取http响应的头字段MapString, String header getHttpResponseHeader(http);//使用增强for循环遍历取得头字段的值,此时遍历的循环顺序与输入树勋相同for(Map.EntryString, String entry : header.entrySet()){//当有键的时候则获取值,如果没有则为空字符串String key entry.getKey()!null ? entry.getKey() : : ;print(key entry.getValue()); //打印键和值得组合}}/*** 打印信息* param msg 信息字符串* */private static void print(String msg) {Log.i(TAG, msg);} } Step 4自定义一个下载线程类 这个自定义的线程类要做的事情如下 ① 首先肯定是要继承Thread类啦,然后重写Run()方法 ② Run()方法:先判断是否下载完成,没有得话:打开URLConnection链接,接着RandomAccessFile 进行数据读写,完成时设置完成标记为true,发生异常的话设置长度为-1,打印异常信息 ③打印log信息的方法 ④判断下载是否完成的方法(根据完成标记) ⑤获得已下载的内容大小 DownLoadThread.java package com.jay.example.service;import java.io.File; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL;import android.util.Log;public class DownloadThread extends Thread {private static final String TAG 下载线程类; //定义TAG,在打印log时进行标记private File saveFile; //下载的数据保存到的文件private URL downUrl; //下载的URLprivate int block; //每条线程下载的大小private int threadId -1; //初始化线程id设置private int downLength; //该线程已下载的数据长度private boolean finish false; //该线程是否完成下载的标志private FileDownloadered downloader; //文件下载器public DownloadThread(FileDownloadered downloader, URL downUrl, File saveFile, int block, int downLength, int threadId) {this.downUrl downUrl;this.saveFile saveFile;this.block block;this.downloader downloader;this.threadId threadId;this.downLength downLength;}Overridepublic void run() {if(downLength block){//未下载完成try {HttpURLConnection http (HttpURLConnection) downUrl.openConnection();http.setConnectTimeout(5 * 1000);http.setRequestMethod(GET);http.setRequestProperty(Accept, image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xamlxml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*);http.setRequestProperty(Accept-Language, zh-CN);http.setRequestProperty(Referer, downUrl.toString()); http.setRequestProperty(Charset, UTF-8);int startPos block * (threadId - 1) downLength;//开始位置int endPos block * threadId -1;//结束位置http.setRequestProperty(Range, bytes startPos - endPos);//设置获取实体数据的范围http.setRequestProperty(User-Agent, Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729));http.setRequestProperty(Connection, Keep-Alive);InputStream inStream http.getInputStream(); //获得远程连接的输入流byte[] buffer new byte[1024]; //设置本地数据的缓存大小为1MBint offset 0; //每次读取的数据量print(Thread this.threadId start download from position startPos); //打印该线程开始下载的位置RandomAccessFile threadfile new RandomAccessFile(this.saveFile, rwd);threadfile.seek(startPos);//用户没有要求停止下载,同时没有达到请求数据的末尾时会一直循环读取数据while (!downloader.getExited() (offset inStream.read(buffer, 0, 1024)) ! -1) {threadfile.write(buffer, 0, offset); //直接把数据写入到文件中downLength offset; //把新线程已经写到文件中的数据加入到下载长度中downloader.update(this.threadId, downLength); //把该线程已经下载的数据长度更新到数据库和内存哈希表中downloader.append(offset); //把新下载的数据长度加入到已经下载的数据总长度中}threadfile.close();inStream.close();print(Thread this.threadId download finish);this.finish true; //设置完成标记为true,无论下载完成还是用户主动中断下载} catch (Exception e) {this.downLength -1; //设置该线程已经下载的长度为-1print(Thread this.threadId : e);}}}private static void print(String msg){Log.i(TAG, msg);}/*** 下载是否完成* return*/public boolean isFinish() {return finish;}/*** 已经下载的内容大小* return 如果返回值为-1,代表下载失败*/public long getDownLength() {return downLength;} } Step 5创建一个DownloadProgressListener接口监听下载进度 FileDownloader中使用了DownloadProgressListener进行进度监听, 所以这里需要创建一个接口,同时定义一个方法的空实现: DownloadProgressListener.java: package com.jay.example.service; public interface DownloadProgressListener {public void onDownloadSize(int downloadedSize); }Step 6编写我们的布局代码 另外调用android:enabledfalse设置组件是否可点击, 代码如下 activity_main.xml: LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsandroid:idid/LinearLayout1android:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:orientationverticaltools:contextcom.jay.example.multhreadcontinuabledemo.MainActivity TextViewandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:text请输入要下载的文件地址 /EditText android:idid/editpathandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:texthttp://10.13.20.32:8080/Test/twelve.mp3 /Button android:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:idid/btndownandroid:text下载 /Button android:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:idid/btnstopandroid:text停止android:enabledfalse /ProgressBarandroid:layout_widthfill_parent android:layout_height18dp style?android:attr/progressBarStyleHorizontalandroid:idid/progressBar/TextView android:layout_widthfill_parent android:layout_heightwrap_content android:gravitycenterandroid:idid/textresultandroid:text显示实时下载的百分比//LinearLayout Step 7MainActivity的编写 最后就是我们的MainActivity了,完成组件以及相关变量的初始化; 使用handler来完成界面的更新操作,另外耗时操作不能够在主线程中进行, 所以这里需要开辟新的线程,这里用Runnable实现,详情见代码 吧 MainActivity.java: package com.jay.example.multhreadcontinuabledemo;import java.io.File;import com.jay.example.service.FileDownloadered;import android.app.Activity; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast;public class MainActivity extends Activity {private EditText editpath;private Button btndown;private Button btnstop;private TextView textresult;private ProgressBar progressbar;private static final int PROCESSING 1; //正在下载实时数据传输Message标志private static final int FAILURE -1; //下载失败时的Message标志private Handler handler new UIHander();private final class UIHander extends Handler{public void handleMessage(Message msg) {switch (msg.what) {//下载时case PROCESSING:int size msg.getData().getInt(size); //从消息中获取已经下载的数据长度progressbar.setProgress(size); //设置进度条的进度//计算已经下载的百分比,此处需要转换为浮点数计算float num (float)progressbar.getProgress() / (float)progressbar.getMax();int result (int)(num * 100); //把获取的浮点数计算结果转换为整数textresult.setText(result %); //把下载的百分比显示到界面控件上if(progressbar.getProgress() progressbar.getMax()){ //下载完成时提示Toast.makeText(getApplicationContext(), 文件下载成功, 1).show();}break;case FAILURE: //下载失败时提示Toast.makeText(getApplicationContext(), 文件下载失败, 1).show();break;}}}Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);editpath (EditText) findViewById(R.id.editpath);btndown (Button) findViewById(R.id.btndown);btnstop (Button) findViewById(R.id.btnstop);textresult (TextView) findViewById(R.id.textresult);progressbar (ProgressBar) findViewById(R.id.progressBar);ButtonClickListener listener new ButtonClickListener();btndown.setOnClickListener(listener);btnstop.setOnClickListener(listener);}private final class ButtonClickListener implements View.OnClickListener{public void onClick(View v) {switch (v.getId()) {case R.id.btndown:String path editpath.getText().toString();if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){File saveDir Environment.getExternalStorageDirectory();download(path, saveDir);}else{Toast.makeText(getApplicationContext(), sd卡读取失败, 1).show();}btndown.setEnabled(false);btnstop.setEnabled(true);break;case R.id.btnstop:exit();btndown.setEnabled(true);btnstop.setEnabled(false);break;}}/*由于用户的输入事件(点击button, 触摸屏幕....)是由主线程负责处理的如果主线程处于工作状态此时用户产生的输入事件如果没能在5秒内得到处理系统就会报“应用无响应”错误。所以在主线程里不能执行一件比较耗时的工作否则会因主线程阻塞而无法处理用户的输入事件导致“应用无响应”错误的出现。耗时的工作应该在子线程里执行。*/private DownloadTask task;/*** 退出下载*/public void exit(){if(task!null) task.exit();}private void download(String path, File saveDir) {//运行在主线程task new DownloadTask(path, saveDir);new Thread(task).start();}/** UI控件画面的重绘(更新)是由主线程负责处理的如果在子线程中更新UI控件的值更新后的值不会重绘到屏幕上* 一定要在主线程里更新UI控件的值这样才能在屏幕上显示出来不能在子线程中更新UI控件的值*/private final class DownloadTask implements Runnable{private String path;private File saveDir;private FileDownloadered loader;public DownloadTask(String path, File saveDir) {this.path path;this.saveDir saveDir;}/*** 退出下载*/public void exit(){if(loader!null) loader.exit();}public void run() {try {loader new FileDownloadered(getApplicationContext(), path, saveDir, 3);progressbar.setMax(loader.getFileSize());//设置进度条的最大刻度loader.download(new com.jay.example.service.DownloadProgressListener() {public void onDownloadSize(int size) {Message msg new Message();msg.what 1;msg.getData().putInt(size, size);handler.sendMessage(msg);}});} catch (Exception e) {e.printStackTrace();handler.sendMessage(handler.obtainMessage(-1));}} }} } Step 8AndroidManifest.xml文件中添加相关权限 !-- 访问internet权限 -- uses-permission android:nameandroid.permission.INTERNET/ !-- 在SDCard中创建与删除文件权限 -- uses-permission android:nameandroid.permission.MOUNT_UNMOUNT_FILESYSTEMS/ !-- 往SDCard写入数据权限 -- uses-permission android:nameandroid.permission.WRITE_EXTERNAL_STORAGE/
http://www.hkea.cn/news/14513966/

相关文章:

  • 绍兴网站建设公司电话肇庆市住房和城乡房屋建设局网站
  • 一家专业做导购的网站网站备案更换
  • 协会网站开发wordpress 后台慢
  • 建设厅网站上的信息采集表还有哪些媲美wordpress框架
  • 哈尔滨手机网站建设价格杭州品牌策划
  • 谁会做网站排名把一个网站挂到网上要怎么做
  • 珠海策划网站建设平台wordpress视频网站主题
  • 做婚恋网站多少钱建设论坛网站需要做什么的
  • 网站设计方案策划安阳哪里有学做网站的学校
  • 宁波做简单网站的网站挣钱怎么做
  • 专门做灯具海报的网站营销型网站更受用户欢迎的原因是
  • 重庆做网站最好的住房和城乡建设部网站执业资格注册中心
  • 网站建设入门解读推广赚钱的平台有哪些
  • joomla做的网站哈尔滨刚刚发生的大事件
  • 电商网站建设与运营实训政务服务 网站 建设方案
  • 女装网站功能的建设江苏网站备案流程图
  • 做字体网站做个企业网站的公司
  • 济南 网站建设公司 医疗东莞58同城网招聘找工作
  • 酒网站模板太仓建设银行网站
  • wordpress企业站主题网上商城下载
  • 如何让网站做成移动版网站模板库免费
  • 网站内部链接优化方法专业的集团网站设计公司
  • 模板建站优点长沙市住房和城乡建设局网站
  • 国际网站建设经验西安房地产网站建设
  • 高端 建站wordpress边栏
  • 个性化定制网站的特点企业邮箱怎么在手机上登录
  • 网站建设无底薪提成wordpress热门分类
  • 网站建设工作汇报济南小程序制作公司
  • 寻找客户的12种方法商丘seo快速排名
  • 网站建设菜单栏设计假网站连接怎么做的