Java中客户端-服务器架构导入CSV文件遇GUI冻结问题
客户端GUI冻结+CSV文件网络导入问题修复
问题背景
开发客户端-服务器架构的商城商品CSV导入功能时,客户端选择文件路径后出现GUI冻结,无法进行任何操作。当前客户端和服务端代码如下:
客户端原代码
public void importFromCSV(String path) { try { writer.write(path); writer.flush(); int bytes = 0; File file = new File(path); FileInputStream fis = new FileInputStream(path); // send file size dos.writeLong(file.length()); // break file into chunks byte[] buffer = new byte[4 * 1024]; while ((bytes = fis.read(buffer)) != -1) { dos.write(buffer, 0, bytes); dos.flush(); } fis.close(); } catch (Exception e) { e.printStackTrace(); } }
服务端原代码
public static void importCSV(Store store) { try { int bytes = 0; System.out.println("about to read path"); String path = reader.readLine(); System.out.println("read path"); FileOutputStream fos = new FileOutputStream(path); long size = dis.readLong(); // read file size byte[] buffer = new byte[4*1024]; while (size > 0 && (bytes = dis.read(buffer, 0, (int)Math.min(buffer.length, size))) != -1) { fos.write(buffer, 0, bytes); size -= bytes; // read upto file size } fos.close(); store.setProducts(CSVFileWork.CSVToProducts(path)); } catch (Exception e) { e.printStackTrace(); } System.out.println(store.getProducts().size()); }
核心问题分析
- GUI主线程阻塞:客户端的
importFromCSV方法直接在GUI线程执行,文件读取、网络传输都是同步阻塞操作,会卡住Swing/JavaFX的事件分发线程,导致界面冻结无响应。 - 传输协议不完整:客户端用
writer.write(path)发送路径后没有添加换行符,服务端reader.readLine()会一直等待换行标记,导致客户端和服务端互相阻塞,加重GUI冻结。 - 异常处理缺失:仅打印栈轨迹,没有中断错误流程或通知用户,问题发生后无法及时感知。
- 服务端安全风险:直接使用客户端传入的路径写入文件,存在路径遍历攻击风险,且未验证服务端路径是否存在。
修复方案
客户端修复要点
- 将文件读取和网络操作移至后台线程,避免阻塞GUI主线程;
- 发送路径后添加换行符,确保服务端能正确读取;
- 完善异常处理,通过弹窗提示用户导入状态;
- 关闭流时使用
try-with-resources自动管理,避免资源泄漏。
修复后的客户端代码:
// 使用SwingWorker在后台执行,适配Swing GUI场景 public void importFromCSV(String path) { new SwingWorker<Void, Void>() { @Override protected Void doInBackground() throws Exception { // 先验证文件有效性 File csvFile = new File(path); if (!csvFile.exists() || !csvFile.isFile()) { JOptionPane.showMessageDialog(null, "文件不存在或不是有效文件"); return null; } try (FileInputStream fis = new FileInputStream(csvFile); BufferedWriter bufferedWriter = new BufferedWriter(writer)) { // 发送路径时添加换行,让服务端readLine能正常读取 bufferedWriter.write(path); bufferedWriter.newLine(); bufferedWriter.flush(); // 发送文件大小 dos.writeLong(csvFile.length()); dos.flush(); byte[] buffer = new byte[4 * 1024]; int bytesRead; while ((bytesRead = fis.read(buffer)) != -1) { dos.write(buffer, 0, bytesRead); dos.flush(); } JOptionPane.showMessageDialog(null, "文件传输完成"); } catch (IOException e) { JOptionPane.showMessageDialog(null, "导入失败:" + e.getMessage()); e.printStackTrace(); } return null; } }.execute(); }
服务端修复要点
- 读取路径时处理可能的读取失败;
- 服务端指定固定存储目录,不要直接使用客户端传入的路径,避免安全风险;
- 验证传输的文件大小,确保接收完整;
- 同样使用
try-with-resources管理流资源; - 异常时输出明确错误信息,便于排查。
修复后的服务端代码:
// 服务端固定存储目录,避免路径遍历攻击 private static final String UPLOAD_DIR = "./server_uploads/"; public static void importCSV(Store store) { try { // 确保上传目录存在 File uploadDir = new File(UPLOAD_DIR); if (!uploadDir.exists()) { uploadDir.mkdirs(); } System.out.println("about to read path"); String clientPath = reader.readLine(); if (clientPath == null) { System.err.println("未读取到客户端路径"); return; } System.out.println("read path: " + clientPath); // 仅提取文件名,避免客户端传入恶意路径 String fileName = new File(clientPath).getName(); String serverFilePath = UPLOAD_DIR + fileName; try (FileOutputStream fos = new FileOutputStream(serverFilePath)) { long fileSize = dis.readLong(); byte[] buffer = new byte[4 * 1024]; long remainingSize = fileSize; int bytesRead; while (remainingSize > 0 && (bytesRead = dis.read(buffer, 0, (int) Math.min(buffer.length, remainingSize))) != -1) { fos.write(buffer, 0, bytesRead); remainingSize -= bytesRead; } if (remainingSize != 0) { System.err.println("文件传输不完整,预期大小:" + fileSize + ",实际接收:" + (fileSize - remainingSize)); return; } // 解析CSV商品数据 store.setProducts(CSVFileWork.CSVToProducts(serverFilePath)); System.out.println("导入完成,商品数量:" + store.getProducts().size()); } } catch (Exception e) { System.err.println("导入失败:" + e.getMessage()); e.printStackTrace(); } }
额外建议
- 客户端可以添加进度条,通过
SwingWorker的publish方法实时更新传输进度; - 服务端可以对上传的CSV文件做格式校验,避免解析错误;
- 网络传输可添加校验和机制,确保文件完整性。
内容的提问来源于stack exchange,提问作者Nathan428
相关产品推荐
相关产品推荐

