Base64. Декодер, возвращающий иностранные символы

Я строю небольшое приложение, чтобы превратить текст в текстовом файле в 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();
    }



}

Текстовый файл перед шифрованием ():

сыр

помидоры

картофель

окороков

ямс

Текстовый файл после encrypt () // 5jAGgAZQBlAHMAZQANAAoAdABvAG0AYQB0AG8AZQBzAA0ACgBwAG8AdABhAHQAbwBlAHMADQAKAGgAYQBtAHMADQAKAHkAYQBtAHMA

Текстовый файл после расшифровки

뿯붿 сыр

помидоры

картофель

окороков

ямс

Перед шифрованием ():

После расшифровки ():

2 ответа

Ваши функции шифрования и дешифрования не делают одинаковых предположений. Шифрование Base64-кодирует любой файл, и это нормально, за исключением имен переменных и комментариев, которые предполагают, что файл является текстовым файлом. Это не должно быть.

decrypt преобразует данные в кодировке Base64 обратно в байты, но затем "перерабатывает", предполагая, что байты были кодированием текста с помощью UTF-8, затем декодирует и перекодирует их перед записью в файл. Если бы предположение было верным, это было бы просто NOP; Это явно не так в вашем случае, и это искажает данные.

Возможно, вы сделали это, потому что пытались использовать PrintWriter. В Java (и.NET) многопоточные и файловые классы ввода / вывода часто сбивают с толку - особенно учитывая их десятилетнюю эволюцию. Иногда есть тот, который делает именно то, что вам нужно, но это может быть трудно найти; в других случаях нет. И иногда широко используемая библиотека, такая как Apache Commons, заполняет пробел.

Итак, просто запишите байты в файл. Есть много современных и исторических вариантов, как объяснено в ответах на этот прямой вопрос byte[] для файла в Java. Вот один с Files.write:

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

Примечание. Хотя Base64, возможно, считался бы шифрованием (и взломанным) пару сотен лет назад, он не предназначен для этой цели. Это немного опасно (и запутанно) называть это так.

Ваш входной файл - UTF-16, а не UTF-8. Начинается с FF FEзнак порядка байтов с прямым порядком байтов. StandardCharsets.UTF_16 справится с этим правильно. (Или вместо этого установите ваш текстовый редактор на UTF-8 вместо UTF-16.)

Когда вы расшифровали fffe как UTF-8, у вас есть два символа замены "��"по одному на каждый из двух байтов, недопустимых в UTF-8. Затем, когда вы распечатали это, каждый символ замены '�' был закодирован как ef bf bd в UTF-8. Затем вы интерпретировали результат как UTF-16, взяв их в группы по два, прочитав его как efbf bdef bfbd, Остальная часть файла была UTF-16 все время, но нулевые байты будут безопасно в обоих направлениях.

(Если бы файл представлял собой текст ASCII, закодированный как UTF-16 без метки порядка байтов, вы бы не заметили, насколько это было нарушено!)

Другие вопросы по тегам