说在前面:给我的需求是实现从服务器A将大量文件(大概几十TB)发送到服务器B,在A服务器生成文件的MD5码,并在服务器B进行md5验证,验证通过保存。
成都创新互联服务项目包括梅列网站建设、梅列网站制作、梅列网页制作以及梅列网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,梅列网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到梅列省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!
我的实现思路:
将待上传的所有文件目录生成一个txt文件,格式如下。前缀中,当后面的数字等于9999的时候,前面的数字会自行相加。(此处加前缀的目的是为了整齐,而且失败了便于查询。)
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
...
每次读取一条目录,进行上传。
本地测试版未去实现的部分,没有把成功和失败的目录写到文件中,也没有添加日志。
2017/07/07增加部分
添加部分注释
添加对于大文件上传的解决方案
2017/07/12增加部分
经过对代码的研究以及测试表明,2017/07/07修改的大文件上传有问题,问题出在bytebuffer的缓存有限制,byte.allocate(int)中的参数类型为int,即最大缓存为Integer.MAX_VALUE,即2^31-1的字节,大概是2G的大小。
如果确定文件不会大于2G的话,用2017/07/07的部分应该足够,但是如果可以的话,依然推荐2017/07/12新增的部分代码
新增的部分,不再原基础上进行修改,而是新增代码,只需要在客户端和服务器调用方法的时候,将handler.sendData(socketChannel, path, pathPre)改成handler.sendData2(socketChannel, path, pathPre),将this.handler.excute((ServerSocketChannel) s.channel())改成this.handler.excute2((ServerSocketChannel) s.channel())即可,当然在handler类中需要新增
相应的方法(excute2(),receiveData2(),sendData2())
另外添加RequestObject类,用于替代execute方法中的RequestObject2类,在execute方法中使用。
在服务器端,原来是将接受到的文件先存到字节数组,然后对字节数组进行md5验证,但是字节数组的大小依然受到Integer.MAX_VALUE的限制。所以现在改成,直接将接收到的字节数组写入到文件,然后直接对文件进行MD5验证。这样excute2的方法会比之前逻辑有些变化。
代码依然不够整洁,需要后续继续修改。
第一部分:将文件目录存储到文本中,文件夹不进行存储。
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(); } } }
第二部分,服务器端代码
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(); // 打开服务器套接字通道 serverSocketChannel = ServerSocketChannel.open(); // 调整通道的阻塞模式非阻塞 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) { Iteratorit = 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增加注释 /*该目录用于服务端文件的存储。 */ 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修改 *新增构造方法,检测succeed.log,failed.log以及其目录是否存在,不存在则创建 */ 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(); } } } /** * 这里边我们处理接收和发送 * * @param serverSocketChannel */ public void excute(ServerSocketChannel serverSocketChannel) { SocketChannel socketChannel = null; /* *2017/07/07增加该字段 *自己测试中发现,有些文件可以读写执行,但是却无法正确发送 *所以在client发送的fileInfo中新增了一个字段,如果把文件读取到字节数组失败 *则设置字节数组为空 *此时字节数组为空有两种情况: *文件为0KB大小,还有上面的一种情况, *前者需要直接新建一个空文件,后者需要报错 *所以client端新增一个字段,用于区分这两种情况。 *第一种情况是fileInfo中设置一个well字符串 *第二种情况是fileInfo中设置一个error字符串 * *此处新增的status由于区分不同情况 *status==0 文件传送正确,并且MD5验证通过 *status==1 文件传送正确,但是MD5验证未通过 *status==2 文件传输失败 *以后如果有新的错误,会在这里继续追加状态 */ int status=0; try { socketChannel = serverSocketChannel.accept(); // 等待客户端连接 RequestObject2 requestObject = receiveData(socketChannel);// 接数据 //md5验证,用的是apache的,2017/07/07添加注释 String md5 = DigestUtils.md5Hex(requestObject.getContents()); //用于对客户端的相应,其实在本程序中用处不太大 String response = ""; //2017/07/07添加该字段,用于判断成功失败 boolean flag=true; /* *2017/07/07对于判断进行修改,新增了判断status字段是否为error *至于下面的responseObject不用关于,只是为了方便固定格式的字符串而已 */ 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(); } } //将处理结果写入到succeed.log和failed.log中 writeRusultToFile(flag, requestObject.getAbsolutePath(),status); //响应客户端 responseData(socketChannel, response); } catch (IOException e) { e.printStackTrace(); } } /* *2017/07/12新增代码 *md5验证方式从验证字节数组改成验证文件流。 *将之前写入文件的部分代码删除,因为在receiveData2已经将文件进行了写入。 * */ public void excute2(ServerSocketChannel serverSocketChannel) { SocketChannel socketChannel = null; int status=0; try { socketChannel = serverSocketChannel.accept(); // 等待客户端连接 RequestObject requestObject = receiveData2(socketChannel);// 接数据 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(); } } /** * * 读取通道中的数据到Object里去 *
* * @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字段进行了修改,所以添加 String status=null; // 文件长度 int contentLength = 0; // 文件内容 byte[] contents = null; // 由于我们解析时前4个字节是文件名长度 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增加注释,并添加字段 *并进行部分修改 */ 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中的字节数组 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(); // 确认要发送的东西发送完了关闭output 不然它端接收时socketChannel.read(Buffer) // 很可能造成阻塞 ,可以把这个(L)注释掉,会发现客户端一直等待接收数据 socketChannel.socket().shutdownOutput();// (L) } catch (IOException e) { e.printStackTrace(); } } /* *2017/07/12新增方法,用于excute2()方法 *大部分代码和2017/07/07的代码相似,因为客户端发送的文件大小可能超出int类型,所以改成long类型,所以服务端也自然进行了修改 *因为可能文件过大,所以直接将接收到的字节数组写入到文件中。 *这里的注释可能比较少 */ 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个字节是文件名长度 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个字节,所以这里为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的字节数组,可以根据需要自己修改。注意有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添加该注释 //服务器地址,因为是本地测试,所以用这个 private static final String IPADDR = "127.0.0.1"; //2017/07/07添加该注释 //服务端口号 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添加该字段 *用于区分文件是否正确读取 */ String status="well"; byte[] bytes=makeFileToBytes(absoluteFilePath); System.out.println(bytes.length); String md5=DigestUtils.md5Hex(bytes); /* *2017/07/07添加该注释 *进行部分修改,增加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进行修改 *之前没有外面的while循环,发现大文件server端一直接收失败 *所以进行的添加。 */ while (buffer.hasRemaining()) { socketChannel.write(buffer); } buffer.clear(); // 关闭输出流防止接受时阻塞,就是告诉接收方本次的内容已经发完了,你不用等了 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;//用于每次发送文件的大小设置,可以自行修改 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,因为之前是发送两个int类型,所以是8,现在是一个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 表示这次发送的是一个buffersize的大小,可能后续还有字节数组没发送完成,需要继续判断;另外当c==0的时候,true的作用是用于后面发送文件的基本信息。 *flag==false表示这次发送的不是一个buffersize的大小,也表示已经发送完成,无需后续判断 */ 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(); // 关闭输出流防止接受时阻塞,就是告诉接收方本次的内容已经发完了,你不用等了 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 *我想存储到服务器的 G:\NioRequest\test1\test2\addChannel.html *所以我要获得客户端目录的test1\test2\addChannel.html部分 *然后拼接到服务器的目录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添加注释 *将文件读取到字节数组,不是我自己写的,网上找到的 */ 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; } }
/*至此全部完成,注释不够多,部分代码是从网上找的。后期有时间会补全注释的,或者下次直接上最终使用的代码*/
网页名称:JAVANIO服务器间连续发送文件(本地测试版)
浏览地址:http://scgulin.cn/article/ipepjd.html