您好,登錄后才能下訂單哦!
說在前面:給我的需求是實現(xiàn)從服務(wù)器A將大量文件(大概幾十TB)發(fā)送到服務(wù)器B,在A服務(wù)器生成文件的MD5碼,并在服務(wù)器B進(jìn)行md5驗證,驗證通過保存。
我的實現(xiàn)思路:
將待上傳的所有文件目錄生成一個txt文件,格式如下。前綴中,當(dāng)后面的數(shù)字等于9999的時候,前面的數(shù)字會自行相加。(此處加前綴的目的是為了整齊,而且失敗了便于查詢。)
AAA0000:D:\upload\addChannel.html
AAA0001:D:\upload\addChannel2.html
AAA0002:D:\upload\addContactPerson.html
AAA0003:D:\upload\admin.html
AAA0004:D:\upload\businessOfChannel.html
....
AAA9999:D:\upload\admin1.html
AAB0000:D:\upload\businessOfChannel1.html
...
每次讀取一條目錄,進(jìn)行上傳。
本地測試版未去實現(xiàn)的部分,沒有把成功和失敗的目錄寫到文件中,也沒有添加日志。
2017/07/07增加部分
添加部分注釋
添加對于大文件上傳的解決方案
2017/07/12增加部分
經(jīng)過對代碼的研究以及測試表明,2017/07/07修改的大文件上傳有問題,問題出在bytebuffer的緩存有限制,byte.allocate(int)中的參數(shù)類型為int,即最大緩存為Integer.MAX_VALUE,即2^31-1的字節(jié),大概是2G的大小。
如果確定文件不會大于2G的話,用2017/07/07的部分應(yīng)該足夠,但是如果可以的話,依然推薦2017/07/12新增的部分代碼
新增的部分,不再原基礎(chǔ)上進(jìn)行修改,而是新增代碼,只需要在客戶端和服務(wù)器調(diào)用方法的時候,將handler.sendData(socketChannel, path, pathPre)改成handler.sendData2(socketChannel, path, pathPre),將this.handler.excute((ServerSocketChannel) s.channel())改成this.handler.excute2((ServerSocketChannel) s.channel())即可,當(dāng)然在handler類中需要新增
相應(yīng)的方法(excute2(),receiveData2(),sendData2())
另外添加RequestObject類,用于替代execute方法中的RequestObject2類,在execute方法中使用。
在服務(wù)器端,原來是將接受到的文件先存到字節(jié)數(shù)組,然后對字節(jié)數(shù)組進(jìn)行md5驗證,但是字節(jié)數(shù)組的大小依然受到Integer.MAX_VALUE的限制。所以現(xiàn)在改成,直接將接收到的字節(jié)數(shù)組寫入到文件,然后直接對文件進(jìn)行MD5驗證。這樣excute2的方法會比之前邏輯有些變化。
代碼依然不夠整潔,需要后續(xù)繼續(xù)修改。
第一部分:將文件目錄存儲到文本中,文件夾不進(jìn)行存儲。
import java.io.File; import java.io.FileOutputStream; public class ReadAllPaths { private static final String rootPath="D:/upload/"; //the root path of the files which will be copied private static final String filePath="G:/temp/unUploadedFilePath.txt";//the record of all files path /* * the items of prefix and num construct the path prefix,for example AAA0001 * and it's mainly convenient for searching */ private String prefix="AAA"; private int num=0; /** * main * @param args * @throws Exception */ public static void main(String[] args) throws Exception { ReadAllPaths paths=new ReadAllPaths(); File file=new File(filePath); if(file.exists()){ file.delete(); } FileOutputStream out=new FileOutputStream(file,true); paths.getAllPaths(rootPath, out); out.close(); } /** * get all path out * @param root * @param out * @throws Exception */ private void getAllPaths(String root,FileOutputStream out) throws Exception{ File file=new File(root); if(file.isDirectory()){ try{if(file.list().length==0){ return; }else{ String[] files=file.list(); for(String f:files){ getAllPaths(root+f+File.separator, out); } } }catch(NullPointerException npe){ return; } }else{ String pathNum=getPathNum(); String path=file.getAbsolutePath(); out.write((pathNum+":"+path+"\n").getBytes()); } } /** * get the path prefix * @return */ private String getPathNum(){ StringBuilder sb=new StringBuilder(); sb.append(getPrefix()).append(getNum()); setNum(); return sb.toString(); } /** * get the String prefix of path prefix * @return */ private String getPrefix() { return prefix; } /** * set the String prefix of path prefix * for example:AAA AAB AAC....AAZ ABA....AZZ BAA... */ private void setPrefix() { char[] ch=new char[3]; ch=getPrefix().toCharArray(); if(ch[2]!='Z'){ ch[2]++; }else{ ch[2]='A'; if(ch[1]!='Z'){ ch[1]++; }else{ ch[1]='A'; ch[0]++; } } prefix=new String(ch); } /** * get the int prefix of path prefix * @return */ private String getNum() { StringBuffer sb=new StringBuffer(); if(num<10){ sb.append("000").append(num); }else if(num<100){ sb.append("00").append(num); }else if(num<1000){ sb.append("0").append(num); }else{ sb.append(num); } return sb.toString(); } /** * set the int prefix of path prefix * and the max num is 9999 and the min is 0000 */ private void setNum() { if(num<9999){ num++; }else{ num=0; setPrefix(); } } }
第二部分,服務(wù)器端代碼
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.util.Iterator; public class Server { Selector selector = null; ServerSocketChannel serverSocketChannel = null; private NioserverHandler2 handler; public Server() throws IOException { selector = Selector.open(); // 打開服務(wù)器套接字通道 serverSocketChannel = ServerSocketChannel.open(); // 調(diào)整通道的阻塞模式非阻塞 serverSocketChannel.configureBlocking(false); //serverSocketChannel.socket().setReuseAddress(true);這里沒明白有什么用,//所以注釋了 serverSocketChannel.socket().bind(new InetSocketAddress(9999)); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); } public Server(NioserverHandler2 handler) throws IOException { this(); this.handler = handler; while (selector.select() > 0) { Iterator<SelectionKey> it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey s = it.next(); it.remove(); this.handler.excute((ServerSocketChannel) s.channel()); } } } public static void main(String[] args) throws IOException { new Server(new NioserverHandler2()); } } public class NioserverHandler2 { //2017/07/07增加注釋 /*該目錄用于服務(wù)端文件的存儲。 */ private final static String DIRECTORY = "G:\\NioRequest\\"; /* *2017/07/07增加 *用于存儲上傳文件成功失敗情況的目錄, *成功的放在succeed.log中 *格式為客戶端傳過來的帶前綴的路徑,無特殊格式,每個一行 *失敗的放在failed.log中 *格式為reason+帶前綴路徑 */ private final static String ResultPath = "G:\\serverLog\\"; /* *2017/07/07修改 *新增構(gòu)造方法,檢測succeed.log,failed.log以及其目錄是否存在,不存在則創(chuàng)建 */ public NioserverHandler2() { File file = new File(ResultPath); File file1 = new File(ResultPath + "succeed.log"); File file2 = new File(ResultPath + "failed.log"); if (!file.exists()) { file.mkdirs(); } if (!file1.exists()) { try { file1.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } if (!file2.exists()) { try { file2.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } } /** * 這里邊我們處理接收和發(fā)送 * * @param serverSocketChannel */ public void excute(ServerSocketChannel serverSocketChannel) { SocketChannel socketChannel = null; /* *2017/07/07增加該字段 *自己測試中發(fā)現(xiàn),有些文件可以讀寫執(zhí)行,但是卻無法正確發(fā)送 *所以在client發(fā)送的fileInfo中新增了一個字段,如果把文件讀取到字節(jié)數(shù)組失敗 *則設(shè)置字節(jié)數(shù)組為空 *此時字節(jié)數(shù)組為空有兩種情況: *文件為0KB大小,還有上面的一種情況, *前者需要直接新建一個空文件,后者需要報錯 *所以client端新增一個字段,用于區(qū)分這兩種情況。 *第一種情況是fileInfo中設(shè)置一個well字符串 *第二種情況是fileInfo中設(shè)置一個error字符串 * *此處新增的status由于區(qū)分不同情況 *status==0 文件傳送正確,并且MD5驗證通過 *status==1 文件傳送正確,但是MD5驗證未通過 *status==2 文件傳輸失敗 *以后如果有新的錯誤,會在這里繼續(xù)追加狀態(tài) */ int status=0; try { socketChannel = serverSocketChannel.accept(); // 等待客戶端連接 RequestObject2 requestObject = receiveData(socketChannel);// 接數(shù)據(jù) //md5驗證,用的是apache的,2017/07/07添加注釋 String md5 = DigestUtils.md5Hex(requestObject.getContents()); //用于對客戶端的相應(yīng),其實在本程序中用處不太大 String response = ""; //2017/07/07添加該字段,用于判斷成功失敗 boolean flag=true; /* *2017/07/07對于判斷進(jìn)行修改,新增了判斷status字段是否為error *至于下面的responseObject不用關(guān)于,只是為了方便固定格式的字符串而已 */ if(requestObject.getStatus().equals("error")){ flag=false; status=2; response = (new ResponseObject("failed", requestObject.getAbsolutePath(), "fail error")).toString(); }else{ if (md5.equals(requestObject.getMd5())) { response = (new ResponseObject("succeed", requestObject.getAbsolutePath(), "")).toString(); File file = new File(DIRECTORY + requestObject.getRelativePath()); if (!file.exists()) { file.mkdirs(); } File file1 = new File(DIRECTORY + requestObject.getRelativePath() + requestObject.getFilename()); if (!file1.exists()) { file1.createNewFile(); } FileOutputStream fos = new FileOutputStream(file1); fos.write(requestObject.getContents()); fos.close(); } else { flag=false; status=1; response = (new ResponseObject("failed", requestObject.getAbsolutePath(), "md5驗證失敗")).toString(); } } //將處理結(jié)果寫入到succeed.log和failed.log中 writeRusultToFile(flag, requestObject.getAbsolutePath(),status); //響應(yīng)客戶端 responseData(socketChannel, response); } catch (IOException e) { e.printStackTrace(); } } /* *2017/07/12新增代碼 *md5驗證方式從驗證字節(jié)數(shù)組改成驗證文件流。 *將之前寫入文件的部分代碼刪除,因為在receiveData2已經(jīng)將文件進(jìn)行了寫入。 * */ public void excute2(ServerSocketChannel serverSocketChannel) { SocketChannel socketChannel = null; int status=0; try { socketChannel = serverSocketChannel.accept(); // 等待客戶端連接 RequestObject requestObject = receiveData2(socketChannel);// 接數(shù)據(jù) String md5 = DigestUtils.md5Hex(new FileInputStream(new File(DIRECTORY+requestObject.getRelativePath()+requestObject.getFilename()))); System.out.println(md5); String response = ""; boolean flag = true; if(requestObject.getStatus().equals("error")){ flag=false; status=2; response = (new ResponseObject("failed", requestObject.getAbsolutePath(), "fail error")).toString(); }else{ if (md5.equals(requestObject.getMd5())) { response = (new ResponseObject("succeed", requestObject.getAbsolutePath(), "")).toString(); } else { flag=false; status=1; response = (new ResponseObject("failed", requestObject.getAbsolutePath(), "md5驗證失敗")).toString(); } } writeRusultToFile(flag, requestObject.getAbsolutePath(),status); System.out.println(response); responseData(socketChannel, response); } catch (IOException e) { e.printStackTrace(); } } /** * <p> * 讀取通道中的數(shù)據(jù)到Object里去 * </p> * * @param socketChannel * @return * @throws IOException */ public RequestObject2 receiveData(SocketChannel socketChannel) throws IOException { // 文件名 String fileName = null; String relativePath = null; String absolutePath = null; String md5 = null; //2017/07/07新增字段,因為RequestObject2字段進(jìn)行了修改,所以添加 String status=null; // 文件長度 int contentLength = 0; // 文件內(nèi)容 byte[] contents = null; // 由于我們解析時前4個字節(jié)是文件名長度 int capacity = 4; ByteBuffer buf = ByteBuffer.allocate(capacity); int size = 0; byte[] bytes = null; // 拿到文件名的長度 size = socketChannel.read(buf); if (size >= 0) { buf.flip(); capacity = buf.getInt(); buf.clear(); } buf = ByteBuffer.allocate(capacity); size = socketChannel.read(buf); if (size >= 0) { buf.flip(); bytes = new byte[size]; buf.get(bytes); buf.clear(); } String fileInfo = new String(bytes); System.out.println(fileInfo); /*2017/07/07增加注釋,并添加字段 *并進(jìn)行部分修改 */ status=fileInfo.split(";")[0]; fileName = fileInfo.split(";")[1]; relativePath = fileInfo.split(";")[2]; absolutePath = fileInfo.split(";")[3]; md5 = fileInfo.split(";")[4]; // 拿到文件長度 capacity = 4; buf = ByteBuffer.allocate(capacity); size = socketChannel.read(buf); if (size >= 0) { buf.flip(); // 文件長度是可要可不要的,如果你要做校驗可以留下 capacity = buf.getInt(); buf.clear(); } if (capacity == 0) { contents = new byte[] {}; } else { // 用于接收buffer中的字節(jié)數(shù)組 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 文件可能會很大 // capacity = 1024; buf = ByteBuffer.allocate(capacity); while ((size = socketChannel.read(buf)) >= 0) { buf.flip(); bytes = new byte[size]; buf.get(bytes); baos.write(bytes); buf.clear(); } contents = baos.toByteArray(); } RequestObject2 requestObject = new RequestObject2(fileName, relativePath, absolutePath, md5, contents,status); return requestObject; } private void responseData(SocketChannel socketChannel, String response) { ByteBuffer buffer = ByteBuffer.wrap(response.getBytes()); try { socketChannel.write(buffer); buffer.clear(); // 確認(rèn)要發(fā)送的東西發(fā)送完了關(guān)閉output 不然它端接收時socketChannel.read(Buffer) // 很可能造成阻塞 ,可以把這個(L)注釋掉,會發(fā)現(xiàn)客戶端一直等待接收數(shù)據(jù) socketChannel.socket().shutdownOutput();// (L) } catch (IOException e) { e.printStackTrace(); } } /* *2017/07/12新增方法,用于excute2()方法 *大部分代碼和2017/07/07的代碼相似,因為客戶端發(fā)送的文件大小可能超出int類型,所以改成long類型,所以服務(wù)端也自然進(jìn)行了修改 *因為可能文件過大,所以直接將接收到的字節(jié)數(shù)組寫入到文件中。 *這里的注釋可能比較少 */ public RequestObject receiveData2(SocketChannel socketChannel) throws IOException { String status=null; String fileName = null; String relativePath = null; String absolutePath = null; String md5 = null; int contentLength = 0; // 由于我們解析時前4個字節(jié)是文件名長度 int capacity = 4; ByteBuffer buf = ByteBuffer.allocate(capacity); int size = 0; byte[] bytes = null; // 拿到文件名的長度 size = socketChannel.read(buf); if (size >= 0) { buf.flip(); capacity = buf.getInt(); buf.clear(); } buf = ByteBuffer.allocate(capacity); size = socketChannel.read(buf); if (size >= 0) { buf.flip(); bytes = new byte[size]; buf.get(bytes); buf.clear(); } status = fileInfo.split(";")[0]; fileName = fileInfo.split(";")[1]; relativePath = fileInfo.split(";")[2]; absolutePath = fileInfo.split(";")[3]; md5 = fileInfo.split(";")[4]; // 拿到文件長度,因為long類型占8個字節(jié),所以這里為8 capacity = 8; buf = ByteBuffer.allocate(capacity); size = socketChannel.read(buf); long cap=0; if (size >= 0) { buf.flip(); // 文件長度顯得不那么重要了 cap = buf.getLong(); buf.clear(); } System.out.println(cap); if (status.equals("well")) { File file = new File(DIRECTORY + relativePath); if (!file.exists()) { file.mkdirs(); } File file1 = new File(DIRECTORY + relativePath + fileName); if (!file1.exists()) { file1.createNewFile(); } FileOutputStream fos=new FileOutputStream(file1); //每次接受1KB的字節(jié)數(shù)組,可以根據(jù)需要自己修改。注意有Integet.MAXVALUE的限制。 buf = ByteBuffer.allocate(1024); while ((size = socketChannel.read(buf)) >= 0) { buf.flip(); bytes = new byte[size]; buf.get(bytes); fos.write(bytes); buf.clear(); } fos.close(); } RequestObject requestObject = new RequestObject(fileName, relativePath, absolutePath, md5,status); return requestObject; } } import java.io.Serializable; public class RequestObject2 implements Serializable { private static final long serialVersionUID = 1L; private String filename; private String relativePath; private String absolutePath; private String md5; private byte[] contents; private String status; public RequestObject2(String filename, String relativePath, String absolutePath, String md5, byte[] contents,String status) { this.filename = filename; this.relativePath = relativePath; this.absolutePath = absolutePath; this.md5 = md5; this.contents = contents; this.status=status; } public String getFilename() { return filename; } public String getRelativePath() { return relativePath; } public String getAbsolutePath() { return absolutePath; } public String getMd5() { return md5; } public byte[] getContents() { return contents; } public String getStatus(){ return status; } } /* *2017/07/12新增類,用于excute2方法 *想對于RequestObject,刪除了byte[] */ import java.io.Serializable; public class RequestObject implements Serializable { private static final long serialVersionUID = 1L; private String filename; private String relativePath; private String absolutePath; private String md5; private String status; public RequestObject(String filename, String relativePath, String absolutePath, String md5, String status) { this.filename = filename; this.relativePath = relativePath; this.absolutePath = absolutePath; this.md5 = md5; this.status = status; } public String getFilename() { return filename; } public String getRelativePath() { return relativePath; } public String getAbsolutePath() { return absolutePath; } public String getMd5() { return md5; } public String getStatus() { return status; } }
第三部分 客戶端代碼
import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; public class Client2 { /* *2017/07/07添加該注釋 *用于存儲要被上傳文件的目錄,即文章第一部分代碼生成文件的位置 */ private static final String unpath = "G:\\temp\\unUploadedFilePath.txt"; /* *2017/07/07添加該注釋 *待上傳文件所在的目錄 *還有一個作用,用于獲得相對路徑 */ private static final String pathPre = "D:\\upload\\"; //2017/07/07添加該注釋 //服務(wù)器地址,因為是本地測試,所以用這個 private static final String IPADDR = "127.0.0.1"; //2017/07/07添加該注釋 //服務(wù)端口號 private static final int PORT = 9999; Selector selector; public Client2() throws IOException { selector = Selector.open(); new Thread(new SendDataRunnable()).start(); } private class SendDataRunnable implements Runnable { private ClientHandler handler; public SendDataRunnable() { handler = new ClientHandler(); } @Override public void run() { try { BufferedReader reader = new BufferedReader(new FileReader(new File(unpath))); String path = ""; while ((path = reader.readLine()) != null && path.length() != 0) { SocketChannel socketChannel; socketChannel = SocketChannel.open(); socketChannel.connect(new InetSocketAddress(IPADDR, PORT)); socketChannel.configureBlocking(false); socketChannel.register(selector, SelectionKey.OP_READ); handler.sendData(socketChannel, path, pathPre); String response = handler.receiveData(socketChannel); System.out.println(response); socketChannel.close(); } } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) throws IOException { Client2 client = new Client2(); } } import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import org.apache.commons.codec.digest.DigestUtils; public class ClientHandler { public void sendData(SocketChannel socketChannel,String path,String pathPre)throws Exception{ System.out.println(path); String absoluteFilePath=getAbsoluteFilePath(path); String fileName=getFileName(absoluteFilePath); String relativeFilePath=getRelativeFilePath(absoluteFilePath, pathPre,fileName); System.out.println(absoluteFilePath); /* *2017/07/07添加該字段 *用于區(qū)分文件是否正確讀取 */ String status="well"; byte[] bytes=makeFileToBytes(absoluteFilePath); System.out.println(bytes.length); String md5=DigestUtils.md5Hex(bytes); /* *2017/07/07添加該注釋 *進(jìn)行部分修改,增加status部分 */ String fileInfo=new StringBuffer() .append(status) .append(";") .append(fileName) .append(";") .append(relativeFilePath) .append(";") .append(path) .append(";") .append(md5) .toString(); System.out.println(fileInfo); ByteBuffer buffer = ByteBuffer.allocate(8 +fileInfo.getBytes().length+bytes.length); buffer.putInt(fileInfo.getBytes().length); buffer.put(fileInfo.getBytes()); buffer.putInt(bytes.length); buffer.put(ByteBuffer.wrap(bytes)); buffer.flip(); /* *2017/07/07進(jìn)行修改 *之前沒有外面的while循環(huán),發(fā)現(xiàn)大文件server端一直接收失敗 *所以進(jìn)行的添加。 */ while (buffer.hasRemaining()) { socketChannel.write(buffer); } buffer.clear(); // 關(guān)閉輸出流防止接受時阻塞,就是告訴接收方本次的內(nèi)容已經(jīng)發(fā)完了,你不用等了 socketChannel.socket().shutdownOutput(); } /* *2017/07/12新增代碼 */ public void sendData2(SocketChannel socketChannel, String path, String pathPre) { System.out.println(path); String absoluteFilePath = getAbsoluteFilePath(path); File file = new File(absoluteFilePath); String fileName = getFileName(absoluteFilePath); String relativeFilePath = getRelativeFilePath(absoluteFilePath, pathPre, fileName); System.out.println(absoluteFilePath); String status = "well"; String md5 = null; int bufferSize = 1024;//用于每次發(fā)送文件的大小設(shè)置,可以自行修改 try { RandomAccessFile rafi = new RandomAccessFile(absoluteFilePath, "r"); byte[] buf = new byte[bufferSize]; int c = 0; try { c = rafi.read(buf); FileInputStream fis = new FileInputStream(new File(absoluteFilePath)); md5 = DigestUtils.md5Hex(fis); fis.close(); } catch (Exception e) { c = 0; status = "error"; md5 = "0"; } String fileInfo = new StringBuffer().append(status).append(";").append(fileName).append(";") .append(relativeFilePath).append(";").append(path).append(";").append(md5).toString(); System.out.println(fileInfo); int len = c; //這里注意下12,因為之前是發(fā)送兩個int類型,所以是8,現(xiàn)在是一個int一個long,所以12 ByteBuffer buffer = ByteBuffer.allocate((int) (12 + fileInfo.getBytes().length + bufferSize)); buffer.putInt(fileInfo.getBytes().length); buffer.put(fileInfo.getBytes()); buffer.putLong(len > 0 ? file.length() : 0); /* *說下flag的作用 *flag==true 表示這次發(fā)送的是一個buffersize的大小,可能后續(xù)還有字節(jié)數(shù)組沒發(fā)送完成,需要繼續(xù)判斷;另外當(dāng)c==0的時候,true的作用是用于后面發(fā)送文件的基本信息。 *flag==false表示這次發(fā)送的不是一個buffersize的大小,也表示已經(jīng)發(fā)送完成,無需后續(xù)判斷 */ boolean flag = true; while(c>0){ if (c == buf.length) { buffer.put(ByteBuffer.wrap(buf)); flag = true; } else { buffer.put(ByteBuffer.wrap(buf, 0, c)); c = 0; flag = false; } buffer.flip(); while (buffer.hasRemaining()) { socketChannel.write(buffer); } if(flag) { buffer.clear(); c = rafi.read(buf); } } if(flag){ buffer.flip(); while (buffer.hasRemaining()) { socketChannel.write(buffer); } } rafi.close(); buffer.clear(); // 關(guān)閉輸出流防止接受時阻塞,就是告訴接收方本次的內(nèi)容已經(jīng)發(fā)完了,你不用等了 socketChannel.socket().shutdownOutput(); } catch (Exception e) { e.printStackTrace(); } } /* *2017/07/07添加注釋 *用于從類似AAA0000:D:\upload\addChannel.html格式的目錄中讀取真正的文件目錄 */ private String getAbsoluteFilePath(String path){ return path.substring(8); } /* *2017/07/07添加注釋 *用于從類似D:\upload\addChannel.html格式的目錄中拿到被存儲的相對路徑(說的啥啊,自己都看不懂) *舉個例子: *客戶端文件目錄D:\upload\test1\test2\addChannel.html,即為下面的absoluteFilePath *我想存儲到服務(wù)器的 G:\NioRequest\test1\test2\addChannel.html *所以我要獲得客戶端目錄的test1\test2\addChannel.html部分 *然后拼接到服務(wù)器的目錄G:\NioRequest\目錄上 *下面的pathPre是為前綴,上面例子中就是D:\upload\ *因為我要的目錄中不包括文件名,所以加了個文件名字段 */ private String getRelativeFilePath(String absoluteFilePath,String pathPre,String fileName){ return absoluteFilePath.substring(pathPre.length(),absoluteFilePath.length()-fileName.length()); } /* *2017/07/07添加注釋 *這個太簡單,不解釋 */ private String getFileName(String path){ return new File(path).getName(); } /* *2017/07/07添加注釋 *將文件讀取到字節(jié)數(shù)組,不是我自己寫的,網(wǎng)上找到的 */ private byte[] makeFileToBytes(String filePath){ File file=new File(filePath); byte[] ret = null; try { FileInputStream in = new FileInputStream(file); ByteArrayOutputStream out = new ByteArrayOutputStream(4096); byte[] b = new byte[4096]; int n; while ((n = in.read(b)) != -1) { out.write(b, 0, n); } in.close(); out.close(); ret = out.toByteArray(); } catch (IOException e) { // log.error("helper:get bytes from file process error!"); e.printStackTrace(); } return ret; } public String receiveData(SocketChannel socketChannel) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); String response = ""; try { ByteBuffer buffer = ByteBuffer.allocate(1024); byte[] bytes; int count = 0; while ((count = socketChannel.read(buffer)) >= 0) { buffer.flip(); bytes = new byte[count]; buffer.get(bytes); baos.write(bytes); buffer.clear(); } bytes = baos.toByteArray(); response = new String(bytes, "UTF-8"); // socketChannel.socket().shutdownInput(); } finally { try { baos.close(); } catch (Exception ex) { } } return response; } }
/*至此全部完成,注釋不夠多,部分代碼是從網(wǎng)上找的。后期有時間會補全注釋的,或者下次直接上最終使用的代碼*/
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。