1. 程式人生 > >Android中Socket大文件斷點上傳

Android中Socket大文件斷點上傳

lai 大於 兩個類 bundle use 分配 1.0 應該 subst

什麽是Socket?

所謂Socket通常也稱作“套接字”,用於描述IP地址和端口,是一個通信連的句柄,應用程序通常通過“套接字”向網絡發送請求或者應答網絡請求,它就是網絡通信過程中端點的抽象表示。它主要包括以下兩個協議:

TCP (Transmission Control Protocol 傳輸控制協議):傳輸控制協議,提供的是面向連接、可靠的字節流服務。當客戶和服務器彼此交換數據前,必須先在雙方之間建立一個TCP連接,之後才能傳輸數據。TCP提供超時重發,丟棄重復數據,檢驗數據,流量控制等功能,保證數據能從一端傳到另一端。

UDP (User Datagram Protocl 用戶數據報協議):用戶數據報協議,是一個簡單的面向數據報的運輸層協議。UDP不提供可靠性,它只是把應用程序傳給IP層的數據報發送出去,但是並不能保證它們能到達目的地。由於UDP在傳輸數據報前不用在客戶和服務器之間建立一個連接,且沒有超時重發等機制,故而傳輸速度很快。

詳細解說如下:

TCP傳輸和UDP不一樣,TCP傳輸是流式的,必須先建立連接,然後數據流沿已連接的線路(虛電路)傳輸。因此TCP的數據流不會像UDP數據報一樣,每個數據報都要包含目標地址和端口,因為每個數據報要單獨路由。TCP傳輸則只需要在建立連接時指定目標地址和端口就可以了。

  形象的講,TCP就像打電話,UDP就像發電報。宏觀上來看UDP是不分客戶端和服務端的。通信雙方是平等的。微觀上來講只相對一個報文,發送端是客戶端,監聽端是服務端。發送端把數據報發給路由器就像把電報發給了郵局,後面的事情就是發送者無法控制,也無從知曉的了。所以說是不可靠的,可能會出現報文丟失而無從知曉。就像每張電報都要有收件人一樣,每個數據報都要有目的地址和端口。

  而TCP每次連接都是分客戶端和服務端的。連接的發起者(相當與撥號打電話的人)是客戶端,監聽者(相當於在電話邊等著接電話的人)是服務端。發起者指定要連接的服務器地址和端口(相當於撥號),監聽者通過和發起者三次握手建立連接(相當於聽到電話響去接電話)。建立連接後雙方可以互相發送和接受數據(打電話)。

Java如何操作Socket?

值得一提的是,Java分別為TCP和UDP提供了相應的類,TCP是java.NET中提供了兩個類Socket和ServerSocket,分別用來表示雙向連接的客戶端和服務端。這是兩個封裝得非常好的類,使用起來很方便!UDP是java.net.DatagramSocket.

127.0.0.1是回路地址,用於測試,相當於localhost本機地址,沒有網卡,不設DNS都可以訪問,端口地址在0~65535之間,其中0~1023之間的端口是用於一些知名的網絡服務和應用,用戶的普通網絡應用程序應該使用1024以上的端口.

Socket通信模型如下:

技術分享

