文件可选择下载

目标:服务器提供一个目录下载,服务端可以任意选择其中的文件下载

具体思路代码中有注释

    /**
 * 服务器
 *
 */
public class Server1 {
	
	public static void main(String[] args) throws IOException {
		
		File dir = new File("D:/test");
		
		// 创建一个服务
		@SuppressWarnings("resource")
		ServerSocket ss = new ServerSocket(8888);
		System.out.println("服务器已启动");
		while(true){
			Socket s = ss.accept();
			String addr = s.getInetAddress().getHostAddress();
			System.out.println("客户端【"+addr+"】已连接");
			System.out.println("客户端【"+addr+"】开始下载...");
			new FileService(s, dir).start();
			System.out.println("客户端【"+addr+"】下载完成");
		}
	}
}
/**
 * 提供文件服务的类
 *
 */
public class FileService extends Thread{
	
	private Socket s;
	private File file;
	
	public FileService(Socket s, File file){
		this.s = s;
		this.file = file;
	}
	
	@Override
	public void run() {
		BufferedInputStream bis = null;
		try {
			// 1. 获取文件列表(仅标准文件) .... 之前有考虑效率问题将获取文件信息放到Server1中,可是这样就固定死了目录.放到这里的话在目录内容修改后进来的Socket也可以获取到
			File[] files = file.listFiles(new FileFilter(){
				@Override
				public boolean accept(File pathname) {
					return pathname.isFile();
				}
			});
			// 准备一个Map集合以编号->文件的方式存储文件信息
			Map<String, File> map = new HashMap<>();
			for (int i = 0; i < files.length; i++) {
				map.put(String.valueOf(i + 1), files[i]);
			}
			// 2. 将文件列表发送到客户端
			ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
			oos.writeObject(map);
			oos.flush();
			// 3. 接收客户端的指令(需要下载的文件编号)
			BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			String no = br.readLine();
			// 4. 根据文件编号找到文件并获取该文件的输入流
			File file = map.get(no);
			bis = new BufferedInputStream(new FileInputStream(file));
			// 5. 根据Socket的输出流将读取的文件内容写出去
			BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
			CopyUtils.copy(bis, bos, 1024);
			bos.flush();
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			try {
				if(s != null){
					s.close();
				}
				if(bis != null){
					bis.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
/**
 * 客户端
 */
public class Client1 {
	// 获取目录中文件
	public static Map<String,File> getFile(Socket s) throws IOException, ClassNotFoundException {
		// 获取基于Socket的对象输入流, 并读取传输过来的文件map
		ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
		Map<String, File> map = (Map<String, File>) ois.readObject();
		Set<String> keys = map.keySet();
		Iterator<String> it = keys.iterator();
		while (it.hasNext()) {
			String key = it.next();
			System.out.println("【" + key + "】" + map.get(key).getName());
		}
		return map;
	}
	// 将选择的文件编号发送给服务端,然后返回对应文件的名称
	public static String sendNum(Socket s, Map<String,File> map) throws IOException{
		System.out.println("请输入需要下载的文件编号");
		PrintWriter pw = new PrintWriter(s.getOutputStream());
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String no = br.readLine();
		pw.println(no);
		pw.flush();
		return map.get(no).getName();
	}
	
	public static void main(String[] args) throws UnknownHostException, IOException, ClassNotFoundException {
		// 指定下载目录
		File dir = new File("D:/test/test1");
		// 1. 连接到指定地址、端口的服务
		Socket s = new Socket("192.168.4.126", 8888);
		// 获取基于Socket的对象输入流, 并读取传输过来的文件map
		 Map<String,File> map = getFile(s);
		// 2. 获取控制台输入流和基于Socket的对象输出流,给服务端发送选项
		String fname = sendNum(s, map);
		// 3. 准备本地文件的输出流,存储来自Socket的输入流中文件数据
		BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(dir, fname)));
		System.out.println("开始下载");
		CopyUtils.copy(bis, bos, 1024);
		System.out.println("下载完成");
		s.close();
		bos.close();
	}
}
/**
 * 服务端和客户端中都得用到文件复制,故将其封装工具类中
 */
public class CopyUtils {
	
	public static void copy(InputStream is, OutputStream os, int length) throws IOException{
		int len = 0;
		byte[] b = new byte[length];
		while((len = is.read(b)) != -1){
			os.write(b,0,len);
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值