说在前面:给我的需求是实现从服务器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) {
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增加注释
/*该目录用于服务端文件的存储。
*/
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();
}
}
/**
* <p>
* 读取通道中的数据到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字段进行了修改,所以添加
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;
}
}
/*至此全部完成,注释不够多,部分代码是从网上找的。后期有时间会补全注释的,或者下次直接上最终使用的代码*/
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。