[java]客户端从服务器下载文件

这篇博客分享了作者使用Java实现从服务器下载文件的过程,遇到的问题包括:byte到int转换的位运算错误、如何转换为浮点数和双精度数、以及Socket的flush操作。虽然Python和系统命令可能更方便,但作者还是详细介绍了Java实现的细节,并指出代码目前的局限性,如无图形界面、无法取消操作等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

好长时间没用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();
	}

}





























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值