文件上傳分析
- 【客戶端】輸入流,從硬盤讀取文件數據到程序中。
- 【客戶端】輸出流,寫出文件數據到服務端。
- 【服務端】輸入流,讀取文件數據到服務端程序。
- 【服務端】輸出流,寫出文件數據到服務器硬盤中。
基本實現
服務端實現
public class FileUpload_Server {public static void main(String[] args) throws IOException {System.out.println("服務器 啟動..... ");// 1. 創建服務端ServerSocketServerSocket serverSocket = new ServerSocket(6666);// 2. 建立連接 Socket accept = serverSocket.accept();// 3. 創建流對象// 3.1 獲取輸入流,讀取文件數據BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());// 3.2 創建輸出流,保存到本地 .BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.jpg"));// 4. 讀寫數據byte[] b = new byte[1024 * 8];int len;while ((len = bis.read(b)) != -1) {bos.write(b, 0, len);}//5. 關閉 資源bos.close();bis.close();accept.close();System.out.println("文件上傳已保存");}
}
客戶端實現
public class FileUPload_Client {public static void main(String[] args) throws IOException {// 1.創建流對象// 1.1 創建輸入流,讀取本地文件 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("test.jpg"));// 1.2 創建輸出流,寫到服務端 Socket socket = new Socket("localhost", 6666);BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());//2.寫出數據. byte[] b = new byte[1024 * 8];int len ; while ((len = bis.read(b)) != -1) {bos.write(b, 0, len);bos.flush();}System.out.println("文件發送完畢");// 3.釋放資源bos.close(); socket.close();bis.close(); System.out.println("文件上傳完畢 ");}
}
文件上傳優化
文件名稱寫死的問題
服務端保存文件的名稱如果寫死,最終導致服務器硬盤遇到相同文件名的文件時只會保留一個文件,建議使用系統時間優化,保證文件名稱唯一,代碼如下:
FileOutputStream fis = new FileOutputStream(System.currentTimeMillis()+".jpg") // 文件名稱
BufferedOutputStream bos = new BufferedOutputStream(fis);
// 自定義命名例如:域名+毫秒值+隨機數+文件后綴
循環接收的問題
服務端只保存一個文件就關閉了,之后用戶無法再上傳,這是不符合實際的,使用循環改進,可以不斷的接收不同用戶的文件,代碼如下:
// 每次接收新的連接,創建一個Socket
while(true){Socket accept = serverSocket.accept();// ......
}
效率問題
服務端在接收大文件時,可能耗費幾秒鐘的時間,此時不能接收其他用戶上傳,可以使用多線程技術優化,代碼如下:
while(true) {Socket accept = serverSocket.accept();// accept 交給子線程處理.new Thread(() -> {// ......InputStream bis = accept.getInputStream();// ......}).start();
}
最終實現
public class FileUpload_Server {public static void main(String[] args) throws IOException {System.out.println("服務器 啟動..... ");// 1. 創建服務端ServerSocketServerSocket serverSocket = new ServerSocket(6666);// 2. 循環接收,建立連接while (true) {Socket accept = serverSocket.accept();/* 3. socket對象交給子線程處理,進行讀寫操作Runnable接口中,只有一個run方法,使用lambda表達式簡化格式*/new Thread(() -> {try (//3.1 獲取輸入流對象BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());//3.2 創建輸出流對象, 保存到本地 .FileOutputStream fis = new FileOutputStream(System.currentTimeMillis() + ".jpg");BufferedOutputStream bos = new BufferedOutputStream(fis);) {// 3.3 讀寫數據byte[] b = new byte[1024 * 8];int len;while ((len = bis.read(b)) != -1) {bos.write(b, 0, len);}//4. 關閉 資源bos.close();bis.close();accept.close();System.out.println("文件上傳已保存");} catch (IOException e) {e.printStackTrace();}}).start();}}
}
信息回寫
前四步與基本文件上傳一致
- 【服務端】獲取輸出流,回寫數據。
- 【客戶端】獲取輸入流,解析回寫數據。
服務端實現
public class FileUpload_Server {public static void main(String[] args) throws IOException {System.out.println("服務器 啟動..... ");// 1. 創建服務端ServerSocketServerSocket serverSocket = new ServerSocket(6666);// 2. 循環接收,建立連接while (true) {Socket accept = serverSocket.accept();/*3. socket對象交給子線程處理,進行讀寫操作Runnable接口中,只有一個run方法,使用lambda表達式簡化格式*/new Thread(() -> {try (//3.1 獲取輸入流對象BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());//3.2 創建輸出流對象, 保存到本地 .FileOutputStream fis = new FileOutputStream(System.currentTimeMillis() + ".jpg");BufferedOutputStream bos = new BufferedOutputStream(fis);) {// 3.3 讀寫數據byte[] b = new byte[1024 * 8];int len;while ((len = bis.read(b)) != -1) {bos.write(b, 0, len);}// 4.=======信息回寫===========================System.out.println("back ........");OutputStream out = accept.getOutputStream();out.write("上傳成功".getBytes());out.close();//================================//5. 關閉 資源bos.close();bis.close();accept.close();System.out.println("文件上傳已保存");} catch (IOException e) {e.printStackTrace();}}).start();}}
}
客戶端實現
public class FileUpload_Client {public static void main(String[] args) throws IOException {// 1.創建流對象// 1.1 創建輸入流,讀取本地文件BufferedInputStream bis = new BufferedInputStream(new FileInputStream("test.jpg"));// 1.2 創建輸出流,寫到服務端Socket socket = new Socket("localhost", 6666);BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());//2.寫出數據.byte[] b = new byte[1024 * 8 ];int len ;while (( len = bis.read(b))!=-1) {bos.write(b, 0, len);}// 關閉輸出流,通知服務端,寫出數據完畢socket.shutdownOutput();System.out.println("文件發送完畢");// 3. =====解析回寫============InputStream in = socket.getInputStream();byte[] back = new byte[20];in.read(back);System.out.println(new String(back));in.close();// ============================// 4.釋放資源socket.close();bis.close();}
}