原文地址:http://blog.csdn.net/whoami021/article/details/21656875
上一篇文章我们实现聊天的功能,下面我们看文件传输怎么实现。
我的做法是:增加一个文件服务器,所有上传和下载文件的操作都由文件服务器来处理。
因此处理逻辑是这样的:如果用户请求上传文件或者下载文件,那么就将用户直接与文件服务器通信,而不用经过中央服务器。
所以现在的问题是知道java怎么实现上传和下载文件,如果这个问题解决了,那基本就搞定了。
首先,文件传输基本都是用面向连接的方式。因为无连接的方式容易丢包,一旦丢了一个数据包,文件就坏了,所有努力全白费。但是需要注意的是面向连接的方式,在服务器处理完一个连接后该连接就关闭了。
下面看代码,在原来的基础上我新建了两个主要文件:FileServer.java和FileClient..java。
- package chat.net.file;
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.util.Iterator;
- import java.util.Set;
- import java.util.TreeMap;
- import chat.Globals;
- /**
- * 文件服务器
- *
- * @author michael
- *
- */
- public class FileServer {
- private TreeMap<String, String> fileMap = new TreeMap<>();
- private final String SavePath = "save/";// 上传文件保存目录
- private final int port = 8821;
- private ServerSocket ss;
- private Socket s;
- private String sender;// 上传者名字
- private String receiver;// 接收者名字
- private int bufferSize = 8192;
- public void start() {
- try {
- // 创建目录
- File file = new File(SavePath);
- if (!file.exists()) {
- file.mkdir();
- }
- ss = new ServerSocket(port);
- while (true) {
- s = ss.accept();
- DataInputStream dis = new DataInputStream(
- new BufferedInputStream(s.getInputStream()));
- dis.readByte();// 运行环境
- int req = dis.readInt();
- if (req == Globals.UploadReq) {// 用户上传文件
- recvFile(dis);
- } else {// 用户下载文件
- sendFile(dis);
- }
- }
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- private void recvFile(DataInputStream dis) {
- DataOutputStream dos = null;
- try {
- sender = dis.readUTF();// 发送者名字
- String savePath = SavePath;
- byte[] buf = new byte[bufferSize];
- long len = 0;
- String fileName = dis.readUTF();// 可能接收到终止的通知
- if (fileName.equals(String.valueOf(Globals.Exit))) {
- dis.close();
- return;
- }
- savePath += fileName;
- dos = new DataOutputStream(new BufferedOutputStream(
- new BufferedOutputStream(new FileOutputStream(savePath))));
- len = dis.readLong();
- System.out.println("文件的长度为:" + len);
- while (true) {
- int read = 0;
- if (dis != null) {
- read = dis.read(buf);
- }
- if (read == -1) {
- break;
- }
- dos.write(buf, 0, read);
- }
- fileMap.put(fileName, sender);
- System.out.println("接收完成,文件存为" + savePath);
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- dis.close();
- if (dos != null) {
- dos.close();
- }
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- private void sendFile(DataInputStream dis) {
- DataOutputStream dos = null;
- DataInputStream fis = null;
- try {
- receiver = dis.readUTF();
- dos = new DataOutputStream(s.getOutputStream());
- // 给客户端发送文件列表
- String fileList = "文件列表:\n";
- if (fileMap.size() == 0) {
- dos.writeUTF("");
- return;
- }
- Set<String> set = fileMap.keySet();
- Iterator<String> it = set.iterator();
- String key;
- int i = 0;
- while (it.hasNext()) {
- ++i;
- key = it.next();
- fileList += i + ".<" + key + "," + fileMap.get(key) + ">";
- }
- dos.writeUTF(fileList);
- String fileName = getFileName(fileList, dis.readInt());
- File file = new File(SavePath + fileName);
- // 开始发送文件
- fis = new DataInputStream(new BufferedInputStream(
- new FileInputStream(file)));
- dos.writeUTF(fileName);
- dos.flush();
- dos.writeLong((long) file.length());
- dos.flush();
- byte[] buf = new byte[bufferSize];
- int read = 0;
- while (true) {
- read = fis.read(buf);
- if (read == -1) {
- break;
- }
- dos.write(buf, 0, read);
- }
- dos.flush();
- System.out.println("文件" + fileName + "传输完成");
- } catch (Exception e) {
- // TODO: handle exception
- e.printStackTrace();
- } finally {
- try {
- dis.close();
- if (fis != null) {
- fis.close();
- }
- dos.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
- private String getFileName(String fileList, int no) {
- String fileName = fileList.substring(fileList.indexOf(String
- .valueOf(no)));
- fileName = fileName.substring(fileName.indexOf("<") + 1,
- fileName.indexOf(","));
- return fileName;
- }
- public static void main(String[] args) {
- new FileServer().start();
- }
- }
- package chat.net.file;
- import java.io.BufferedInputStream;
- import java.io.BufferedOutputStream;
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.net.Socket;
- import java.net.UnknownHostException;
- import java.util.Scanner;
- import chat.Globals;
- /**
- * 文件客户端 支持上传和下载文件
- *
- * @author michael
- *
- */
- public class FileClient {
- private String HOST = "127.0.0.1";
- private final int port = 8821;
- private Socket socket;
- private String ENV = "linux";// 运行环境
- private int bufferSize = 8192;
- private Scanner sc = new Scanner(System.in);
- /**
- * 上传文件
- *
- * @param req
- * @param peer
- */
- public void uploadFile(int req, String peer) {
- try {
- socket = new Socket(HOST, port);
- sendMessage(req, peer);// 发送操作类型
- System.out.print("输入上传文件的绝对路径:");
- String path = sc.next();
- // String path = "/home/michael/Desktop/zouning71.rar";
- // 发送文件
- File file = new File(path);
- DataInputStream dis = new DataInputStream(new BufferedInputStream(
- new FileInputStream(file)));
- DataOutputStream dos = new DataOutputStream(
- socket.getOutputStream());
- if (!file.exists()) {
- System.out.println("该文件不存在");
- dos.writeUTF(String.valueOf(Globals.Exit));
- dos.flush();
- return;
- }
- sendFile(dis, dos, file);
- } catch (Exception e) {
- // TODO: handle exception
- e.printStackTrace();
- }
- }
- private void sendFile(DataInputStream dis, DataOutputStream dos, File file) {
- try {
- // 将文件名及长度发给服务器
- dos.writeUTF(file.getName());
- dos.flush();
- dos.writeLong((long) file.length());
- dos.flush();
- byte[] buf = new byte[bufferSize];
- int read = 0;
- while (true) {
- read = dis.read(buf);
- if (read == -1) {
- break;
- }
- dos.write(buf, 0, read);
- }
- dos.flush();
- // 注意关闭socket链接,不然客户端会等待server的数据过来,
- // 直到socket超时,导致数据不完整。
- dis.close();
- dos.close();
- } catch (Exception e) {
- // TODO: handle exception
- e.printStackTrace();
- }
- }
- /**
- * 下载文件
- *
- * @param req
- * @param peer
- */
- public void downloadFile(int req, String peer) {
- try {
- socket = new Socket(HOST, port);
- sendMessage(req, peer);// 发送操作类型
- DataInputStream dis = new DataInputStream(socket.getInputStream());
- DataOutputStream dos = new DataOutputStream(
- socket.getOutputStream());
- // 接收文件列表
- String fileList = dis.readUTF();
- if (fileList.equals("")) {
- System.out.println("服务器没有文件");
- return;
- }
- System.out.println(fileList);
- System.out.print("输入要下载的文件序号:");
- dos.writeInt(sc.nextInt());
- dos.flush();
- System.out.print("输入文件的保存位置(绝对路径):");
- String savePath = sc.next();
- // String savePath = "/home/michael/Desktop/";
- recvFile(dis, dos, savePath);
- } catch (Exception e) {
- // TODO: handle exception
- e.printStackTrace();
- }
- }
- private void sendMessage(int req, String peer) {
- DataOutputStream dos = null;
- try {
- dos = new DataOutputStream(socket.getOutputStream());
- if (ENV.equalsIgnoreCase("windows")) {
- dos.writeByte(0x1);
- dos.flush();
- } else if (ENV.equalsIgnoreCase("unix")) {
- dos.writeByte(0x2);
- dos.flush();
- } else if (ENV.equalsIgnoreCase("linux")) {
- dos.write(0x3);
- dos.flush();
- } else {
- dos.writeUTF(ENV);
- dos.flush();
- }
- dos.writeInt(req);// 向服务器发送操作类型:上传文件OR下载文件
- dos.writeUTF(peer);// 上传者或者下载者
- dos.flush();
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- private void recvFile(DataInputStream dis, DataOutputStream dos,
- String savePath) {
- try {
- byte[] buf = new byte[bufferSize];
- long len = 0;
- String fileName = dis.readUTF();
- if (!savePath.endsWith("/")) {
- savePath += "/";
- }
- savePath += fileName;
- dos = new DataOutputStream(new BufferedOutputStream(
- new BufferedOutputStream(new FileOutputStream(savePath))));
- len = dis.readLong();
- System.out.println("文件的长度为:" + len);
- int read = 0;
- while (true) {
- read = dis.read(buf);
- if (read == -1) {
- break;
- }
- dos.write(buf, 0, read);
- }
- System.out.println("接收完成,文件存为" + savePath);
- dis.close();
- dos.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args) {
- FileClient client = new FileClient();
- client.uploadFile(Globals.UploadReq, "noname");
- client.downloadFile(Globals.DownloadReq, "noname");
- }
- }
上面这两个文件就可以实现文件上传和下载了,有需要完整工程代码的请点击这里。
测试的时候先运行两个服务器:Server和FileServer,然后在运行Main。