Base64.Decoder 返回外来字符

问题描述 投票:0回答:2

我正在构建一个小型应用程序,将文本文件中的文本转换为 Base64,然后恢复正常。解码后的文本总是在第一行的开头返回一些汉字。

public EncryptionEngine(File appFile){
    this.appFile= appFile;
}


public void encrypt(){

    try {
        byte[] fileText = Files.readAllBytes(appFile.toPath());// get file text as bytes

        Base64.Encoder encoder = Base64.getEncoder();
        PrintWriter writer = new PrintWriter(appFile);

        writer.print("");//erase old, readable text
        writer.print(encoder.encodeToString(fileText));// insert encoded text
        writer.close();


    } catch (IOException e) {

        e.printStackTrace();
    }

}

public void deycrpt(){

    try {
        byte[] fileText = Files.readAllBytes(appFile.toPath());

        String s = new String (fileText, StandardCharsets.UTF_8);//String s = new String (fileText);


        Base64.Decoder decoder = Base64.getDecoder();
        byte[] decodedByteArray = decoder.decode(s);

        PrintWriter writer = new PrintWriter(appFile);
        writer.print("");
        writer.print(new String (decodedByteArray,StandardCharsets.UTF_8)); //writer.print(new String (decodedByteArray));
        writer.close();


    } catch (IOException e) {

        e.printStackTrace();
    }



}

加密之前的文本文件():

奶酪

西红柿

土豆

火腿

山药

加密后的文本文件() //5jAGgAZQBlAHMAZQANAAoAdABvAG0AYQB0AG8AZQBzAA0ACgBwAG8AdABhAHQAbwBlAHMADQAKAGgAYQBtAHMADQAKAHkaYQBtAHMA

解密后的文本文件

뿯붿奶酪

西红柿

土豆

火腿

山药

Before encrypt() :

After decrypt() :

java utf-8 decoder
2个回答
1
投票

您的输入文件是 UTF-16,而不是 UTF-8。它以

FF FE
开头,即小端字节顺序标记。
StandardCharsets.UTF_16
将正确处理这个问题。 (或者,将文本编辑器设置为 UTF-8 而不是 UTF-16。)

当您将

fffe
解码为 UTF-8 时,您会得到两个替换字符
"��"
,每个字符对应 UTF-8 中无效的两个字节。然后,当您打印出来时,每个替换字符
'�'
都被编码为 UTF-8 中的
ef bf bd
。然后,您将结果解释为 UTF-16,将它们分成两个组,将其读作
efbf bdef bfbd
。文件的其余部分始终是 UTF-16,但空字节将安全地往返。

(如果文件是 UTF-16 的 ascii 文本编码,没有字节顺序标记,你不会注意到这是多么糟糕!)


1
投票

您的加密和解密函数不会做出相同的假设。 encrypt Base64 对任何文件进行编码,除了表明该文件是文本文件的变量名称和注释之外,都很好。不一定是这样。

decrypt 将 Base64 编码的数据反转回字节,但随后通过假设字节是使用 UTF-8 进行文本编码、然后解码并在将它们写入文件之前重新编码来“过度处理”。如果假设成立,那么它只是一个 NOP;对于您的情况来说,这显然是不正确的,并且它会破坏数据。

也许您这样做是因为您尝试使用 PrintWriter。在 Java(和 .NET)中,多个流和文件 I/O 类常常令人困惑,特别是考虑到它们长达数十年的演变。有时,有一个产品可以满足您的需求,但可能很难找到;其他时候则没有。有时,像 Apache Commons 这样的常用库可以填补这个空白。

因此,只需将字节写入文件即可。正如这个直接问题byte[] to file in Java 的答案中所解释的,有许多现代和历史选项。这是一个带有 Files.write:

Files.write(appFile.toPath(), decodedByteArray, StandardOpenOption.CREATE);

注意:虽然 Base64 在几百年前可能被认为是加密(并被破解),但它并不是用于此目的。这样称呼它有点危险(并且令人困惑)。

© www.soinside.com 2019 - 2024. All rights reserved.