Multi-thread resumable upload for Android

Source: Internet
Author: User

The multi‑thread resumable upload function is used in recent projects. Therefore, it is very convenient to encapsulate a jar package.

Multi-thread resumable download: multiple threads are used to download the same resource. Each download thread is responsible for the download task of a certain part of the resource and is merged into a file. This improves the overall speed; when a thread is interrupted or the network is interrupted, the location where each thread has been downloaded can be saved, when the previous undownloaded resource is downloaded again, it can be restored to the status when it was downloaded again. This saves a lot of traffic and does not need to start the download again.

The following describes some main classes in the jar package:

Dbopenhelper. Java initializes the SQLite database and creates tables.

Package COM. justsy. eleschoolbag. mutildownload; import android. content. context; import android. database. SQLite. sqlitedatabase; import android. database. SQLite. sqliteopenhelper;/*** database operation class ** @ author netizen **/public class dbopenhelper extends sqliteopenhelper {// database name Private Static final string dbname = "down. DB "; Private Static final int version = 1;/*** constructor * @ Param context */Public dbopenhelper (context) {super (context, dbname, null, version) ;}@ overridepublic void oncreate (sqlitedatabase dB) {// create table db.exe csql ("create table if not exists filedownlog (ID integer primary key autoincrement, downpath varchar (100 ), threadid integer, downlength long) ") ;}@ overridepublic void onupgrade (sqlitedatabase dB, int oldversion, int newversion) mongodb.exe csql (" Drop table if exists filedownlog "); oncreate (db );}}

Fileservice. Java adds, deletes, modifies, and queries database tables

Package COM. justsy. eleschoolbag. mutildownload; import Java. util. hashmap; import Java. util. map; import android. content. context; import android. database. cursor; import android. database. SQLite. sqlitedatabase; public class fileservice {private dbopenhelper openhelper; Public fileservice (context) {openhelper = new dbopenhelper (context );} /*** get the object length downloaded by each thread * @ Param path * @ return */Public Map <integer, Long> getdata (string path) {sqlitedatabase DB = openhelper. getreadabledatabase (); cursor = dB. rawquery ("select threadid, downlength from filedownlog where downpath =? ", New string [] {path}); Map <integer, long> DATA = new hashmap <integer, long> (); While (cursor. movetonext () {data. put (cursor. getint (0), cursor. getlong (1);} cursor. close (); dB. close (); return data;}/*** Save the length of the file downloaded by each thread * @ Param path * @ Param map */Public void save (string path, map <integer, long> map) {// int threadid, int positionsqlitedatabase DB = openhelper. getwritabledatabase (); dB. begintransaction (); tr Y {for (Map. Entry <integer, long> entry: map.entryset())mongodb.exe csql ("insert into filedownlog (downpath, threadid, downlength) values (?,?,?) ", New object [] {path, entry. getkey (), entry. getvalue ()});} dB. settransactionsuccessful ();} finally {dB. endtransaction ();} dB. close ();}/*** update the file length downloaded by each thread in real time * @ Param path * @ Param map */Public void Update (string path, Map <integer, long> map) {system. out. println ("map:" + map); sqlitedatabase DB = openhelper. getwritabledatabase (); dB. begintransaction (); try {for (map. entry <integer, long> entry: map. entryset ()){ Db.exe csql ("Update filedownlog set downlength =? Where downpath =? And threadid =? ", New object [] {entry. getvalue (), path, entry. getkey ()});} dB. settransactionsuccessful ();} finally {dB. endtransaction ();} dB. close ();}/*** after the file is downloaded, delete the corresponding download record * @ Param path */Public void Delete (string path) {sqlitedatabase DB = openhelper.getwritabledatabase(mongomongodb.exe csql ("delete from filedownlog where downpath =? ", New object [] {path}); DB. Close ();}}

The filedownloader. Java downloader manages downloads, initializes data, and starts downloading.

Package COM. justsy. eleschoolbag. mutildownload; 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. annotation. suppresslint; import android. content. conte XT; import android. OS. handler; import android. OS. message; import android. util. log;/*** loader * @ author tibib **/@ suppresslint ("defaultlocale") public class filedownloader {Private Static final string tag = "filedownloader"; private context; private fileservice;/* length of the downloaded file */private long downloadsize = 0;/* length of the original file */private long filesize = 0; /* Number of threads */private downloadthread [] threads ;/* Save the file locally */private file SaveFile;/* cache the download length of each thread */private Map <integer, long> DATA = new concurrenthashmap <integer, long> (); /* download length of each thread */private long block;/* download path */private string DownLoadURL;/* download completion handler */private handler finishhandler; /* file storage path */private file filesavedir;/* file name */private string filename;/* Number of threads for enabling download */private int threadnum; /* pause download */private Boolean isrun = true;/*** download the Build File * @ Param DownLoadURL download path * @ Param filesavedir file storage directory * @ Param threadnum download thread count */Public filedownloader (context, Handler finishhandler, string DownLoadURL, file filesavedir, string filename, int threadnum) {This. context = context; this. finishhandler = finishhandler; this. downLoadURL = DownLoadURL; this. filesavedir = filesavedir; this. filename = filename; this. threadnum = threadnum;}/*** start download * @ Throws exception */Public void download () throws exception {// initialization data try {initdata ();} catch (exception e) {Throw E ;} try {randomaccessfile randout = new randomaccessfile (this. saveFile, "RW"); If (this. filesize> 0) 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 (I + 1, 0l); // initialize the length of data downloaded by each thread to 0 }}for (INT I = 0; I <this. threads. length; I ++) {// enable the thread to download long downlength = This. data. get (I + 1); If (downlength <this. block & this. downloadsize <this. filesize) {// determine whether the thread has completed the download; otherwise, continue to download this. threads [I] = new downloadthread (this, URL, this. saveFile, this. block, this. data. get (I + 1), I + 1); this. threads [I]. start (); // thread. sleep (5*1000);} else {This. threads [I] = NULL;} This. fileservice. save (this. downLoadURL, this. data);} catch (exception e) {print (E. tostring (); throw new exception ("File Download fail");}/*** initialize data before download * @ throws exception */private void initdata () throws exception {try {// prepare for pausing and re-Downloading this. downloadsize = 0l; this. isrun = true; this. fileservice = new fileserv Ice (this. context); Url url = new URL (this. DownLoadURL); If (! This. filesavedir. exists () This. filesavedir. mkdirs (); this. threads = new downloadthread [this. threadnum]; httpurlconnection conn = (httpurlconnection) URL. openconnection (); Conn. setconnecttimeout (30*1000); Conn. setrequestmethod ("get"); Conn. setrequestproperty ("accept", "image/GIF, image/JPEG, image/pjpeg, image/pjpeg, application/X-Shockwave-flash, application/XAML + XML, application/vnd. MS-xpsdocument, AP Plication/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.20.6.2152 ;. net CLR 3.5.30729) "); Conn. setrequestproperty ("connection", "keep-alive"); Conn. connect (); printresponseheader (conn); If (Conn. getresponsecode () = 200) {This. filesize = Conn. getcontentlength (); // obtain the file size based on the response if (this. filesize <= 0) throw new runtimeexception ("unkown file size"); // the file name if (this. filename! = NULL &&! "". Equals (this. filename) {This. saveFile = new file (this. filesavedir, this. filename); // construct and save the file} else {// otherwise, obtain the server's file name string filename = getfilename (conn); // obtain the file name this. saveFile = new file (this. filesavedir, filename); // build and save file} Map <integer, long> logdata = This. fileservice. getdata (this. downLoadURL); // obtain the download log. I (TAG, "the database has threads to download data:" + logdata); If (logdata. size ()> 0) {// If a download record exists for (map. entry <integer, long> entry: Logdata. entryset () This. data. put (entry. getkey (), entry. getvalue (); // put the Data Length downloaded by each thread into data} If (this. data. size () = This. threads. length) {// calculate the length of data downloaded by all threads for (INT I = 0; I <this. threads. length; I ++) {This. downloadsize + = This. data. get (I + 1);} print ("downloaded length" + this. downloadsize);} // calculate the length of data downloaded by each thread. This. block = (this. filesize % This. threads. length) = 0? This. filesize/This. threads. length: This. filesize/This. threads. length + 1 ;}else {Throw new exception ("server no response") ;}} catch (exception e) {print (E. tostring (); throw new exception ("Don't connection this URL ");}} /*** get the file name * @ Param conn * @ return */private string getfilename (httpurlconnection conn) {string filename = This. downLoadURL. substring (this. downLoadURL. lastindexof ('/') + 1); If (F Ilename = NULL | "". equals (filename. trim () {// if the file name for (INT I = 0; I ++) {string mine = Conn. getheaderfield (I); If (Mine = NULL) break; 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 "; // a default file name} return filename;} public Boole An isrun () {return isrun;} public void setrun (Boolean isrun) {This. isrun = isrun;}/*** length of the current download * @ return */public long getdownloadsize () {return downloadsize ;} /*** get thread count */Public int getthreadsize () {return threads. length;}/*** get file size * @ return */public long getfilesize () {return filesize;} public handler getfinishhandler () {return finishhandler;} public Map <integer, long> getdata () {return data ;} Public fileservice getfileservice () {return fileservice;} public void setdownloadsize (long downloadsize) {This. downloadsize = downloadsize;}/*** cumulative downloaded size * @ Param size */protected synchronized void append (INT size) {downloadsize + = size; If (downloadsize> = This. filesize) {// download completed // CLEAR database table data this. fileservice. delete (this. downLoadURL); message MSG = new message (); MSG. what = 0; // indicates that the download is completed this. finishhandler. sendme Ssage (MSG);} else {message MSG = new message (); MSG. what =-1; // notify the update download progress this. finishhandler. sendmessage (MSG );}} /*** update the last download location of the specified Thread * @ Param threadid thread ID * @ Param POS the last download location */Public synchronized void Update (INT threadid, long POS) {This. data. put (threadid, POS); this. fileservice. update (this. downLoadURL, this. data);}/*** get download percentage * @ Return percentage */Public int getdownloadpercent () {return (INT) (downloadsi Ze * 100/filesize);}/*** get the HTTP response header field * @ Param HTTP * @ return */public static Map <string, string> gethttpresponseheader (httpurlconnection HTTP) {Map <string, string> header = new linkedhashmap <string, string> (); For (INT I = 0; I ++) {string mine = http. getheaderfield (I); If (Mine = NULL) break; header. put (HTTP. getheaderfieldkey (I), Mine);} return header;}/*** print the HTTP header field * @ Param HTTP */public static Vo Id printresponseheader (httpurlconnection HTTP) {Map <string, string> header = gethttpresponseheader (HTTP); For (map. entry <string, string> entry: header. entryset () {string key = entry. getkey ()! = NULL? Entry. getkey () + ":": ""; print (Key + entry. getvalue () ;}}/*** print log information * @ Param MSG */Private Static void print (string MSG) {log. I (TAG, MSG );}}

Downloadthread. Java downloads the data and status of each thread in real time.

Package COM. justsy. eleschoolbag. mutildownload; import Java. io. file; import Java. io. ioexception; import Java. io. inputstream; import Java. io. randomaccessfile; import java.net. httpurlconnection; import java.net. URL; import android. OS. handler; import android. OS. message; import android. util. log;/*** download Thread class * @ author tibib **/public class downloadthread extends thread {Private Static final string tag = "Download Thread "; private file SaveFile; Private URL downurl; private long block; private int threadid =-1; private long downlength; private filedownloader downloader; /*** constructor ** @ Param downloader * @ Param downurl * @ Param SaveFile storage path * @ Param block the download size of each thread * @ Param downlength * @ Param threadid thread ID */Public downloadthread (filedownloader downloader, URL downurl, file SaveFile, long block, lon G downlength, int threadid) {This. downurl = downurl; this. saveFile = SaveFile; this. block = block; this. downloader = downloader; this. threadid = threadid; this. downlength = downlength;} @ overridepublic void run () {randomaccessfile threadfile = NULL; inputstream instream = NULL; If (downlength <block) {// the download is not completed. Try {// use the get method to download httpurlconnection HTTP = (httpurlconnection) downurl. openconnection (); http. setconne Cttimeout (30*1000); http. setrequestmethod ("get"); http. setrequestproperty ("accept", "image/GIF, image/JPEG, image/pjpeg, image/pjpeg, application/X-Shockwave-flash, application/XAML + XML, 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", "Z H-CN "); http. setrequestproperty ("Referer", downurl. tostring (); http. setrequestproperty ("charset", "UTF-8"); long startpos = block * (threadid-1) + downlength; // start position long endpos = block * threadid-1; // end position HTTP. setrequestproperty ("range", "bytes =" + startpos + "-" + endpos); // you can specify the HTTP range for retrieving object data. 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.20.6.2152 ;. net CLR 3.5.30729) "); http. setrequestproperty ("connection", "keep-alive"); log. I (TAG, "Code:" + HTTP. getresponsecode (); instream = http. getinputstream (); byte [] buffer = new byte [1024*512]; int offset = 0; threadfile = new randomaccessfile (this. saveFile, "RWD"); threadfile. seek (startpos); // whether to read the end and the download tool is in the running status while (Downloader. isrun () & (Offset = instream. Read (buffer ))! =-1) {log. I (TAG, this. threadid + "offset"); threadfile. write (buffer, 0, offset); downlength + = offset; // record the total length of all downloads Downloader. append (offset); // real-time update (too slow) Downloader. update (this. threadid, downlength) ;}} catch (exception e) {// handler finishhandler = downloader is interrupted during thread download. getfinishhandler (); message MSG = new message (); MSG. what = 1; // download failed finishhandler. sendmessage (MSG); // pause downloader download. setrun (false); Prin T ("Thread" + this. threadid + ":" + E) ;}finally {If (instream! = NULL) {try {instream. Close () ;}catch (ioexception e) {e. printstacktrace () ;}} if (threadfile! = NULL) {try {threadfile. close ();} catch (ioexception e) {e. printstacktrace () ;}}} else {print ("Thread" + this. threadid + "Download finish") ;}}/*** print log information * @ Param MSG */Private Static void print (string MSG) {log. I (TAG, MSG );}}

Jar package (with source code), with an instance, uploaded later

Source code example:

Http://download.csdn.net/detail/tibib/4905964

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.