java支援大檔案斷點傳輸的Socket

來源:互聯網
上載者:User

本文將要介紹的是如何使用線程池來建立Socket服務,並支援大檔案的斷點續傳

首先我們建立一個工具類:

package com.android.server.util;import java.io.ByteArrayOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.PushbackInputStream;public class StreamTool {/** * 儲存檔案 *  * @param file *            檔案路徑 * @param data *            位元組碼資料 * @throws Exception */public static void save(File file, byte[] data) throws Exception {FileOutputStream fileOutputStream = new FileOutputStream(file);fileOutputStream.write(data);fileOutputStream.close();}/** * 讀取一行 * @param in  輸入資料流 * @return 字元竄 * @throws IOException */public static String readLine(PushbackInputStream in) throws IOException {char[] buf = new char[128];int room = buf.length;int offset = 0;int c;loop: while (true) {switch (c = in.read()) {case -1:case '\n':break loop;case '\r':int c2 = in.read();if (c2 != '\n' && c2 != -1)in.unread(c2);break loop;default:if (--room < 0) {char[] lineBuffer = buf;buf = new char[offset + 128];room = buf.length - offset - 1;System.arraycopy(lineBuffer, 0, buf, 0, offset);}buf[offset++] = (char) c;break;}}if (c == -1 && offset == 0)return null;return String.copyValueOf(buf,0,offset);}/** * 讀取流 * @param inStream  * @return 位元組數 * @throws Exception */public static byte[] readStream(InputStream inStream) throws Exception{ByteArrayOutputStream outputStream=new ByteArrayOutputStream();byte [] buf=new byte[1024];int len=-1;while((len=inStream.read(buf))!=1){outputStream.write(buf,0,len);}outputStream.close();inStream.close();return outputStream.toByteArray();}}

這個工具類主要實現檔案的讀寫工作。

下面我們來看一下這個Socket怎麼寫

請看代碼:

package com.android.server;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;import java.io.PushbackInputStream;import java.io.RandomAccessFile;import java.net.ServerSocket;import java.net.Socket;import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.Map;import java.util.Properties;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import com.android.server.util.StreamTool;public class SocketServer {private ExecutorService executorService;// 線程池private ServerSocket server = null;private int port;// 監聽private boolean quit;// 是否推出退出private Map<Long, FileLog> datas = new HashMap<Long, FileLog>();// 存放斷點資料public SocketServer(int port) {this.port = port;// 初始化線程池executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 50);// 擷取cpu目,cpu越多獲得的線程越多}public void start() throws IOException {server = new ServerSocket(port);while (!quit) {Socket socket = server.accept();//接受到用戶端的請求executorService.execute(new SocketTask(socket));//使用線程池系統管理使用者並發}}public void quit(){this.quit=true;try {server.close();} catch (Exception e) {e.printStackTrace();}}private class SocketTask implements Runnable {private Socket socket;public SocketTask(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {System.out.println("accepted connection from"+ socket.getInetAddress() + "@" + socket.getPort());PushbackInputStream inputStream = new PushbackInputStream(socket.getInputStream());// 得到客戶端發來的第一行數據:Content-Length=143253434;filename=xxx.3gp;sourceid=// 如果第一次請求sourceid為空白String head = StreamTool.readLine(inputStream);System.out.println(head);if (head != null) {String[] items = head.split(";");String fileLength = items[0].substring(items[0].indexOf("=") + 1);String fileName = items[1].substring(items[1].indexOf("=") + 1);String sourceId = items[2].substring(items[2].indexOf("=") + 1);long id = System.currentTimeMillis();// 檔案idFileLog log = null;if (null != sourceId && !"".equals(sourceId)) {id = Long.valueOf(sourceId);log = find(id);// 尋找檔案是否存在上傳記錄}File file = null;// 儲存的檔案int position = 0;// 斷點位置// 如果上傳的檔案不存在上傳記錄,為檔案添加追蹤記錄if (log == null) {String path = new SimpleDateFormat("yyyy/MM/dd/HH/mm/ss").format(new Date());File dir = new File("file/" + path);if (!dir.exists())dir.mkdirs();file = new File(dir, fileName);// 建立上傳檔案if (file.exists()) {// 如果檔案存在則改名fileName = fileName.substring(0,fileName.indexOf("."))+ dir.listFiles().length+ fileName.substring(fileName.indexOf("."));file = new File(dir, fileName);}save(id, file);} else {// 如果存在檔案斷點,讀取上次的檔案file = new File(log.getPath());if (file.exists()) {File logFile = new File(file.getParentFile(),file.getName() + ".log");if (logFile.exists()) {Properties properties = new Properties();properties.load(new FileInputStream(logFile));position = Integer.valueOf(properties.getProperty("length"));// 讀取斷點的位置}}}// 伺服器接受到用戶端的請求,給用戶端發送相應資訊:sourceid,和position位置資訊OutputStream outputStream = socket.getOutputStream();String respons = "sourceid=" + id + "position" + position+ "\r\n";outputStream.write(respons.getBytes());RandomAccessFile accessFile = new RandomAccessFile(file,"rwd");if(position==0) accessFile.setLength(Integer.valueOf(fileLength));//設定檔案長度accessFile.seek(position);//移動到指定位置寫入資料byte [] buf=new byte[1024];int len=1;int length=position;while((len=inputStream.read(buf))!=-1){accessFile.write(buf,0,len);length+=len;Properties properties=new Properties();properties.put("length", String.valueOf(length));FileOutputStream fileOutputStream=new FileOutputStream(new File(file.getParent(),file.getName()+".log"));properties.store(fileOutputStream, null);//即時記錄檔案的最後儲存位置fileOutputStream.close();}if(length==accessFile.length()) delete(id);accessFile.close();inputStream.close();outputStream.close();}} catch (Exception e) {}finally{if(socket!=null&&!socket.isClosed())try {socket.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}public static void main(String[] args) {String s = "12345";System.out.println(s.indexOf("5"));System.out.println(s.substring(2, s.indexOf("5")));}/** * 尋找檔案 *  * @param sourceId *            檔案Id * @return */public FileLog find(long sourceId) {return datas.get(sourceId);}/** * 儲存檔案斷點 *  * @param id *            檔案id * @param file *            檔案 */public void save(long id, File file) {datas.put(id, new FileLog(id, file.getAbsolutePath()));}/** * 檔案上床完畢刪除檔案記錄的斷點 *  * @param sourceId *            檔案Id */public void delete(long sourceId) {if (datas.containsKey(sourceId)) {datas.remove(sourceId);}}private class FileLog {private long id;private String path;public FileLog(long id, String path) {this.id = id;this.path = path;}public long getId() {return id;}public void setId(long id) {this.id = id;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}}}

我們使用了一個Map對象來隱藏檔的斷點位置,方便下一次繼續上傳。ExecutorService線程池用來管理我們的SocketTask的線程。FileLog是我們每個檔案上傳實儲存的類!

到此我們就完成了一個簡單的斷點上傳的服務。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.