客户端

  • 文件上传案例的客户端:读取本地文件,上传到服务器,读取服务器回写的数据

  • 明确:

  • 数据源: c:11.jpg目的地:服务器

  • 实现步骤:

  • 1,创建一个本地字节输入流FileInputstream对象,构造方法中绑定要读取的数据源

  • 2·创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号

  • 3,使用Socket中的方法getOutputstream,获取网络字节输出流outputStream对象

  • 4·使用本地字节输入流FileInputStream对象中的方法read,读取本地文件

  • 5·使用网络字节输出流OutputStream对象中的方法write,把读取到的文件上传到服务器

  • 6·使用Socket中的方法getInputstream,获取网络字节输入流Inputstream对象

  • 7·使用网络字节输入流Inputstream对象中的方法read读取服务回写的数据

  • 8.释放资源(FileInputStream, Socket)

  1. public static void main(String[] args) throws IOException {
  2. // 1,创建一个本地字节输入流FileInputstream对象,构造方法中绑定要读取的数据源
  3. FileInputStream fis = new FileInputStream("/Users/xuxian/Documents/tx.jpg");
  4. // 2·创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
  5. Socket socket = new Socket("127.0.0.1", 8888);
  6. // 3.使用Socket中的方法getOutputstream,获取网络字节输出流outputStream对象
  7. OutputStream os = socket.getOutputStream();
  8. // 4.使用本地字节输入流FileInputStream对象中的方法read,读取本地文件
  9. int len = 0;
  10. byte[] bytes = new byte[1024];
  11. while ((len = fis.read(bytes)) != -1) {
  12. /*
  13. fis.read(bytes)读取本地文件,结束标记是读取到-1结束
  14. while循环里会读取-1吗?不会那么也不会把结束标记写个服务器
  15. 解决:上传完文件,给服务器写一个结束标记
  16. void shutdownoutput()禁用此套接字的输出流。
  17. 对于TCP套接字,任何以前写入的数据都将被发送,并且后跟TCP的正常连接终止序列。
  18. */
  19. // 5·使用网络字节输出流OutputStream对象中的方法write,把读取到的文件上传到服务器
  20. os.write(bytes, 0, len);
  21. }
  22. socket.shutdownOutput();
  23. // 6·使用Socket中的方法getInputstream,获取网络字节输入流Inputstream对象
  24. InputStream is = socket.getInputStream();
  25. // 7·使用网络字节输入流Inputstream对象中的方法read读取服务回写的数据
  26. while ((len = is.read(bytes)) != -1) {
  27. System.out.println(new String(bytes, 0, len));
  28. }
  29. // 8.释放资源(FileInputStream, Socket)
  30. fis.close();
  31. socket.close();
  32. }

服务器端

  • 文件上传案例服务器端:读取客户端上传的文件,保存到服务器的硬盘,给客户端回写”上传成功

  • 明确:

  • 数据源:客户端上传的文件

  • 目的地:服务器的硬盘d:\luploadl1 .jpg

  • 实现步骤

  • 1,创建一个服务器ServerSocket对象,和系统要指定的端口号

  • 2.使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象

  • 3.使用Socket对象中的方法getInputstream,获取到网络字节输入流Inputstream对象

  • 4·判断d: lupload文件夹是否存在,不存在则创建

  • 5·创建一个本地字节输出流FileOutputstream对象,构造方法中绑定要输出的目的地

  • 6,使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件

  • 7·使用本地字节输出流FileoutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上

  • 8.使用Socket对象中的方法getoutputstream,获取到网络字节输出流outputstream对象

  • 9,使用网络字节输出流Outputstream对象中的方法write,给客户端回写”上传成功

  • 10,释放资源(FileoutputStream, Socket, ServerSockd ```java public static void main(String[] args) {

    1. /*
    2. 让服务器一直处于监听状态(死循环accept方法)有一个客户端上传文件,就保存一个文件
    3. */
    4. while (true) {
    5. /*
    6. 使用多线程技术,提高程序的效率
    7. 有一个客户端上传文件,就弃启一个线程,完成文件的上传
    8. */
    9. new Thread(new Runnable() {
    10. @Override
    11. public void run() {
    12. try {

    // 1,创建一个服务器ServerSocket对象,和系统要指定的端口号

                      ServerSocket server = new ServerSocket(8888);
                      // 2,使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象
                      Socket socket = server.accept();
                      //        3,使用Socket对象中的方法getInputstream,获取到网络字节输入流Inputstream对象
                      InputStream is = socket.getInputStream();
                      //        4,判断d: lupload文件夹是否存在,不存在则创建
                      File filename = new File("/Users/xuxian/Desktop/upload");
                      if (!filename.exists()) {
                          filename.mkdirs();
                      }
                      //        5·创建一个本地字节输出流FileOutputstream对象,构造方法中绑定要输出的目的地
                  /*
                  自定义一个文件的命名规则:防止同名的文件被覆盖规则:域名+毫秒值+随机数
                   */
                      String fileName = "/xuxian" + System.currentTimeMillis() + new Random().nextInt(9999) + ".jpg";
                      FileOutputStream fos = new FileOutputStream(filename + fileName);
    

    // 6,使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件

                      int len = 0;
                      byte[] bytes = new byte[1024];
                      while ((len = is.read(bytes)) != -1) {
                      /*
                      is.read读取客户端上传的文件,
                      永远也读取不到文件的结束标记read方法计入到阻塞状态,
                      一直死循环等待结束标记
                       */
    

    // 7·使用本地字节输出流FileoutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上

                          fos.write(bytes, 0, len);
                      }
    

    // 8.使用Socket对象中的方法getoutputstream,获取到网络字节输出流outputstream对象

                      OutputStream os = socket.getOutputStream();
    

    // 9,使用网络字节输出流Outputstream对象中的方法write,给客户端回写”上传成功

                      os.write("上传成功".getBytes());
    

    // 10,释放资源(FileoutputStream, Socket, ServerSockd

                      fos.close();
                      socket.close();
                      server.close();
                  } catch (Exception e) {
                      System.out.println(e);
                  }
              }
    
        }).start();


    }
}



<a name="28362dc5"></a>
### 文件上传优化分析

<a name="a5320d5c"></a>
#### 1,文件名称写死的问题

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

```java
FileOutputStream fis = new FileoutputStream (System. currentTimeMillis()+".jpg") // 文件名称
Bufferedoutputstream bos = new Bufferedoutputstream(fis);

2.循环接收的问题

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

while (true) {
Socket accept = serverSocket.accept();
......
}

3,效率问题

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

new Thread(new Runnable() {
    @Override
    public void run() {

    }

网络线程里的 read问题

fis.read(bytes)读取本地文件,结束标记是读取到-1结束
while循环里会读取-1吗?不会那么也不会把结束标记写个服务器
解决:上传完文件,给服务器写一个结束标记
void shutdownoutput()禁用此套接字的输出流。
对于TCP套接字,任何以前写入的数据都将被发送,并且后跟TCP的正常连接终止序列。

自定义一个文件的命名规则

自定义一个文件的命名规则:防止同名的文件被覆盖规则:域名+毫秒值+随机数
String fileName = “/xuxian” + System.currentTimeMillis() + new Random().nextInt(9999) + “.jpg”;