客户端
文件上传案例的客户端:读取本地文件,上传到服务器,读取服务器回写的数据
明确:
数据源: 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)
public static void main(String[] args) throws IOException {
// 1,创建一个本地字节输入流FileInputstream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("/Users/xuxian/Documents/tx.jpg");
// 2·创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
Socket socket = new Socket("127.0.0.1", 8888);
// 3.使用Socket中的方法getOutputstream,获取网络字节输出流outputStream对象
OutputStream os = socket.getOutputStream();
// 4.使用本地字节输入流FileInputStream对象中的方法read,读取本地文件
int len = 0;
byte[] bytes = new byte[1024];
while ((len = fis.read(bytes)) != -1) {
/*
fis.read(bytes)读取本地文件,结束标记是读取到-1结束
while循环里会读取-1吗?不会那么也不会把结束标记写个服务器
解决:上传完文件,给服务器写一个结束标记
void shutdownoutput()禁用此套接字的输出流。
对于TCP套接字,任何以前写入的数据都将被发送,并且后跟TCP的正常连接终止序列。
*/
// 5·使用网络字节输出流OutputStream对象中的方法write,把读取到的文件上传到服务器
os.write(bytes, 0, len);
}
socket.shutdownOutput();
// 6·使用Socket中的方法getInputstream,获取网络字节输入流Inputstream对象
InputStream is = socket.getInputStream();
// 7·使用网络字节输入流Inputstream对象中的方法read读取服务回写的数据
while ((len = is.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len));
}
// 8.释放资源(FileInputStream, Socket)
fis.close();
socket.close();
}
服务器端
文件上传案例服务器端:读取客户端上传的文件,保存到服务器的硬盘,给客户端回写”上传成功
明确:
数据源:客户端上传的文件
目的地:服务器的硬盘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) {
/*
让服务器一直处于监听状态(死循环accept方法)有一个客户端上传文件,就保存一个文件
*/
while (true) {
/*
使用多线程技术,提高程序的效率
有一个客户端上传文件,就弃启一个线程,完成文件的上传
*/
new Thread(new Runnable() {
@Override
public void run() {
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”;