Details
Background
The size of files that can be downloaded to the BlackBerry smartphone using the BlackBerry® Mobile Data System (BlackBerry MDS) is limited due to storage availability on the BlackBerry smartphone and the cost of transferring data wirelessly. The BlackBerry MDS uses the Multipurpose Internet Mail Extensions (MIME) type reported by the web server to determine which file limit should be applied. This file limit may also include any additional overhead from the web server, and will apply both before and after transcoding is done by the BlackBerry MDS. BlackBerry MDS provides a response code of 413 if the file size is too big. For standard Hypertext Transfer Protocol (HTTP) file downloading, as is done in the following example, there is no additional overhead or transcoding. For more information on BlackBerry MDS file settings and response code 413, see this article.
HTTP Range request header
If it is supported by the server, the Range header can be used to make individual requests for parts of a file. By keeping these file range requests below the limit of an individual file, larger files can be downloaded in parts and recombined on the BlackBerry smartphone. The file does not have to be separated into chunks on the server using this approach. The following example uses the Range header to request a file in several parts.
Note: The use of response code 206 for partial content and downloading the file correctly is based entirely on calculating the correct byte range to request. The same approach could be used to resume downloading interrupted transfers.
private class DownloadCombiner extends Thread { private String remoteName; private String localName; private int connection; private int chunksize; public DownloadCombiner(String remoteName, String localName, int connection, int chunksize) { this.remoteName = remoteName; this.localName = localName; this.connection = connection; this.chunksize = chunksize; } public void run() { try { int chunkIndex = 0; int totalSize = 0; /* * File connection */ FileConnection file =(FileConnection)Connector.open(localName); if (!file.exists()) { file.create(); file.setWritable(true); OutputStream out = file.openOutputStream(); /* * HTTP Connections */ String currentFile = remoteName + connectionType(); log("Full URL: " + currentFile); HttpConnection conn; InputStream in; int rangeStart = 0; int rangeEnd = 0; while (true) { log("Opening Chunk: " + chunkIndex); conn = (HttpConnection) Connector.open(currentFile, Connector.READ_WRITE, true); rangeStart = chunkIndex * chunksize; rangeEnd = rangeStart + chunksize - 1; log("Requesting Range: " + rangeStart + "-" + rangeEnd); conn.setRequestProperty("Range", "bytes=" + rangeStart + "-" + rangeEnd); int responseCode = conn.getResponseCode(); if (responseCode != 200 && responseCode != 206) { log("Response Code = " + conn.getResponseCode()); break; } log("Retreived Range: " + conn.getHeaderField("Content-Range")); in = conn.openInputStream(); int length = -1; byte[] readBlock = new byte[256]; int fileSize = 0; while ((length = in.read(readBlock)) != -1) { out.write(readBlock, 0, length); fileSize += length; Thread.yield(); // Try not to get cut off } totalSize += fileSize; log("Chunk Downloaded: " + fileSize + " Bytes"); chunkIndex++; // index (range) increase in.close(); conn.close(); in = null; conn = null; /* * Pause to allow connections to close and other Threads * to run. */ Thread.sleep(1000); } log("Full file downloaded: " + totalSize + " Bytes"); out.close(); file.close(); log("Wrote file to local storage"); } catch (Exception e) { log(e.toString()); } } private String connectionType() { switch (connection) { case 1: return ";deviceside=false"; case 2: return ";deviceside=true;interface=wifi"; default: return ";deviceside=true"; } } }
File splitting
A large file can be downloaded to the BlackBerry smartphone by splitting the file into multiple parts and then downloading each part to the microSD card, where the parts can be recombined into the original file.
The following code segment describes a scheme for splitting a file into defined part sizes. The file parts are labeled with the original filename and a part ID.
public void splitFile() throws Exception { BufferedInputStream input = new BufferedInputStream(new FileInputStream(_file)); byte[] readBlock = new byte[_chunksize]; int chunkFileId = 0; int length = -1; while ((length = input.read(readBlock)) != -1) { String chunkFileName = _file.getName() + "." + chunkFileId++; BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(chunkFileName)); output.write(readBlock, 0, length); output.flush(); output.close(); System.out.println("Wrote Chunk file " + chunkFileName + " of " + length + " Bytes"); } System.out.println("Completed Splitting " + _file.getName()); }
File downloading
Once the file has been split into a series of parts, each part can be downloaded in order and written out to one file on the microSD card.
Note: The response code is used to determine whether the part exists. If the part does not exist, the downloading process is completed.
private class DownloadCombiner extends Thread { private String remoteName; private String localName; private int connection; public DownloadCombiner(String remoteName, String localName) { this.remoteName = remoteName; this.localName = localName; } public void run() { try { int chunkIndex = 0; int totalSize = 0; FileConnection file = (FileConnection) Connector.open(localName); if (!file.exists()) { file.create(); } file.setWritable(true); OutputStream out = file.openOutputStream(); HttpConnection conn; InputStream in; while (true) { System.out.println("Opening Chunk: " + chunkIndex); String currentFile = remoteName + "." + chunkIndex++; conn = (HttpConnection) Connector.open(currentFile); if (conn.getResponseCode() != 200) { System.out.println("Response Code = " + conn.getResponseCode()); break; } in = conn.openInputStream(); int length = -1; byte[] readBlock = new byte[256]; int fileSize = 0; while ((length = in.read(readBlock)) != -1) { out.write(readBlock, 0, length); fileSize += length; } totalSize += fileSize; System.out.println("Chunk Downloaded: " + fileSize + " Bytes"); in.close(); conn.close(); in = null; conn = null; Thread.yield(); // allow other threads time } System.out.println("Full file downloaded: " + totalSize + " Bytes"); out.close(); file.close(); System.out.println("Wrote file to local storage"); } catch (Exception e) { System.err.println(e.toString()); } } }
鸟E文,比看甲骨文还头疼。
英语太差,求翻译,囧er
不错收了,一个不错的多线程下载案例。
哟哟最近在开发黑莓?