如果大家對Java Socket編程還有模糊的地方抓緊溫習(http://blog.csdn.net/shimiso/article/details/8529941),本文不在此贅述,下面我們以最常用的TCP協議舉例:

服務器,使用ServerSocket監聽指定的端口,端口可以隨意指定(由於1024以下的端口通常屬於保留端口,在一些操作系統中不可以隨意使用,所以建議使用大於1024的端口),等待客戶連接請求,客戶連接後,會話產生;在完成會話後,關閉連接。
客戶端,使用java socket通信對網絡上某一個服務器的某一個端口發出連接請求,一旦連接成功,打開會話;會話完成後,關閉Socket。客戶端不需要指定打開的端口,通常臨時的、動態的分配一個1024以上的端口。

TCP網絡連接模型:

技術分享

技術分享

Android客戶端程序代分析:

[java] view plain copy
  1. UploadActivity.java
  2. package com.android.upload;
  3. import java.io.File;
  4. import java.io.OutputStream;
  5. import java.io.PushbackInputStream;
  6. import java.io.RandomAccessFile;
  7. import java.net.Socket;
  8. import android.app.Activity;
  9. import android.os.Bundle;
  10. import android.os.Environment;
  11. import android.os.Handler;
  12. import android.os.Message;
  13. import android.view.View;
  14. import android.view.View.OnClickListener;
  15. import android.widget.Button;
  16. import android.widget.EditText;
  17. import android.widget.ProgressBar;
  18. import android.widget.TextView;
  19. import android.widget.Toast;
  20. import com.android.service.UploadLogService;
  21. import com.android.socket.utils.StreamTool;
  22. public class UploadActivity extends Activity {
  23. private EditText filenameText;
  24. private TextView resulView;
  25. private ProgressBar uploadbar;
  26. private UploadLogService logService;
  27. private boolean start=true;
  28. private Handler handler = new Handler(){
  29. @Override
  30. public void handleMessage(Message msg) {
  31. int length = msg.getData().getInt("size");
  32. uploadbar.setProgress(length);
  33. float num = (float)uploadbar.getProgress()/(float)uploadbar.getMax();
  34. int result = (int)(num * 100);
  35. resulView.setText(result+ "%");
  36. if(uploadbar.getProgress()==uploadbar.getMax()){
  37. Toast.makeText(UploadActivity.this, R.string.success, 1).show();
  38. }
  39. }
  40. };
  41. @Override
  42. public void onCreate(Bundle savedInstanceState) {
  43. super.onCreate(savedInstanceState);
  44. setContentView(R.layout.main);
  45. logService = new UploadLogService(this);
  46. filenameText = (EditText)this.findViewById(R.id.filename);
  47. uploadbar = (ProgressBar) this.findViewById(R.id.uploadbar);
  48. resulView = (TextView)this.findViewById(R.id.result);
  49. Button button =(Button)this.findViewById(R.id.button);
  50. Button button1 =(Button)this.findViewById(R.id.stop);
  51. button1 .setOnClickListener(new OnClickListener() {
  52. @Override
  53. public void onClick(View v) {
  54. start=false;
  55. }
  56. });
  57. button.setOnClickListener(new View.OnClickListener() {
  58. @Override
  59. public void onClick(View v) {
  60. start=true;
  61. String filename = filenameText.getText().toString();
  62. if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
  63. File uploadFile = new File(Environment.getExternalStorageDirectory(), filename);
  64. if(uploadFile.exists()){
  65. uploadFile(uploadFile);
  66. }else{
  67. Toast.makeText(UploadActivity.this, R.string.filenotexsit, 1).show();
  68. }
  69. }else{
  70. Toast.makeText(UploadActivity.this, R.string.sdcarderror, 1).show();
  71. }
  72. }
  73. });
  74. }
  75. /**
  76. * 上傳文件
  77. * @param uploadFile
  78. */
  79. private void uploadFile(final File uploadFile) {
  80. new Thread(new Runnable() {
  81. @Override
  82. public void run() {
  83. try {
  84. uploadbar.setMax((int)uploadFile.length());
  85. String souceid = logService.getBindId(uploadFile);
  86. String head = "Content-Length="+ uploadFile.length() + ";filename="+ uploadFile.getName() + ";sourceid="+
  87. (souceid==null? "" : souceid)+"\r\n";
  88. Socket socket = new Socket("192.168.1.78",7878);
  89. OutputStream outStream = socket.getOutputStream();
  90. outStream.write(head.getBytes());
  91. PushbackInputStream inStream = new PushbackInputStream(socket.getInputStream());
  92. String response = StreamTool.readLine(inStream);
  93. String[] items = response.split(";");
  94. String responseid = items[0].substring(items[0].indexOf("=")+1);
  95. String position = items[1].substring(items[1].indexOf("=")+1);
  96. if(souceid==null){//代表原來沒有上傳過此文件,往數據庫添加一條綁定記錄
  97. logService.save(responseid, uploadFile);
  98. }
  99. RandomAccessFile fileOutStream = new RandomAccessFile(uploadFile, "r");
  100. fileOutStream.seek(Integer.valueOf(position));
  101. byte[] buffer = new byte[1024];
  102. int len = -1;
  103. int length = Integer.valueOf(position);
  104. while(start&&(len = fileOutStream.read(buffer)) != -1){
  105. outStream.write(buffer, 0, len);
  106. length += len;
  107. Message msg = new Message();
  108. msg.getData().putInt("size", length);
  109. handler.sendMessage(msg);
  110. }
  111. fileOutStream.close();
  112. outStream.close();
  113. inStream.close();
  114. socket.close();
  115. if(length==uploadFile.length()) logService.delete(uploadFile);
  116. } catch (Exception e) {
  117. e.printStackTrace();
  118. }
  119. }
  120. }).start();
  121. }
  122. }
  123. StreamTool.java
  124. package com.android.socket.utils;
  125. import java.io.ByteArrayOutputStream;
  126. import java.io.File;
  127. import java.io.FileOutputStream;
  128. import java.io.IOException;
  129. import java.io.InputStream;
  130. import java.io.PushbackInputStream;
  131. public class StreamTool {
  132. public static void save(File file, byte[] data) throws Exception {
  133. FileOutputStream outStream = new FileOutputStream(file);
  134. outStream.write(data);
  135. outStream.close();
  136. }
  137. public static String readLine(PushbackInputStream in) throws IOException {
  138. char buf[] = new char[128];
  139. int room = buf.length;
  140. int offset = 0;
  141. int c;
  142. loop: while (true) {
  143. switch (c = in.read()) {
  144. case -1:
  145. case ‘\n‘:
  146. break loop;
  147. case ‘\r‘:
  148. int c2 = in.read();
  149. if ((c2 != ‘\n‘) && (c2 != -1)) in.unread(c2);
  150. break loop;
  151. default:
  152. if (--room < 0) {
  153. char[] lineBuffer = buf;
  154. buf = new char[offset + 128];
  155. room = buf.length - offset - 1;
  156. System.arraycopy(lineBuffer, 0, buf, 0, offset);
  157. }
  158. buf[offset++] = (char) c;
  159. break;
  160. }
  161. }
  162. if ((c == -1) && (offset == 0)) return null;
  163. return String.copyValueOf(buf, 0, offset);
  164. }
  165. /**
  166. * 讀取流
  167. * @param inStream
  168. * @return 字節數組
  169. * @throws Exception
  170. */
  171. public static byte[] readStream(InputStream inStream) throws Exception{
  172. ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
  173. byte[] buffer = new byte[1024];
  174. int len = -1;
  175. while( (len=inStream.read(buffer)) != -1){
  176. outSteam.write(buffer, 0, len);
  177. }
  178. outSteam.close();
  179. inStream.close();
  180. return outSteam.toByteArray();
  181. }
  182. }
  183. UploadLogService.java
  184. package com.android.service;
  185. import java.io.File;
  186. import android.content.Context;
  187. import android.database.Cursor;
  188. import android.database.sqlite.SQLiteDatabase;
  189. public class UploadLogService {
  190. private DBOpenHelper dbOpenHelper;
  191. public UploadLogService(Context context){
  192. this.dbOpenHelper = new DBOpenHelper(context);
  193. }
  194. public void save(String sourceid, File uploadFile){
  195. SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
  196. db.execSQL("insert into uploadlog(uploadfilepath, sourceid) values(?,?)",
  197. new Object[]{uploadFile.getAbsolutePath(),sourceid});
  198. }
  199. public void delete(File uploadFile){
  200. SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
  201. db.execSQL("delete from uploadlog where uploadfilepath=?", new Object[]{uploadFile.getAbsolutePath()});
  202. }
  203. public String getBindId(File uploadFile){
  204. SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
  205. Cursor cursor = db.rawQuery("select sourceid from uploadlog where uploadfilepath=?",
  206. new String[]{uploadFile.getAbsolutePath()});
  207. if(cursor.moveToFirst()){
  208. return cursor.getString(0);
  209. }
  210. return null;
  211. }
  212. }
  213. DBOpenHelper.java
  214. package com.android.service;
  215. import android.content.Context;
  216. import android.database.sqlite.SQLiteDatabase;
  217. import android.database.sqlite.SQLiteOpenHelper;
  218. public class DBOpenHelper extends SQLiteOpenHelper {
  219. public DBOpenHelper(Context context) {
  220. super(context, "upload.db", null, 1);
  221. }
  222. @Override
  223. public void onCreate(SQLiteDatabase db) {
  224. db.execSQL("CREATE TABLE uploadlog (_id integer primary key autoincrement, uploadfilepath varchar(100), sourceid varchar(10))");
  225. }
  226. @Override
  227. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  228. db.execSQL("DROP TABLE IF EXISTS uploadlog");
  229. onCreate(db);
  230. }
  231. }
  232. main.xml
  233. <?xml version="1.0" encoding="utf-8"?>
  234. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  235. android:orientation="vertical"
  236. android:layout_width="fill_parent"
  237. android:layout_height="fill_parent"
  238. >
  239. <TextView
  240. android:layout_width="fill_parent"
  241. android:layout_height="wrap_content"
  242. android:text="@string/filename"
  243. />
  244. <EditText
  245. android:layout_width="fill_parent"
  246. android:layout_height="wrap_content"
  247. android:text="022.jpg"
  248. android:id="@+id/filename"
  249. />
  250. <Button
  251. android:layout_width="wrap_content"
  252. android:layout_height="wrap_content"
  253. android:text="@string/button"
  254. android:id="@+id/button"
  255. />
  256. <Button
  257. android:layout_width="wrap_content"
  258. android:layout_height="wrap_content"
  259. android:text="暫停"
  260. android:id="@+id/stop"
  261. />
  262. <ProgressBar
  263. android:layout_width="fill_parent"
  264. android:layout_height="20px"
  265. style="?android:attr/progressBarStyleHorizontal"
  266. android:id="@+id/uploadbar"
  267. />
  268. <TextView
  269. android:layout_width="fill_parent"
  270. android:layout_height="wrap_content"
  271. android:gravity="center"
  272. android:id="@+id/result"
  273. />
  274. </LinearLayout>
  275. AndroidManifest.xml
  276. <?xml version="1.0" encoding="utf-8"?>
  277. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  278. package="com.android.upload"
  279. android:versionCode="1"
  280. android:versionName="1.0" >
  281. <uses-sdk android:minSdkVersion="8" />
  282. <application
  283. android:icon="@drawable/ic_launcher"
  284. android:label="@string/app_name" >
  285. <activity
  286. android:name=".UploadActivity"
  287. android:label="@string/app_name" >
  288. <intent-filter>
  289. <action android:name="android.intent.action.MAIN" />
  290. <category android:name="android.intent.category.LAUNCHER" />
  291. </intent-filter>
  292. </activity>
  293. </application>
  294. <!-- 訪問網絡的權限 -->
  295. <uses-permission android:name="android.permission.INTERNET"/>
  296. <!-- 在SDCard中創建與刪除文件權限 -->
  297. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
  298. <!-- 往SDCard寫入數據權限 -->
  299. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  300. </manifest>

