signed

QiShunwang

“诚信为本、客户至上”

Java基础 第五节 第三课

2020/12/27 2:48:45   来源:

综合案例

  • 概述
  • 图解
  • 基本实现
    • 服务端实现
    • 客户端实现
  • 文件上传优化
    • 上传分析
      • 文件名写死的问题
      • 循环接收的问题
      • 效率问题
    • 代码展示
    • 回写分析
    • 代码展示

概述

文件上传案例:

  1. 客户端输入流, 从硬盘读取文件数据到程序中
  2. 客户端输出流, 写出文件数据到服务端
  3. 服务端输入流, 读取文件数据到服务端程序
  4. 服务端输出流, 写出文件数据到服务器硬盘中

图解

在这里插入图片描述

基本实现

服务端实现

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class FileUpload_Server {
    public static void main(String[] args) throws IOException {
        System.out.println("服务器, 启动...");
        // 1. 创建服务端ServerSocket
        ServerSocket ss = new ServerSocket(6666);
        // 2. 建立连接
        Socket server = ss.accept();
        // 3. 创建对象
        BufferedInputStream bis = new BufferedInputStream(server.getInputStream());  // 获取输入流, 读取文件数据
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a.jpg"));  // 创建输出流, 保存到本地
        // 4. 写出数据
        byte[] bytes = new byte[1024];
        int len;
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
        }
        // 5. 关闭资源
        bos.close();
        bis.close();
        server.close();
        System.out.println("文件上传已保存");
    }
}

客户端实现

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;

public class FileUpload_Client {
    public static void main(String[] args) throws IOException {
        // 1. 创建流对象
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("test.jpg"));  // 创建输入流, 读取本地文件
        Socket socket = new Socket("localhost", 6666);  // 创建输出流, 写到服务端
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

        // 2. 写出数据
        byte[] bytes = new byte[1024 * 8];
        int len;
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
            bos.flush();
        }
        System.out.println("文件发送完毕");
        // 3. 释放资源
        bos.close();
        socket.close();
        bis.close();
    }
}

文件上传优化

上传分析

文件名写死的问题

服务端, 保存文件的名称如果写死, 那么最终导致服务器硬盘, 只会保留一个文件. 建议使用系统时间优化, 保证文件名称唯一, 代码如下:

FileOutputStream fos = new FileOutputStream(System.currentTimeMillis() + ".jpg");
BufferedOutputStream bos = new BufferedOutputStream(fos)

循环接收的问题

服务端, 指保存一个文件就关闭了, 之后的用户无法再上传, 这是不符合实际的. 使用循环改进, 可以不断的接收不同的文件, 代码如下:

while (true) {
    Socket server = ss.accept();
    ......         
}

效率问题

服务端, 在接收大文件时, 可能耗费几秒钟的时间, 此时间不能接收其他用户上传. 所以, 使用多线程技术优化, 代码如下:

while (true) {
    Socket server = ss.accept();
    // Socket对象交给子线程处理, 进行读写操作
    // Runnable接口中, 只有一个run方法, 使用lambda表达简化格式
    new Thread(() -> {
        
    }).start();
}

代码展示

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class FileUpload_Server {
    public static void main(String[] args) throws IOException {
        System.out.println("服务器, 启动...");
        // 1. 创建服务端ServerSocket
        ServerSocket ss = new ServerSocket(6666);
        // 2. 循环接收, 建立连接
        while (true) {
            Socket server = ss.accept();
            // 3. Socket对象交给子线程处理, 进行读写操作
            // Runnable接口中, 只有一个run方法, 使用lambda表达简化格式
            new Thread(() -> {
                try (
                        // 获取输入流对象
                        BufferedInputStream bis = new BufferedInputStream(server.getInputStream());
                        // 创建输出流对象, 保存到本地
                        FileOutputStream fos = new FileOutputStream(System.currentTimeMillis() + ".jpg");
                        BufferedOutputStream bos = new BufferedOutputStream(fos)
                ) {
                    // 读写数据
                    byte[] bytes = new byte[1024 * 8];
                    int len;
                    while ((len = bis.read(bytes)) != -1) {
                        bos.write(bytes, 0, len);
                    }
                    System.out.println("文件上传已保存");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

回写分析

前四步与基本文件上传一致.

  1. 客户端输入流, 从硬盘读取文件数据到程序中
  2. 客户端输出流, 写出文件数据到服务端
  3. 服务端输入流, 读取文件数据到服务端程序
  4. 服务端输出流, 写出文件数据到服务器硬盘中
  5. 服务器输出流, 回写数据
  6. 客户端输入流, 解析回写数据

在这里插入图片描述

代码展示

服务端:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class FileUpload_Server {
    public static void main(String[] args) throws IOException {
        System.out.println("服务器, 启动...");
        // 1. 创建服务端ServerSocket
        ServerSocket ss = new ServerSocket(6666);
        // 2. 循环接收, 建立连接
        while (true) {
            Socket server = ss.accept();
            // 3. Socket对象交给子线程处理, 进行读写操作
            // Runnable接口中, 只有一个run方法, 使用lambda表达简化格式
            new Thread(() -> {
                try (
                        // 获取输入流对象
                        BufferedInputStream bis = new BufferedInputStream(server.getInputStream());
                        // 创建输出流对象, 保存到本地
                        FileOutputStream fos = new FileOutputStream(System.currentTimeMillis() + ".jpg");
                        BufferedOutputStream bos = new BufferedOutputStream(fos)
                ) {
                    // 读写数据
                    byte[] bytes = new byte[1024 * 8];
                    int len;
                    while ((len = bis.read(bytes)) != -1) {
                        bos.write(bytes, 0, len);
                    }
                    // ======================回写数据======================
                    System.out.println("back...");
                    OutputStream os = server.getOutputStream();
                    os.write("上传成功".getBytes());
                    System.out.println("文件上传已保存");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

客户端:

import java.io.*;
import java.net.Socket;

public class FileUpload_Client {
    public static void main(String[] args) throws IOException {
        // 1. 创建流对象
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("test.jpg"));  // 创建输入流, 读取本地文件
        Socket client = new Socket("localhost", 6666);  // 创建输出流, 写到服务端
        BufferedOutputStream bos = new BufferedOutputStream(client.getOutputStream());

        // 2. 写出数据
        byte[] bytes = new byte[1024 * 8];
        int len;
        while ((len = bis.read(bytes)) != -1) {
            bos.write(bytes, 0, len);
            bos.flush();
        }
        client.shutdownOutput();  // 关闭输出流, 通知服务端写出数据完毕
        System.out.println("文件发送完毕");
        // ======================解析回写======================
        // 3. 解析回写
        InputStream is = client.getInputStream();
        byte[] back = new byte[1024];
        is.read(back)
        System.out.println(new String(back));

        // 4. 释放资源
        bos.close();
        client.close();
        bis.close();
    }
}