文章目录414. Java 文件操作基础 - 批量压缩与索引将154首十四行诗高效存储为带目录的二进制文件 写入所有 Sonnet 核心思路✅ 示例代码 代码解析 使用示例 总结414. Java 文件操作基础 - 批量压缩与索引将154首十四行诗高效存储为带目录的二进制文件 写入所有 Sonnet前面我们已经学会了如何压缩单个 Sonnet。但是莎士比亚总共有154 首 Sonnet我们需要把它们都写到一个二进制文件里方便后续统一存储和读取。问题是如果把所有 Sonnet 压缩后直接拼接到一个文件里后续怎么知道每一首的位置offset和长度length呢 答案是我们需要额外存储一个“目录表”告诉程序每首诗的起始位置和长度。 核心思路最终生成的文件结构如下-----------------------------------|Numberof sonnets(int)||Offset[0](int)||Length[0](int)||Offset[1](int)||Length[1](int)||...||Offset[n-1](int)||Length[n-1](int)|-----------------------------------|Compressedsonnets bytes array|-----------------------------------Number of sonnets→ 一共有多少首Offset, Length→ 每首 Sonnet 在压缩字节数组中的位置和大小Compressed data→ 154 首 Sonnet 的压缩内容 注意这里的 offset 是相对于压缩字节数组的起始位置不是整个文件开头。如果想让它相对于整个文件需要加上 header 的大小4 2*4*numberOfSonnets。✅ 示例代码intnumberOfSonnetssonnets.size();PathsonnetsFilePath.of(files/sonnets.bin);try(varsonnetFileFiles.newOutputStream(sonnetsFile);vardosnewDataOutputStream(sonnetFile)){ListIntegeroffsetsnewArrayList();ListIntegerlengthsnewArrayList();byte[]encodedSonnetsBytesArraynull;// 第一步压缩所有 Sonnet 并拼接到内存流try(ByteArrayOutputStreamencodedSonnetsnewByteArrayOutputStream()){for(Sonnetsonnet:sonnets){byte[]sonnetCompressedBytessonnet.getCompressedBytes();offsets.add(encodedSonnets.size());// 当前拼接流的大小就是下一个 Sonnet 的 offsetlengths.add(sonnetCompressedBytes.length);encodedSonnets.write(sonnetCompressedBytes);}// 第二步写入文件头dos.writeInt(numberOfSonnets);for(intindex0;indexnumberOfSonnets;index){dos.writeInt(offsets.get(index));dos.writeInt(lengths.get(index));}encodedSonnetsBytesArrayencodedSonnets.toByteArray();}// 第三步写入所有压缩内容sonnetFile.write(encodedSonnetsBytesArray);}catch(IOExceptione){e.printStackTrace();} 代码解析offsets.add(encodedSonnets.size())encodedSonnets.size()返回当前拼接流的长度也就是下一首 Sonnet 在字节数组中的起始位置。lengths.add(sonnetCompressedBytes.length)存储当前 Sonnet 的压缩字节数。dos.writeInt(numberOfSonnets)写入总数方便后续读取时知道有多少首。dos.writeInt(offsets.get(index)); dos.writeInt(lengths.get(index));按顺序写入 offset 和 length形成一个“索引表”。sonnetFile.write(encodedSonnetsBytesArray)最后把所有拼接好的字节流一次性写入文件。 使用示例运行代码后会在files/sonnets.bin生成一个二进制文件。它的结构大概是这样的[Header]154(总数)0120(第1首起始0,长度120字节)120130(第2首起始120,长度130字节)...[Body][GZIP压缩后的Sonnet字节内容...] 总结单个 Sonnet 压缩 →getCompressedBytes()所有 Sonnet 拼接 →ByteArrayOutputStream索引表写入 →DataOutputStream最终文件结构 Header Body这样我们就能高效存储所有 154 首 Sonnet既节省空间又能快速定位到任意一首诗。