黑马程序员技术交流社区

标题: 【成都校区】IO流综合操作案例 [打印本页]

作者: 逍遥来了    时间: 2018-11-29 13:19
标题: 【成都校区】IO流综合操作案例
本帖最后由 逍遥来了 于 2018-11-29 13:25 编辑

最近学习了IO流,抽时间结合课外资料写了一个上传文件案例,可以多线程上传、上传文件及IP地址端口可在本地文件中配置,保存文件后缀名自动匹配,客户端上传文件时在控制台显示上传进度。现附上代码:
*********服务端*********
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* @author xiaoyaolaile
* @version 1.0
*/
public class FileUploadServer {

    public static void main(String[] args) throws IOException {
        //创建Socket对象
        System.out.println("服务器 启动...");
        ServerSocket sc = new ServerSocket(6666);

        //客户端连接数
        int count = 0;

        //创建线程池
        ExecutorService es = Executors.newCachedThreadPool();

        while (true) {
            //循环建立连接
            Socket accept = sc.accept();

            System.out.println("建立第" + (++count) + "个客户端连接...");

            //连接池提交任务方式
            es.submit(() -> {
                //创建File对象,封装目的地
                File dest = new File("D:" + File.separator + "upload");
                if (!dest.exists()) {
                    dest.mkdirs();
                }

                try {
                    //获取上传文件名
                    InputStream is = accept.getInputStream();
                    int len = 0;
                    String filename = "";
                    while ((len = is.read()) != -1) {
                        if (len == '*') {
                            break;
                        }
                        filename += (char)len;
                    }
                    System.out.println("文件名是"+filename);

                    //创建输入流,读入客户端发送数据
                    BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
                    //创建输出流,保存到本地
                    BufferedOutputStream bos = new BufferedOutputStream(
                            new FileOutputStream(dest + File.separator + filename));

                    //读写操作
                    byte[] bytes = new byte[1024*8];
                    while ((len = bis.read(bytes)) != -1) {
                        bos.write(bytes, 0, len);
                    }

                    //=====信息回写=====
                    System.out.println("文件已接收,保存路径:"+dest.getAbsolutePath());
                    OutputStream out = accept.getOutputStream();
                    out.write("上传成功".getBytes());
                    out.close();

                    //=====关闭资源=====
                    bos.close();
                    bis.close();
                    accept.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "保存成功!");
            });

            //匿名线程显示创建
            //new Thread(()->....).start();

        }
    }
}

********客户端********
/**
* @author xiaoyaolaile
* @version 1.0
*/
public class FileUploadClient {
    /**
     * 源文件地址
     */
    static String srcPath;
    /**
     * 服务器IP地址
     */
    static String ipAddr;
    /**
     * 服务器端口
     */
    static String port;

    static {
        //创建读取配置文件流,设置源文件地址
        Properties properties = new Properties();
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("upload.properties");
            properties.load(fis);
            srcPath = properties.getProperty("srcPath");
            ipAddr = properties.getProperty("ipAddr");
            port = properties.getProperty("port");

            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        //创建游标和进度条的对象
        Courior c = new Courior();
        ProBar pb = new ProBar(c);

        //创建Socket对象
        Socket client = null;
        try {
            client = new Socket(ipAddr, Integer.valueOf(port));
        } catch (IOException e) {
            System.out.println("连接失败,检查服务器是否启动/网络是否正常");
        }

        //创建输入流读入本地文件
        File f = new File(srcPath);
        System.out.println("上传:" + f.getName());
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(f));

        //告诉服务器上传文件名
        OutputStream os = client.getOutputStream();
        //约定*为终止符
        os.write((f.getName() + "*").getBytes());
        os.flush();

        //创建输出流写到服务端
        BufferedOutputStream bos = new BufferedOutputStream(client.getOutputStream());

        //设置进度条对象的文件总大小,并启动线程
        pb.setTotal(f.length());
        pb.start();
        System.out.println("开始上传...");

        //读写操作
        byte[] bytes = new byte[1024 * 8];
        int len = 0;
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
            //让游标记录变化
            c.setSize(c.getSize() + len);
        }
        bos.flush();
        client.shutdownOutput();

        //判断进度条线程是否结束,如果未结束,则睡眠主线程。
        while (pb.isAlive()) {
            Thread.sleep(1);
        }
        System.out.println('\n' + "文件发送完毕");

        //=====解析回写=====
        InputStream in = client.getInputStream();
        byte[] back = new byte[64];
        int backLen = in.read(back);
        System.out.println(new String(back, 0, backLen));
        in.close();

        //====关闭资源=====
        bis.close();
        client.close();

        System.out.println("客户端关闭...");

    }
}

/**
* 定义一个游标类实现客户端线程和进度条线程的进度共享
*
* @version 1.0
*/
class Courior {
    /**
     * size 记录已上传部分的文件大小
     */
    private long size;

    public long getSize() {
        return size;
    }

    public void setSize(long size) {
        this.size = size;
    }
}

/**
* 定义一个进度条类,实现进度条打印
*
* @version 1.0
*/
class ProBar extends Thread {
    /**
     * total 保存文件的总长度
     */
    private long total;
    /**
     * courior 封装游标引用
     */
    private Courior courior;
    /**
     * formater 封装一个数据转换类对象
     */
    private DecimalFormat formater = new DecimalFormat("#.##%");

    public ProBar(Courior courior) {
        this.courior = courior;
    }

    public long getTotal() {
        return total;
    }

    public void setTotal(long total) {
        this.total = total;
    }

    @Override
    public void run() {

        //当前上传文件大小小于文件总大小时进入循环
        while (courior.getSize() < total) {
            System.out.print('\r' + "上传进度:[");
            //箭头随着文件大小增加而增多
            for (int i = 0; i < courior.getSize() * 1.0 / total * 10; i++) {
                System.out.print(">");
            }
            //横杠随着文件大小增加而减少
            for (int j = 10; j > courior.getSize() * 1.0 / total * 10; j--) {
                System.out.print("-");
            }
            //打印进度数值
            System.out.print("]【" + formater.format((float) (courior.getSize() * 1.0 / total)) + "】");

            //显示刷新频率
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //当前上传文件大小等于文件总大小时再打印一次
        System.out.print('\r' + "上传进度:[");
        int max = 10;
        for (int i = 0; i < max; i++) {
            System.out.print(">");
        }
        System.out.print("]【" + formater.format((float) (courior.getSize() * 1.0 / total)) + "】");

    }
}
********配置文件********
在当前项目路径下新建upload.properties文件,内容格式为:
#上传配置文件
#源文件路径
srcPath = D:\\\\App.ico
#服务器地址
ipAddr = localhost
#服务器端口
port = 6666
修改key对应的值即可上传想要的文件

结果示例:
客户端------




服务端------






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2