Java中如何将ArrayList<Integer>转为字节数组再转成BLOB?
Java 中 ArrayList 转压缩BLOB存储数据库指南
核心思路
直接将数值序列化为字节数组(无需Base64,因为Base64会增加约33%的体积,不符合压缩存储的需求),然后用GZIP压缩,最后写入数据库BLOB字段;读取时反向操作即可。
步骤1:将 ArrayList 中的数值转为字节数组
处理 Integer 类型
import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; public static byte[] intListToBytes(ArrayList<Integer> intList) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); // 先写入元素个数,方便还原时读取 dos.writeInt(intList.size()); for (Integer num : intList) { dos.writeInt(num); } dos.close(); return baos.toByteArray(); }
处理 Double 类型
public static byte[] doubleListToBytes(ArrayList<Double> doubleList) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); dos.writeInt(doubleList.size()); for (Double num : doubleList) { dos.writeDouble(num); } dos.close(); return baos.toByteArray(); }
混合类型处理(同时有Integer和Double)
可以先写入类型标记,再写入对应数值:
public static byte[] mixedListToBytes(ArrayList<Number> mixedList) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dos = new DataOutputStream(baos); dos.writeInt(mixedList.size()); for (Number num : mixedList) { if (num instanceof Integer) { dos.writeByte(0); // 标记为Integer dos.writeInt(num.intValue()); } else if (num instanceof Double) { dos.writeByte(1); // 标记为Double dos.writeDouble(num.doubleValue()); } // 可扩展其他数值类型 } dos.close(); return baos.toByteArray(); }
步骤2:压缩字节数组
使用GZIP压缩减少体积:
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; public static byte[] compress(byte[] data) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); GZIPOutputStream gzipOut = new GZIPOutputStream(baos); gzipOut.write(data); gzipOut.close(); return baos.toByteArray(); } // 对应的解压方法 public static byte[] decompress(byte[] compressedData) throws IOException { ByteArrayInputStream bais = new ByteArrayInputStream(compressedData); GZIPInputStream gzipIn = new GZIPInputStream(bais); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len = gzipIn.read(buffer)) != -1) { baos.write(buffer, 0, len); } gzipIn.close(); return baos.toByteArray(); }
步骤3:存入数据库BLOB字段
JDBC操作示例:
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; public static void saveBlobToDb(Connection conn, byte[] compressedData, int monthId) throws SQLException { String sql = "INSERT INTO monthly_weather_stats (month_id, stats_blob) VALUES (?, ?)"; try (PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setInt(1, monthId); pstmt.setBytes(2, compressedData); pstmt.executeUpdate(); } }
步骤4:从BLOB读取并还原数据
以还原Integer列表为例:
import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; public static ArrayList<Integer> readIntListFromDb(Connection conn, int monthId) throws Exception { String sql = "SELECT stats_blob FROM monthly_weather_stats WHERE month_id = ?"; ArrayList<Integer> intList = new ArrayList<>(); try (PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setInt(1, monthId); try (ResultSet rs = pstmt.executeQuery()) { if (rs.next()) { byte[] compressedData = rs.getBytes("stats_blob"); byte[] rawData = decompress(compressedData); DataInputStream dis = new DataInputStream(new ByteArrayInputStream(rawData)); int size = dis.readInt(); for (int i = 0; i < size; i++) { intList.add(dis.readInt()); } dis.close(); } } } return intList; }
关键注意事项
- 避免Base64编码:Base64会将二进制转为文本,额外增加体积,BLOB字段直接存储字节数组即可。
- 序列化一致性:还原数据时必须和序列化时的顺序、类型严格对应,否则会出现数据错误。
- 异常处理:IO操作和数据库操作需妥善捕获异常,防止数据损坏或丢失。
- 性能考量:日常气象月度数据量不大,无需分块处理;若数据量极大,可考虑分块存储。
内容的提问来源于stack exchange,提问作者Palu
相关产品推荐
相关产品推荐