Java服務端:

[java] view plain copy
  1. SocketServer.javapackage com.android.socket.server;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.FileOutputStream;
  5. import java.io.IOException;
  6. import java.io.OutputStream;
  7. import java.io.PushbackInputStream;
  8. import java.io.RandomAccessFile;
  9. import java.net.ServerSocket;
  10. import java.net.Socket;
  11. import java.text.SimpleDateFormat;
  12. import java.util.Date;
  13. import java.util.HashMap;
  14. import java.util.Map;
  15. import java.util.Properties;
  16. import java.util.concurrent.ExecutorService;
  17. import java.util.concurrent.Executors;
  18. import com.android.socket.utils.StreamTool;
  19. public class SocketServer {
  20. private String uploadPath="D:/uploadFile/";
  21. private ExecutorService executorService;// 線程池
  22. private ServerSocket ss = null;
  23. private int port;// 監聽端口
  24. private boolean quit;// 是否退出
  25. private Map<Long, FileLog> datas = new HashMap<Long, FileLog>();// 存放斷點數據,最好改為數據庫存放
  26. public SocketServer(int port) {
  27. this.port = port;
  28. // 初始化線程池
  29. executorService = Executors.newFixedThreadPool(Runtime.getRuntime()
  30. .availableProcessors() * 50);
  31. }
  32. // 啟動服務
  33. public void start() throws Exception {
  34. ss = new ServerSocket(port);
  35. while (!quit) {
  36. Socket socket = ss.accept();// 接受客戶端的請求
  37. // 為支持多用戶並發訪問,采用線程池管理每一個用戶的連接請求
  38. executorService.execute(new SocketTask(socket));// 啟動一個線程來處理請求
  39. }
  40. }
  41. // 退出
  42. public void quit() {
  43. this.quit = true;
  44. try {
  45. ss.close();
  46. } catch (IOException e) {
  47. e.printStackTrace();
  48. }
  49. }
  50. public static void main(String[] args) throws Exception {
  51. SocketServer server = new SocketServer(7878);
  52. server.start();
  53. }
  54. private class SocketTask implements Runnable {
  55. private Socket socket;
  56. public SocketTask(Socket socket) {
  57. this.socket = socket;
  58. }
  59. @Override
  60. public void run() {
  61. try {
  62. System.out.println("accepted connenction from "
  63. + socket.getInetAddress() + " @ " + socket.getPort());
  64. PushbackInputStream inStream = new PushbackInputStream(
  65. socket.getInputStream());
  66. // 得到客戶端發來的第一行協議數據:Content-Length=143253434;filename=xxx.3gp;sourceid=
  67. // 如果用戶初次上傳文件,sourceid的值為空。
  68. String head = StreamTool.readLine(inStream);
  69. System.out.println(head);
  70. if (head != null) {
  71. // 下面從協議數據中讀取各種參數值
  72. String[] items = head.split(";");
  73. String filelength = items[0].substring(items[0].indexOf("=") + 1);
  74. String filename = items[1].substring(items[1].indexOf("=") + 1);
  75. String sourceid = items[2].substring(items[2].indexOf("=") + 1);
  76. Long id = System.currentTimeMillis();
  77. FileLog log = null;
  78. if (null != sourceid && !"".equals(sourceid)) {
  79. id = Long.valueOf(sourceid);
  80. log = find(id);//查找上傳的文件是否存在上傳記錄
  81. }
  82. File file = null;
  83. int position = 0;
  84. if(log==null){//如果上傳的文件不存在上傳記錄,為文件添加跟蹤記錄
  85. String path = new SimpleDateFormat("yyyy/MM/dd/HH/mm").format(new Date());
  86. File dir = new File(uploadPath+ path);
  87. if(!dir.exists()) dir.mkdirs();
  88. file = new File(dir, filename);
  89. if(file.exists()){//如果上傳的文件發生重名,然後進行改名
  90. filename = filename.substring(0, filename.indexOf(".")-1)+ dir.listFiles().length+ filename.substring(filename.indexOf("."));
  91. file = new File(dir, filename);
  92. }
  93. save(id, file);
  94. }else{// 如果上傳的文件存在上傳記錄,讀取上次的斷點位置
  95. file = new File(log.getPath());//從上傳記錄中得到文件的路徑
  96. if(file.exists()){
  97. File logFile = new File(file.getParentFile(), file.getName()+".log");
  98. if(logFile.exists()){
  99. Properties properties = new Properties();
  100. properties.load(new FileInputStream(logFile));
  101. position = Integer.valueOf(properties.getProperty("length"));//讀取斷點位置
  102. }
  103. }
  104. }
  105. OutputStream outStream = socket.getOutputStream();
  106. String response = "sourceid="+ id+ ";position="+ position+ "\r\n";
  107. //服務器收到客戶端的請求信息後,給客戶端返回響應信息:sourceid=1274773833264;position=0
  108. //sourceid由服務生成,唯一標識上傳的文件,position指示客戶端從文件的什麽位置開始上傳
  109. outStream.write(response.getBytes());
  110. RandomAccessFile fileOutStream = new RandomAccessFile(file, "rwd");
  111. if(position==0) fileOutStream.setLength(Integer.valueOf(filelength));//設置文件長度
  112. fileOutStream.seek(position);//移動文件指定的位置開始寫入數據
  113. byte[] buffer = new byte[1024];
  114. int len = -1;
  115. int length = position;
  116. while( (len=inStream.read(buffer)) != -1){//從輸入流中讀取數據寫入到文件中
  117. fileOutStream.write(buffer, 0, len);
  118. length += len;
  119. Properties properties = new Properties();
  120. properties.put("length", String.valueOf(length));
  121. FileOutputStream logFile = new FileOutputStream(new File(file.getParentFile(), file.getName()+".log"));
  122. properties.store(logFile, null);//實時記錄文件的最後保存位置
  123. logFile.close();
  124. }
  125. if(length==fileOutStream.length()) delete(id);
  126. fileOutStream.close();
  127. inStream.close();
  128. outStream.close();
  129. file = null;
  130. }
  131. } catch (Exception e) {
  132. e.printStackTrace();
  133. } finally {
  134. try {
  135. if(socket != null && !socket.isClosed()) socket.close();
  136. } catch (IOException e) {}
  137. }
  138. }
  139. }
  140. public FileLog find(Long sourceid) {
  141. return datas.get(sourceid);
  142. }
  143. // 保存上傳記錄
  144. public void save(Long id, File saveFile) {
  145. // 日後可以改成通過數據庫存放
  146. datas.put(id, new FileLog(id, saveFile.getAbsolutePath()));
  147. }
  148. // 當文件上傳完畢,刪除記錄
  149. public void delete(long sourceid) {
  150. if (datas.containsKey(sourceid))
  151. datas.remove(sourceid);
  152. }
  153. private class FileLog {
  154. private Long id;
  155. private String path;
  156. public FileLog(Long id, String path) {
  157. super();
  158. this.id = id;
  159. this.path = path;
  160. }
  161. public Long getId() {
  162. return id;
  163. }
  164. public void setId(Long id) {
  165. this.id = id;
  166. }
  167. public String getPath() {
  168. return path;
  169. }
  170. public void setPath(String path) {
  171. this.path = path;
  172. }
  173. }
  174. }
  175. ServerWindow.javapackage com.android.socket.server;
  176. import java.awt.BorderLayout;
  177. import java.awt.Frame;
  178. import java.awt.Label;
  179. import java.awt.event.WindowEvent;
  180. import java.awt.event.WindowListener;
  181. public class ServerWindow extends Frame{
  182. private SocketServer server;
  183. private Label label;
  184. public ServerWindow(String title){
  185. super(title);
  186. server = new SocketServer(7878);
  187. label = new Label();
  188. add(label, BorderLayout.PAGE_START);
  189. label.setText("服務器已經啟動");
  190. this.addWindowListener(new WindowListener() {
  191. @Override
  192. public void windowOpened(WindowEvent e) {
  193. new Thread(new Runnable() {
  194. @Override
  195. public void run() {
  196. try {
  197. server.start();
  198. } catch (Exception e) {
  199. e.printStackTrace();
  200. }
  201. }
  202. }).start();
  203. }
  204. @Override
  205. public void windowIconified(WindowEvent e) {
  206. }
  207. @Override
  208. public void windowDeiconified(WindowEvent e) {
  209. }
  210. @Override
  211. public void windowDeactivated(WindowEvent e) {
  212. }
  213. @Override
  214. public void windowClosing(WindowEvent e) {
  215. server.quit();
  216. System.exit(0);
  217. }
  218. @Override
  219. public void windowClosed(WindowEvent e) {
  220. }
  221. @Override
  222. public void windowActivated(WindowEvent e) {
  223. }
  224. });
  225. }
  226. /**
  227. * @param args
  228. */
  229. public static void main(String[] args) {
  230. ServerWindow window = new ServerWindow("文件上傳服務端");
  231. window.setSize(300, 300);
  232. window.setVisible(true);
  233. }
  234. }
  235. StreamTool.javapackage com.android.socket.utils;
  236. import java.io.ByteArrayOutputStream;
  237. import java.io.File;
  238. import java.io.FileOutputStream;
  239. import java.io.IOException;
  240. import java.io.InputStream;
  241. import java.io.PushbackInputStream;
  242. public class StreamTool {
  243. public static void save(File file, byte[] data) throws Exception {
  244. FileOutputStream outStream = new FileOutputStream(file);
  245. outStream.write(data);
  246. outStream.close();
  247. }
  248. public static String readLine(PushbackInputStream in) throws IOException {
  249. char buf[] = new char[128];
  250. int room = buf.length;
  251. int offset = 0;
  252. int c;
  253. loop: while (true) {
  254. switch (c = in.read()) {
  255. case -1:
  256. case ‘\n‘:
  257. break loop;
  258. case ‘\r‘:
  259. int c2 = in.read();
  260. if ((c2 != ‘\n‘) && (c2 != -1)) in.unread(c2);
  261. break loop;
  262. default:
  263. if (--room < 0) {
  264. char[] lineBuffer = buf;
  265. buf = new char[offset + 128];
  266. room = buf.length - offset - 1;
  267. System.arraycopy(lineBuffer, 0, buf, 0, offset);
  268. }
  269. buf[offset++] = (char) c;
  270. break;
  271. }
  272. }
  273. if ((c == -1) && (offset == 0)) return null;
  274. return String.copyValueOf(buf, 0, offset);
  275. }
  276. /**
  277. * 讀取流
  278. * @param inStream
  279. * @return 字節數組
  280. * @throws Exception
  281. */
  282. public static byte[] readStream(InputStream inStream) throws Exception{
  283. ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
  284. byte[] buffer = new byte[1024];
  285. int len = -1;
  286. while( (len=inStream.read(buffer)) != -1){
  287. outSteam.write(buffer, 0, len);
  288. }
  289. outSteam.close();
  290. inStream.close();
  291. return outSteam.toByteArray();
  292. }
  293. }

運行效果如下:
android前端控制:
技術分享

後臺監控日誌:

技術分享

下載後的文件路徑:

技術分享

源碼下載地址

Android中Socket大文件斷點上傳