Java网络通信Part3:文件的上传及优化

一、原理

【客户端】读取本地的文件 将文件上传到服务器
【服务器】再把上传的文件保存到服务器的硬盘上

1、客户端使用【本地字节输入流】 读取要上传的文件
2、客户端使用(网络字节输出流) 将读取到的文件上传到服务器
3、服务器使用(网络字节输入流) 读取客户端上传的文件
4、服务器使用【本地字节输出流】 将读取到的文件保存在服务器的硬盘上
5、服务器使用(网络字节输出流) 给客户端回写"上传成功"
6、客户端使用(网络字节输入流) 读取服务器回写的数据
7、释放数据

客户端和服务器对本地硬盘进行读写 使用自己创建的字节流对象(即本地流)
客户端和服务器二者之间进行读写 使用Socket中提供的字节流对象(即网络流)

二、文件上传案例

1、服务端

// 1、创建一个服务器ServiceSocket对象 向系统要指定的端口号
ServerSocket serverSocket=new ServerSocket(8888);

// 2、使用ServerSocket对象中的accept()方法 获取请求的客户端Socket对象
Socket socket=serverSocket.accept();

// 3、使用Socket对象中的getInputStream()方法 获取到网络字节输入流InputStream对象
InputStream inputStream=socket.getInputStream();

// 4、判断E:\\upload文件夹(目标文件夹)是否存在 若不存在则创建
File file=new File("E:\\upload");
if (!file.exists())
{
	// mkdirs()方法:可建立多级文件夹
    file.mkdirs();
}

// 5、创建一个本地字节输出流FileOutputStream对象 构造方法中绑定要输出的目的地
FileOutputStream fileOutputStream=new FileOutputStream(file+"\\test.jpg");

// 6、使用网络字节输入流InputStream对象中的read()方法 读取客户端上传的文件
int len=0;
byte[] bytes=new byte[1024];
while ((len=inputStream.read(bytes))!=-1)
{
	// 7、使用本地字节输出流FileOutStream对象中的write()方法 将读取到的文件上传到服务器的硬盘上
    fileOutputStream.write(bytes,0,len);
}

// 8、使用Socket对象中的getOutputStream()方法 获取网络字节输出流OutputStream对象
// 9、使用网络字节输出流OutputStream对象中的write()方法 给客户端回写"上传成功"语句
socket.getOutputStream().write("上传成功".getBytes());

// 10、释放资源
fileOutputStream.close();
socket.close();
serverSocket.close();

2、客户端

// 1、创建一个本地字节输出流FileInputStream对象 构造方法中绑定要读取的数据源
FileInputStream fileInputStream=new FileInputStream("D:\\test.jpg");

// 2、创建一个客户端Socket对象 构造方法中绑定服务器的IP地址和端口号
Socket socket=new Socket("192.168.36.56",8888);

// 3、使用Socket中的方法getOutputStream 获取网络字节输出流OutputStream对象
OutputStream outputStream=socket.getOutputStream();

// 4、使用本地字节输入流FileInputStre对象中的read()方法 读取本地的要上传的文件
int len=0;
byte[] bytes=new byte[1024];
while ((len=fileInputStream.read(bytes))!=-1)
{
	// 5、使用网络字节输出流OutputStream对象中的write()方法 将读取到的文件上传到服务器
    outputStream.write(bytes,0,len);
}

// 6、解决阻塞问题:上传完文件给服务器写一个结束标记
// void shutdownOutput() 禁用此套接字的输出流
// 对于TCP套接字 任何以前写入的数据都将被发送 并且之后会跟TCP的正常连接终止序列
socket.shutdownOutput();

// 7、使用Socket中的getInputStream()方法 读取网络字节输入流InputStream对象
InputStream inputStream=socket.getInputStream();
while ((len=inputStream.read(bytes))!=-1)
{
    System.out.println(new String(bytes,0,len));
}

// 8、释放资源
fileInputStream.close();
socket.close();

三、优化

1、文件名定死 再上传文件时原文件被覆盖的问题

自定义文件命名规则 防止同名文件被覆盖
规则:域名+毫秒值+随机数

String fileName="zjitc"+System.currentTimeMillis()+new Random().nextInt(99999)+".jpg";

FileOutputStream fileOutputStream=new FileOutputStream(file+"\\"+fileName);

2、上传一个文件就无法继续上传的问题

使服务器一直处于监听窗台(死循环accept()方法)
只要有一个客户端上传文件 就保存一个文件

while (true)
{
	// 使用ServerSocket对象中的accept()方法 获取请求的客户端Socket对象
    Socket socket=serverSocket.accept();

	......

	// 释放资源
    fileOutputStream.close();
    socket.close();
}

// 当服务器一直处于监听状态 此时 服务器就无需关闭了
// serverSocket.close();

3、上传速度过慢 效率过低的问题

使用多线程技术 提高程序效率
每当有一个客户端上传文件 就开启一个线程 以完成文件的上传
但由于实现Runnable接口 里面的代码无法抛出异常 因此只能try catch

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

    new Thread(new Runnable() {
	    @Override
	    public void run() {
	       try {
			// 使用ServerSocket对象中的accept()方法 获取请求的客户端Socket对象
			Socket socket=serverSocket.accept();
			
			......
	
			  // 释放资源
			  fileOutputStream.close();
		 	  socket.close();
		       }
		       catch (IOException e)
		       {
		           System.out.println(e);
		       }
	    }
    }).start();
}

发布了56 篇原创文章 · 获赞 0 · 访问量 1180

猜你喜欢

转载自blog.csdn.net/Piconjo/article/details/104621490