好长时间没用java了... 需要在两台电脑上把文件同步,用java实现了个。。。其实用python以及系统自带的命令更容易实现。。。
遇到的问题:
1. java 的byte[] 向 int long 转换,自己写的转换函数,使用 ret = ret << 8 + byte_i 时,会有问题,因为 << 的优先级比低,改成 ret = (ret<<8) + byte_i 依然有问题,因为byte_i是有符号的。。。int 与 byte 进行运算时,byte会向上扩展。。。。我的实现:
ret = (ret <<8) | (0xff & b[i]);
2.考虑如何将字节转换为float及double: Float有一个方法 Float.intBitsToFloat( int i ),同样Double.longBitsToDouble( long i )。
3. socket的 flush 问题:如果不flush,使用write对socket的输出流发送数据之后,有可能数据一直缓冲在本机中。。。
写的较为简单,没有图形界面,且一旦开始执行没法取消,客户端也没有指定(手动或自动判断)需要同步的文件,后续加上其它功能。。。
服务器端代码:
import java.net.*;
import java.io.*;
class Util{
public static byte [] i2b(int i){
byte[] b = new byte[4];
for(int i1=0; i1<4; i1++ ){
int v = ((i>>(8*i1)) & 0xff);
b[3-i1]=(byte)v;
}
return b;
}
public static byte [] i2b(long i){
byte[] b = new byte[8];
for(int i1=0; i1<8; i1++ ){
b[7-i1]=(byte)((i>>(8*i1)) & 0xff);
}
return b;
}
public static void writeInteger(OutputStream os, int val)throws IOException{
byte [] b = i2b(val);
// off=4时,即已经读取了4个字节,跳出.
int off = 0;
os.write(b, 0, b.length );
}
public static void writeFileInfo(OutputStream os, File f)throws IOException{
//文件名:长度,文件内容长度.md5.
//输出文件名,输出文件内容。
byte [] name = f.getName().getBytes();
byte [] name_len = i2b(name.length);
byte [] content_len = i2b( f.length() );
// 文件名长度.
os.write( name_len );
// 文件名.
os.write( name );
// 文件内容长度.
os.write( content_len );
os.flush();
}
public static boolean writeFileContent(OutputStream os, File f)throws IOException{
//文件名:长度,文件内容长度.md5.
//输出文件名,输出文件内容。
long content_len = f.length();
FileInputStream fis = new FileInputStream(f);
byte [] buf = new byte[128];
long len = 0;
int n = 0;
while( (n = fis.read(buf, 0, buf.length))!=-1 ){
len += n;
os.write(buf, 0, n);
os.flush();
System.out.println("发送:" + n + "字节。");
}
System.out.println("##共发送" + len + "字节##");
return len == f.length();
}
}
public class Server extends Thread {
ServerSocket server = null;
Socket sk = null;
BufferedReader rdr = null;
PrintWriter wtr = null;
void close(){
try {
sk.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Server(int port) throws Exception{
try{
server = new ServerSocket(port);
}catch( IOException e ){
e.printStackTrace();
throw new Exception( e.getMessage() );
}
}
public void run(){
while( true ){
System.out.println("Listenning...");
System.out.println( server.toString() );
try{
//将请求交给一个线程去处理.
sk = server.accept();
//ServerThread
ServerThread th = new ServerThread( sk );
th.start();
}catch( Exception e){
e.printStackTrace();
}
}
}
class ServerThread extends Thread{
Socket sk = null;
public ServerThread( Socket sk ){ this.sk = sk; }
void sendFile( String fname ){
try{
File f = new File( fname );
System.out.println( f.toString() + "#" + f.length());
DataOutputStream dout = new DataOutputStream( new BufferedOutputStream( sk.getOutputStream()));
//写文件元信息:
Util.writeFileInfo(dout, f);
boolean ret = Util.writeFileContent(dout, f);
String ret_msg = "";
if( ret )ret_msg = "传输完成.";
else ret_msg = "传输失败.";
System.out.println( ret_msg );
}catch( Exception e ){
e.printStackTrace();
}
}
public void run(){
try{
// 将一个文件写回客户端。
// 格式:[文件名长度,文件名],[文件内容长度,文件内容]。
PrintWriter wtr = new PrintWriter(sk.getOutputStream());
BufferedReader rdr = new BufferedReader(new InputStreamReader(sk.getInputStream()));
//
System.out.println("Server线程开始发送文件.");
/*枚举出一个文件夹中的内容,由其md5决定是否传送*/
String file_name = "F:/Share/file_1.txt";
sendFile( file_name );
}catch( Exception e ){
e.printStackTrace();
}
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int port = 2019;
Server server = null;
try {
server = new Server( port );
server.run();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
server.close();
}
}
}
客户端代码:
import java.net.*;
import java.io.*;
class Util{
public static int b2i(byte [] b){
int ret = 0;
for(int i=0; i<4&&i<b.length; i++){
ret = (ret <<8) | b[i];
}
return ret;
}
public static long b2long(byte [] b){
long ret = 0;
for(int i=0; i<8&&i<b.length; i++){
ret = (ret <<8) | (0xff & b[i]);
}
return ret;
}
public static byte [] i2b(int i){
byte[] b = new byte[4];
for(int i1=0; i1<4; i1++ ){
b[3-i1]=(byte)((i>>(8*i1)) & 0xff);
}
return b;
}
public static byte [] i2b(long i){
byte[] b = new byte[8];
for(int i1=0; i1<8; i1++ ){
b[3-i1]=(byte)((i>>(8*i1)) & 0xff);
}
return b;
}
public static byte[] readNBytes(InputStream is, int len)throws IOException{
byte [] b = new byte[len];
int off = 0;
while( off < len ){
int n= is.read(b, off, len-off);
if( n == -1 ){
throw new IOException();
}
off += n;
}
return b;
}
public static int readInteger(InputStream is)throws IOException{
byte [] b = readNBytes(is, 4);
return b2i(b);
}
public static long readLong(InputStream is)throws IOException{
byte [] b = readNBytes(is, 8);
return b2long(b);
}
public static void writeInteger(OutputStream os, int val)throws IOException{
byte [] b = i2b(val);
// off=4时,即已经读取了4个字节,跳出.
int off = 0;
os.write(b, 0, b.length );
}
public static void writeFileInfo(OutputStream os, File f)throws IOException{
//文件名:长度,文件内容长度.md5.
//输出文件名,输出文件内容。
long content_len = f.length();
byte [] name = f.getName().getBytes();
// 文件名长度.
os.write( i2b(name.length) );
// 文件名.
os.write( name );
// 文件内容长度.
os.write( i2b(content_len) );
os.flush();
}
public static boolean writeFileContent(OutputStream os, File f)throws IOException{
//文件名:长度,文件内容长度.md5.
//输出文件名,输出文件内容。
long content_len = f.length();
FileInputStream fis = new FileInputStream(f);
byte [] buf = new byte[128];
long len = 0;
int n = 0;
while( (n = fis.read(buf, 0, buf.length))!=-1 ){
len += n;
os.write(buf, 0, n);
}
return len == f.length();
}
public static boolean readFile(InputStream is, String path)throws IOException{
//文件名:长度,文件内容长度.md5.
//输出文件名,输出文件内容。
int fname_len = readInteger( is );
String fname = new String( readNBytes(is, fname_len) );
long content_len = readLong( is );
System.out.println("文件名长度:" + new Integer(fname_len).toString()+"字节.");
System.out.println("开始下载文件:" + fname + "x");
System.out.println("文件长度:"+new Long(content_len).toString()+"字节.");
File f = new File(path + fname);
FileOutputStream fos = new FileOutputStream(f);
byte [] buf = new byte[128];
long len = 0;
int n = 0;
while( true ){
System.out.println("进入循环1。。");
n = is.read(buf, 0, 4);
if( -1 == n)break;
System.out.println("进入循环2。。");
len += n;
System.out.println("接收"+n+"字节 ");
System.out.println("下载:" + new Float( (1.0f*len)/content_len ).toString() + "%");
fos.write(buf, 0, n);
}
fos.flush();
fos.close();
System.out.println("##共接收" + len + "字节 ##");
return len == content_len;
}
}
public class Client {
//private ClientSocket cs = null;
private String server_ip = "10.108.14.222";
private int server_port = 2019;
private Socket s = null;
public Client(int port){ server_port = port;}
public void run(){
try{
s = new Socket();
s.connect( new InetSocketAddress(server_ip, server_port ));
OutputStream os = s.getOutputStream();
InputStream is = s.getInputStream();
System.out.println("开始下载...");
Util.readFile(is,"D:/share2/");
/*关闭*/
s.shutdownInput();
s.shutdownOutput();
is.close();
os.close();
s.close();
}catch( Exception e ){
e.printStackTrace();
}
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int port = 2019;
new Client(port).run();
}
}