
java中用文本流(如filereader)读取huffman编码后的二进制文件会导致字节被错误转换为unicode替换字符u+fffd(对应字节0xfd,即二进制11111101),应改用字节流(fileinputstream)直接读取原始字节。
java中用文本流(如filereader)读取huffman编码后的二进制文件会导致字节被错误转换为unicode替换字符u+fffd(对应字节0xfd,即二进制11111101),应改用字节流(fileinputstream)直接读取原始字节。
Huffman编码生成的是原始二进制数据,而非可读文本——它可能包含任意字节值(0x00–0xFF),其中许多(如0x00、0x01、0xFF等)在UTF-8或平台默认编码下无法映射为合法字符。当你使用 FileReader + BufferedReader 时,Java会尝试将输入字节按字符编码(默认系统编码,通常是UTF-8)解码为 char;遇到非法或不可映射的字节序列时,JVM会静默插入 Unicode 替换字符 U+FFFD(其UTF-8编码为 0xEF 0xBF 0xBD,而单字节 0xFD 正是该字符在Latin-1等单字节编码下的“截断视图”——这正是你看到大量 11111101 的根本原因)。
✅ 正确做法:始终使用字节流处理二进制文件。以下是修复后的示例代码:
import java.io.*;
public class HuffmanBinaryReader {
public static void main(String[] args) throws IOException {
try (FileInputStream fis = new FileInputStream("encoded.bin");
BufferedInputStream bis = new BufferedInputStream(fis);
FileWriter fw = new FileWriter("out.txt");
BufferedWriter bw = new BufferedWriter(fw)) {
printRemainingBits(bis, bw);
}
}
static void printRemainingBits(BufferedInputStream bis, BufferedWriter bw) throws IOException {
System.out.println("\nRemaining Bytes (as bits):");
int b;
while ((b = bis.read()) != -1) {
printByteBits((byte) b);
bw.write(String.format("%s ", toBinaryString((byte) b)));
}
bw.newLine();
}
public static void printByteBits(byte b) {
for (int i = 7; i >= 0; i--) {
int bit = (b >> i) & 1;
System.out.print(bit);
}
System.out.print(" ");
}
public static String toBinaryString(byte b) {
return String.format("%8s", Integer.toBinaryString(b & 0xFF)).replace(' ', '0');
}
}
⚠️ 关键注意事项:
- 绝不使用 FileReader/BufferedReader 处理二进制数据:它们专为文本设计,强制字符解码会破坏原始字节。
- 关闭资源时优先使用 try-with-resources:确保 InputStream 和 OutputStream 正确释放。
- bis.read() 返回 int(0–255)而非 char:避免符号扩展问题;强制转为 byte 后再位运算更安全。
- 验证文件写入源头:确保Huffman编码器输出的是纯二进制(如用 FileOutputStream 写入),而非误用 Writer 类。
总结:Huffman压缩文件本质是二进制流,必须全程以字节为单位处理——从读取、解码到写入。混淆文本流与字节流是此类问题最常见根源。切换至 FileInputStream 后,你将看到真实的 10011011、11100110 等原始比特序列,而非被篡改的 11111101。











