综合案例
- 概述
- 图解
- 基本实现
- 服务端实现
- 客户端实现
- 文件上传优化
- 上传分析
- 文件名写死的问题
- 循环接收的问题
- 效率问题
- 代码展示
- 回写分析
- 代码展示
概述
文件上传案例:
- 客户端输入流, 从硬盘读取文件数据到程序中
- 客户端输出流, 写出文件数据到服务端
- 服务端输入流, 读取文件数据到服务端程序
- 服务端输出流, 写出文件数据到服务器硬盘中
图解
基本实现
服务端实现
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();
}
}
}
回写分析
前四步与基本文件上传一致.
- 客户端输入流, 从硬盘读取文件数据到程序中
- 客户端输出流, 写出文件数据到服务端
- 服务端输入流, 读取文件数据到服务端程序
- 服务端输出流, 写出文件数据到服务器硬盘中
- 服务器输出流, 回写数据
- 客户端输入流, 解析回写数据
代码展示
服务端:
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();
}
}