系列文章目录
前言
怎么从客户端上传一个文件到服务端
一、怎么做
(1)服务端
我们先假设只接收一个文件,不考虑多个
下面思考几个问题
从客户端发送文件到服务器端,服务端要做的事情
(1)接收客户端的连接
(2)接收文件名.后缀名
思考: 存哪里 ①在当前项目中找一个位置存储,例如:upload文件夹
如何解决文件名重名的问题 文件名需要处理,加入时间戳或其他的唯一编码的UUID等值
.后缀名需要保留,因为它代表文件的类型
(3)接收文件内容
(4)反馈结果
下面新建一个保存文件的地方
思考,要用什么流呢?
a、
这里既要接收文件名.后缀名,又要接收文件内容
这里既有 文本信息“文件名.后缀名”,又有其他类型的数据“文件内容”,只能选择字节流。
b、字节流如何区别,文件名.后缀名 与 文件内容呢?(我怎么知道你5个字节代表的是文件名还是10个字节代表的是后缀名)
想哪种字节输入流,可以处理字符串,和字节类型的数据。
FileInputStream、BufferedInputStream、DataInputStream、ObjectInputStream
这些里面可用的:DataInputStream:readUTF() 和 read(byte[])
ObjectInputStream也可以,但是麻烦,我这里选择DataInputStream
因为输出流是独立的,所以也要记得关闭
至此服务端就完成了
(2)客户端
从客户端发送文件到服务器端,客户端要做的事情
(1)从键盘输入文件的路径名,即选择要发送的文件
(2)给服务器先把“文件名.后缀名"
(3)发送文件内容
(4)接收服务器的反馈结果
这里同样因为既要发送“文件名.后缀名",又要发送“文件内容”,选择字节流,选择DataOutputStream
效果如下
二、多个客户端同时发送文件
跟上篇文章一样,只需要改服务器端
改成多线程即可
三、代码
服务端:
package com.atguigu.test14;
import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TestServer {
public static void main(String[] args) throws IOException {
//1、开启服务器
ServerSocket server = new ServerSocket(9999);
//2、接收客户端的连接
Socket socket = server.accept();
//3、获取输入流
InputStream in = socket.getInputStream();
DataInputStream dis = new DataInputStream(in);
//接收文件名.后缀名
String fileName = dis.readUTF();
//处理文件名
/*
* 希望我要在服务器存储的文件名: 原来的文件名 + 时间戳
*/
long timestamp = System.currentTimeMillis();
//.的下标
int index = fileName.lastIndexOf(".");
//后缀名
String ext = fileName.substring(index);
// 原来的文件名
String name = fileName.substring(0, index);
//新文件名
String newFileName = "upload/" + name + timestamp + ext;
//创建文件输出流,把接收到的文件内容,写入新文件
FileOutputStream fos = new FileOutputStream(newFileName);
//接收文件内容
byte[] data = new byte[1024];
int len;
while((len = dis.read(data))!=-1){
fos.write(data, 0, len);
}
//还可以给客户端反馈:文件接收完毕
OutputStream out = socket.getOutputStream();
PrintStream ps = new PrintStream(out);
ps.println("文件接收完毕!");
//断开
fos.close();
socket.close();
server.close();
}
}
客户端:
package com.atguigu.test14;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/*
* 从客户端发送文件到服务器端
*
*
* 客户端:
* (1)从键盘输入文件的路径名,即选择要发送的文件
* (2)给服务器先把“文件名.后缀名"
* (3)发送文件内容
* (4)接收服务器的反馈结果
*
* 这里同样因为既要发送“文件名.后缀名",又要发送“文件内容”,选择字节流,选择DataOutputStream
*
*/
public class TestClient {
public static void main(String[] args) throws UnknownHostException, IOException {
//1、连接服务器
Socket socket = new Socket("192.168.30.142",9999);
//2、从键盘输入文件的路径名,即选择要发送的文件
Scanner input = new Scanner(System.in);
System.out.print("请选择你要发送的文件(例如:D:/尚硅谷_190513班_柴林燕_JavaSE/开学典礼所发资料.rar):");
String fileName = input.nextLine();
File file = new File(fileName);
//3、给服务器发送“文件名.后缀名"
OutputStream out = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(out);
//发送“文件名.后缀名"
dos.writeUTF(file.getName());
//4、发送文件内容
//先从file文件读取内容
FileInputStream fis = new FileInputStream(file);
byte[] data = new byte[1024];
int len;
while((len = fis.read(data)) != -1){
//一边读,一边给服务器发送
dos.write(data,0,len);
}
socket.shutdownOutput();//表示发送完毕了
//5、接收反馈
InputStream in = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
String result = br.readLine();
System.out.println("结果:" + result);
//6、关闭
socket.close();
fis.close();
}
}
服务器端,多个客户端同时向服务器上传文件
(只需要改服务器端)
package com.atguigu.test15;
import java.io.DataInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
* 从客户端发送文件到服务器端
* (1)接收客户端的连接
* (2)接收文件名.后缀名
* 思考:
* 存哪里 ①在当前项目中找一个位置存储,例如:upload文件夹
* 如何解决文件名重名的问题 文件名需要处理,加入时间戳或其他的唯一编码的UUID等值
* .后缀名需要保留,因为它代表文件的类型
* (3)接收文件内容
* (4)反馈结果
*
* 思考:
* 这里既要接收文件名.后缀名,又要接收文件内容。
* 这里既有 文本信息“文件名.后缀名”,又有其他类型的数据“文件内容”,只能选择字节流。
*
* 如何区别,文件名.后缀名 与 文件内容呢
* 想哪种字节输入流,可以处理字符串,和字节类型的数据。
*
* FileInputStream
* BufferedInputStream
* DataInputStream
* ObjectInputStream
*
* 这些里面:DataInputStream:readUTF() 和 read(byte[])
* ObjectInputStream也可以,但是麻烦,我这里选择DataInputStream
*
* 加一个条件:同时多个客户端给服务器发送文件,客户端不用修改,服务器端加入多线程
*/
public class TestServer {
public static void main(String[] args) throws IOException {
//1、开启服务器
ServerSocket server = new ServerSocket(9999);
while(true){
//2、接收客户端的连接
Socket socket = server.accept();
FileUploadThread ft = new FileUploadThread(socket);
ft.start();
}
// server.close();//不关闭服务器
}
}
class FileUploadThread extends Thread{
private Socket socket;
public FileUploadThread(Socket socket) {
super();
this.socket = socket;
}
public void run(){
try {
//3、获取输入流
InputStream in = socket.getInputStream();
DataInputStream dis = new DataInputStream(in);
//接收文件名.后缀名
String fileName = dis.readUTF();
//处理文件名
/*
* 希望我要在服务器存储的文件名: 原来的文件名 + 时间戳
*/
long timestamp = System.currentTimeMillis();
//.的下标
int index = fileName.lastIndexOf(".");
//后缀名
String ext = fileName.substring(index);
// 原来的文件名
String name = fileName.substring(0, index);
//新文件名
String newFileName = "upload/" + name + timestamp + ext;
//创建文件输出流,把接收到的文件内容,写入新文件
FileOutputStream fos = new FileOutputStream(newFileName);
//接收文件内容
byte[] data = new byte[1024];
int len;
while((len = dis.read(data))!=-1){
fos.write(data, 0, len);
}
//还可以给客户端反馈:文件接收完毕
OutputStream out = socket.getOutputStream();
PrintStream ps = new PrintStream(out);
ps.println("文件接收完毕!");
//断开
fos.close();
socket.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}