Java文件传输
前段时间的项目中需要实现网络硬盘的功能, 所以整理了Java的Socket文件传输, 方便以后重用!
大家都知道Java语言功能强大, 对网络传输的支持更强, Socket和多线程是程序员必备知识.
为了方便项目布署, 服务器没有使用FTP服务器, 全是由纯Java所写.
除了文件传输外, 自定义了传输协议, 即在同一个流中, 增加了文件的一些属性.
服务器端核心代码:
客户端核心代码:
这里要注意的是, 既然是自定义的传输协议, 在文件流之前传输的字节必须是事先定义好的, 例如: 客户端向服务器发送了5个文件额外属性, 标识此文件信息, 则服务器读取时要先将这5个属性读出来, 而且客户端写入时每个属性的字节长度必须和服务器读取时使用的字节长度相同, 否则便失败了! 另外, 每个属性之间的字节间隔我使用了16进制的 0x00000000 来标识, 以便服务器端读取时分隔.
前段时间的项目中需要实现网络硬盘的功能, 所以整理了Java的Socket文件传输, 方便以后重用!
大家都知道Java语言功能强大, 对网络传输的支持更强, Socket和多线程是程序员必备知识.
为了方便项目布署, 服务器没有使用FTP服务器, 全是由纯Java所写.
除了文件传输外, 自定义了传输协议, 即在同一个流中, 增加了文件的一些属性.
服务器端核心代码:
Thread fileThread = new Thread(){
public void run(){
try {
ServerSocket ss = new ServerSocket(port, maxConnected);
System.out.println("文件传输服务启动成功!");
while(true){
Socket socket = ss.accept();
Thread trFile = new TrFile(socket);
//trFile.setDaemon(true);
trFile.start();
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
class TrFile extends Thread{
private Socket socket;
private String UPLOAD_TYPE = "/example"; // value = /gamesave or /webdisk
private String USER_DIR = "/example"; // value = /username
private String childFilename = null;
private String childFileaddr = null;
private String childGame = null;
private String childFiletype = null;
private String childUserid = null;
private String childFilesize = null;
public TrFile(Socket socket){
this.socket = socket;
}
public void run(){
try{
InputStream in =
socket.getInputStream();
PrintWriter out =
new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream())),true);
while(true)
{
//第一个参数为命令
String cmds = getFileInfo(in, 128);
/*
if("exit".equals(cmds)){
System.exit(0);
} else */
if("cp".equals(cmds)){
//获得用户名
childUserid = getFileInfo(in, 30);
//获得网吧硬盘目录
childFiletype = getFileInfo(in, 128);
//获得游戏
childGame = getFileInfo(in, 128);
//获得文件名
childFilename = getFileInfo(in, 256);
//获得文件大小
childFilesize = getFileInfo(in, 128);
//获得其它属性...
//做一些目录的处理
USER_DIR = "/" + childUserid;
if (childGame.equals("")){
//网络硬盘
USER_DIR += "/"+childFiletype;
UPLOAD_TYPE = "/webdisk";
}else{
//游戏存档
USER_DIR = USER_DIR + "/" + childGame;
UPLOAD_TYPE = "/gamesave";
}
//在服务器创建目录
File folder = new File(APP_CONTEXT+UPLOAD_ROOT+UPLOAD_TYPE+USER_DIR);
if (!folder.exists()){
folder.mkdirs();
}
File fileout = new File(folder, childFilename);
//如果文件已存在, 则在文件名尾追加(i)命名.
int fileEndIndex = 0;
while(fileout.exists()){
String[] newFileNames = FileUtil.splitFileNameHasDot(childFilename);
String newFileName = newFileNames[0] + "(" + (++fileEndIndex) + ")" + newFileNames[1];
fileout = new File(folder,newFileName);
}
if (fileEndIndex!=0){
String[] newFileNames = FileUtil.splitFileNameHasDot(childFilename);
childFilename = newFileNames[0] + "(" + fileEndIndex + ")" + newFileNames[1];
}
//创建新文件
fileout.createNewFile();
FileOutputStream fos = new FileOutputStream(fileout);
int ta = Integer.parseInt(childFilesize);
byte[] buf = new byte[1024*10];
//InputStream ins = socket.getInputStream();
while(true){
if(ta==0){
break;
}
int len = ta;
if(len>buf.length){
len = buf.length;
}
int rlen = in.read(buf, 0, len);
//int rlen = ins.read(buf, 0, len);
ta -= rlen;
if(rlen>0){
fos.write(buf,0,rlen);
fos.flush();
}
else{
break;
}
}
out.println("cp finish!");
fos.close();
System.out.println("服务器端已存储文件: " + fileout.getPath());
childFileaddr = "/"+UPLOAD_ROOT+UPLOAD_TYPE+USER_DIR+"/"+childFilename;
if (childGame.equals("")){
WebdiskLog wl = new WebdiskLog();
wl.setUsername(childUserid);
wl.setFilename(childFileaddr);
wl.setFilesize(childFilesize);
wl.setUploadtime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new GregorianCalendar().getTime()));
new WebdiskLogDAO().add(wl, null);
System.out.println("服务器端已写入webdisk上传日志数据库: " + childFileaddr);
}else{
}
break;
}
else{
System.out.println("err command!");
out.println("err command!");
break;
}
}
socket.close();
}catch(Exception e){
e.printStackTrace();
}
}
String getFileInfo(InputStream in, int len){
String result = null;
try{
byte cmd[] = new byte[len];
int b = 0;
while(b<cmd.length){
b += in.read(cmd, b, cmd.length-b);
}
int ends = 0;
for(int i=0;i<cmd.length;i++){
if(cmd==0x00000000){
ends = i;
break;
}
}
result = new String(cmd,0,ends);
}catch(Exception ex){
ex.printStackTrace();
}
return result;
}
}
};
fileThread.setDaemon(true);
fileThread.start();
客户端核心代码:
Thread uploadThread = new Thread(){
final String localPath = newItemTableItem.getText(0);
final String realFilename = newItemTableItem.getText(3);
final String uploadFolder = newItemTableItem.getText(2);
final TableItem childTi = newItemTableItem;
final TableEditor te = (TableEditor)childTi.getData();
final ProgressBar pb = (ProgressBar)te.getEditor();
public void run(){
try {
InetAddress addr = InetAddress.getByName(Config.getInstance().getProperty("inner_web_ip"));
Socket socket =
new Socket(addr, Integer.valueOf(Config.getInstance().getProperty("webdisk_savegame_port")).intValue());
OutputStream out = socket.getOutputStream();
File filein = new File(localPath);
//发送命令
sendFileInfo(out, 128, "cp");
//发送用户名
sendFileInfo(out, 30, AppManager.user.getUsername());
//发送网吧硬盘目录
sendFileInfo(out, 128, uploadFolder);
//发送游戏
sendFileInfo(out, 128, "");
//发送文件名
sendFileInfo(out, 256, realFilename);
//发送文件大小
sendFileInfo(out, 128, ""+filein.length());
//发送其它信息...
FileInputStream fis = null;
byte[] buf = new byte[1024*10];
//char[] bufC = new char[1024*10];
fis = new FileInputStream(filein);
int readsize = 0;
int countNum = 0;
//OutputStream ops = socket.getOutputStream();
while((readsize = fis.read(buf, 0, buf.length))>0){
out.write(buf,0,readsize);
out.flush();
countNum+=readsize;
final int progress = countNum;
Display.getDefault().asyncExec(new Runnable(){
public void run(){
//更新进度
pb.setSelection(progress);
//pb.redraw();
}
});
}
out.close();
socket.close();
fis.close();
Display.getDefault().asyncExec(new Runnable(){
public void run(){
pb.setSelection(pb.getMaximum());
childTi.setImage(0, ImageManager.getInstance().getInterfaceImage(display, "udload_susseful.gif"));
getFileList(null, null, null, null, null);
}
});
} catch (Exception ex) {
ex.printStackTrace();
if (pb.getSelection()==pb.getMaximum()){
childTi.setImage(0, ImageManager.getInstance().getInterfaceImage(display, "udload_susseful.gif"));
}else{
childTi.setImage(0, ImageManager.getInstance().getInterfaceImage(display, "udload_failed.gif"));
}
}
}
void sendFileInfo(OutputStream out, int len, String content){
try{
byte[] cmd = new byte[len];
byte[] tcmd = content.getBytes();
for(int i=0;i<tcmd.length;i++){
cmd = tcmd;
}
cmd[tcmd.length] = 0x00000000;
out.write(cmd,0,cmd.length);
}catch(Exception ex){
ex.printStackTrace();
}
}
};
//uploadThread.setDaemon(true);
uploadThread.start();
这里要注意的是, 既然是自定义的传输协议, 在文件流之前传输的字节必须是事先定义好的, 例如: 客户端向服务器发送了5个文件额外属性, 标识此文件信息, 则服务器读取时要先将这5个属性读出来, 而且客户端写入时每个属性的字节长度必须和服务器读取时使用的字节长度相同, 否则便失败了! 另外, 每个属性之间的字节间隔我使用了16进制的 0x00000000 来标识, 以便服务器端读取时分隔.