如何从MySQL Blob恢复存入的ArrayList<String>?读取时遇文件未找到异常
问题分析与解决方案
你遇到的FileNotFoundException核心原因是你存入数据库的并不是ArrayList的序列化数据,而是File对象本身——File对象序列化后仅保存了文件的路径信息,完全不包含文件里的内容。再加上你设置了tempFile.deleteOnExit(),当JVM退出后临时文件会被自动删除,后续读取时自然找不到这个路径对应的文件了。
错误点拆解
- 写入环节:
preparedStatement.setObject(1, tempFile)执行的是对File对象的序列化,存入Blob的只是文件路径字符串,不是myList的序列化数据。 - 读取环节:你读出来的是之前序列化的
File对象,但这个文件已经被删除(或者在不同运行环境中根本不存在),打开它时自然会抛出找不到文件的异常。
修正方案:直接序列化ArrayList到Blob(跳过无效的临时文件中转)
方案1:跳过临时文件,直接序列化ArrayList到字节数组存入Blob
这是最高效的方式,不需要临时文件做中转:
写入代码
ArrayList<String> myList = new ArrayList<>(); // 直接将ArrayList序列化到字节数组 ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { oos.writeUnshared(myList); oos.flush(); byte[] listBytes = baos.toByteArray(); // 存入数据库Blob列 String insertQuery = "INSERT INTO table (tempFile) VALUES (?)"; try (PreparedStatement pstmt = connection.prepareStatement(insertQuery)) { pstmt.setBytes(1, listBytes); pstmt.executeUpdate(); } } catch (IOException | SQLException e) { e.printStackTrace(); }
读取代码
String selectQuery = "SELECT tempFile FROM table WHERE ..."; // 补充你的查询条件 try (PreparedStatement pstmt = connection.prepareStatement(selectQuery); ResultSet rs = pstmt.executeQuery()) { if (rs.next()) { // 从Blob中读取字节数组,直接反序列化为ArrayList byte[] listBytes = rs.getBytes("tempFile"); try (ByteArrayInputStream bais = new ByteArrayInputStream(listBytes); ObjectInputStream ois = new ObjectInputStream(bais)) { ArrayList<String> myList = (ArrayList<String>) ois.readObject(); System.out.println(myList.size()); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } catch (SQLException | IOException e) { e.printStackTrace(); }
方案2:若必须用临时文件,需读取文件内容存入Blob
如果你因为某些原因必须保留临时文件步骤,那要把文件里的序列化数据读出来存入Blob,而不是存File对象:
修正后的写入代码
ArrayList<String> myList = new ArrayList<>(); File tempFile = File.createTempFile("myFile", ".temp"); tempFile.deleteOnExit(); // 将ArrayList写入临时文件 try (FileOutputStream fos = new FileOutputStream(tempFile); ObjectOutputStream oos = new ObjectOutputStream(fos)) { oos.writeUnshared(myList); } // 读取临时文件的内容为字节数组 byte[] fileContent = Files.readAllBytes(tempFile.toPath()); // 存入数据库 String insertQuery = "INSERT INTO table (tempFile) VALUES (?)"; try (PreparedStatement pstmt = connection.prepareStatement(insertQuery)) { pstmt.setBytes(1, fileContent); pstmt.executeUpdate(); } catch (IOException | SQLException e) { e.printStackTrace(); }
读取代码和方案1一致,直接从Blob字节数组反序列化即可,无需再操作File对象。
关键注意事项
- 确保
ArrayList里的元素(这里是String)都是可序列化的(String本身已经实现Serializable接口,所以没问题)。 - 序列化和反序列化的类结构要完全一致,否则会抛出
ClassNotFoundException或InvalidClassException。
内容的提问来源于stack exchange,提问作者user3202153
相关产品推荐
相关产品推荐

