编写Java程序,实现客户端向服务端上传文件的功能

简介: 编写Java程序,实现客户端向服务端上传文件的功能

需求说明:


实现客户端向服务端上传文件的功能

当启动服务端后,运行客户端程序,系统提示客户在客户端输入上传文件的完整路径。当客户在客户端输入完成后,服务端实现文件上传


43.png

44.png


实现思路:


创建客户端类 FileClient 和服务端类 FileServer

在客户端类中定义uploadFile(Socket socket)方法,用于上传文件,使用BufferedOutputStream包装socket中输入流对象,使用new FileInputStream输入流对象读取本地文件,使用输出流将文件利用socket管道将数据循环发送至服务端

在客户端FileCliet类中,使用new Socket连接本地服务端和端口,调用uploadFile方法实现文件上传

在服务端类FileServer中,定义downFile()方法用于下载文件,该方法中使用BufferedInputStream包装socket中的输入流读取文件内容,并且使用FileOutputStream写到本地

分别运行服务端和客户端程序进行测试


实现代码:


服务端类 FileServer

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class FileServer {
  public ServerSocket server;
  public Socket socket;
  public void downloadFile() {
    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;
    try {
      // 获取Socket管道字节输入流
      InputStream in = socket.getInputStream();
      // 将Socket管道字节输入流,进行缓冲包装提高读取的速度
      bis = new BufferedInputStream(in);
      // 读取客户端发送的文件名
      int length = bis.read();
      byte[] b = new byte[length];
      bis.read(b);
      // 获取需要下载的文件名
      String fileName = this.getFileName(new String(b));
      // 下载的文件对象
      FileOutputStream fos = new FileOutputStream("H://" + this.getFileName(fileName));
      // 对FileOutputStream进行缓冲包装,提高写入的速度
      bos = new BufferedOutputStream(fos);
      // 创建临时变量保存数据
      int data = 0;
      // 写入文件
      while ((data = bis.read()) != -1) {
        bos.write(data);
      }
      System.out.println("客户/" + socket.getInetAddress() + ":上传文件[" + fileName + "]成功");
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if (bis != null) {
          bis.close();
        }
        if (bos != null) {
          bos.close();
        }
        server.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
  // 对文件的全路径进行拆分,返回文件名
  private String getFileName(String fn) {
    String[] files = fn.split("/");
    return files[files.length - 1];
  }
  // 创建服务器
  public void crateServer() {
    try {
      // 创建Socket实例
      server = new ServerSocket(8888);
      // 创建while循环接受多个客户端的连接
      while (true) {
        // 每一个连接的客户端都与服务器维护一条专属的Socket通信管道
        socket = server.accept();
        System.out.println("客户端已经连接");
        downloadFile();
        break;
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
  public static void main(String[] args) {
    new FileServer().crateServer();
  }
}


客户端类 FileClient


import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
public class FileClient {
  // 向服务器发送数据
  public void uploadFile(Socket socket) {
    BufferedReader reader = null;
    BufferedInputStream bis = null;
    BufferedOutputStream bos = null;
    try {
      System.out.println("请输入要上传文件的完成路径:");
      // 接收键盘输入
      InputStream in = System.in;
      // 获取Socket管道字节输出流
      OutputStream out = socket.getOutputStream();
      // 使用BufferedReader包装,便于按行读取客户端输入的数据
      reader = new BufferedReader(new InputStreamReader(in));
      // 客户端上传到服务端文件的名字
      String fileName = reader.readLine();
      // 创建字符文件输入流,用于读取上传文件中的数据
      FileInputStream fis = new FileInputStream(fileName);
      // 使用字节输入缓冲提高读取的速度
      bis = new BufferedInputStream(fis);
      // 获取Socket管道输出流,将从文件中的数据写入到管道中
      bos = new BufferedOutputStream(out);
      byte[] nbt = fileName.getBytes();
      // 将文件名字符串转换成字节数组的长度写入到Socket管道中
      bos.write(nbt.length);
      // 将字节数组写入到Socket管道中
      bos.write(nbt);
      // 定义临时变量,将从文件中读取到的数据写入到Socket管道中
      int data = 0;
      // 将文件中的数据写入到Socket管道中
      while ((data = bis.read()) != -1) {
        bos.write(data);
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      // 关闭io流和socket
      try {
        if (reader != null) {
          reader.close();
        }
        if (bis != null) {
          bis.close();
        }
        if (bos != null) {
          bos.close();
        }
        socket.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
  public static void main(String[] args) {
    Socket client = null;
    try {
      // 创建客户端套接字对象
      client = new Socket("127.0.0.1", 8888);
      new FileClient().uploadFile(client);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}
相关文章
|
20天前
|
Java 流计算
利用java8 的 CompletableFuture 优化 Flink 程序
本文探讨了Flink使用avatorscript脚本语言时遇到的性能瓶颈,并通过CompletableFuture优化代码,显著提升了Flink的QPS。文中详细介绍了avatorscript的使用方法,包括自定义函数、从Map中取值、使用Java工具类及AviatorScript函数等,帮助读者更好地理解和应用avatorscript。
利用java8 的 CompletableFuture 优化 Flink 程序
|
11天前
|
Java Maven 数据安全/隐私保护
如何实现Java打包程序的加密代码混淆,避免被反编译?
【10月更文挑战第15天】如何实现Java打包程序的加密代码混淆,避免被反编译?
23 2
|
13天前
|
安全 Java Linux
java程序设置开机自启
java程序设置开机自启
|
16天前
|
运维 Java Linux
【运维基础知识】Linux服务器下手写启停Java程序脚本start.sh stop.sh及详细说明
### 启动Java程序脚本 `start.sh` 此脚本用于启动一个Java程序,设置JVM字符集为GBK,最大堆内存为3000M,并将程序的日志输出到`output.log`文件中,同时在后台运行。 ### 停止Java程序脚本 `stop.sh` 此脚本用于停止指定名称的服务(如`QuoteServer`),通过查找并终止该服务的Java进程,输出操作结果以确认是否成功。
23 1
|
18天前
|
Java Python
如何通过Java程序调用python脚本
如何通过Java程序调用python脚本
13 0
|
数据库 Java NoSQL
那些年,我们见过的Java服务端乱象
导读查尔斯·狄更斯在《双城记》中写道:“这是一个最好的时代,也是一个最坏的时代。”移动互联网的快速发展,出现了许多新机遇,很多创业者伺机而动;随着行业竞争加剧,互联网红利逐渐消失,很多创业公司九死一生。
5703 5
|
算法 Java Serverless
那些年,我们见过的Java服务端乱象 | 8月6号云栖夜读
今天的首篇文章,讲述了:查尔斯·狄更斯在《双城记》中写道:“这是一个最好的时代,也是一个最坏的时代。”移动互联网的快速发展,出现了许多新机遇,很多创业者伺机而动;随着行业竞争加剧,互联网红利逐渐消失,很多创业公司九死一生。
3092 0
|
3天前
|
监控 安全 Java
在 Java 中使用线程池监控以及动态调整线程池时需要注意什么?
【10月更文挑战第22天】在进行线程池的监控和动态调整时,要综合考虑多方面的因素,谨慎操作,以确保线程池能够高效、稳定地运行,满足业务的需求。
71 38
|
5天前
|
Java 调度
[Java]线程生命周期与线程通信
本文详细探讨了线程生命周期与线程通信。文章首先分析了线程的五个基本状态及其转换过程,结合JDK1.8版本的特点进行了深入讲解。接着,通过多个实例介绍了线程通信的几种实现方式,包括使用`volatile`关键字、`Object`类的`wait()`和`notify()`方法、`CountDownLatch`、`ReentrantLock`结合`Condition`以及`LockSupport`等工具。全文旨在帮助读者理解线程管理的核心概念和技术细节。
18 1
[Java]线程生命周期与线程通信
|
2天前
|
安全 Java
在 Java 中使用实现 Runnable 接口的方式创建线程
【10月更文挑战第22天】通过以上内容的介绍,相信你已经对在 Java 中如何使用实现 Runnable 接口的方式创建线程有了更深入的了解。在实际应用中,需要根据具体的需求和场景,合理选择线程创建方式,并注意线程安全、同步、通信等相关问题,以确保程序的正确性和稳定性。