Как я могу сохранить строковый байт без потери информации? - PullRequest
3 голосов
/ 05 ноября 2019

Я занимаюсь разработкой декодера JPEG (я нахожусь в фазе Хаффмана) и хочу записать BinaryString в файл. Например, предположим, у нас есть это:

String huff = "00010010100010101000100100";

Я пытался преобразовать его в целое число, разделив его на 8 и сохранив целочисленное представление, так как я не могу записать биты:

huff.split("(?<=\\G.{8})"))
int val = Integer.parseInt(str, 2);
out.write(val); //writes to a FileOutputStream

Проблема в том, что в моем примереесли я пытаюсь сохранить "00010010" , он преобразуется в 18 (10010), и мне нужны 0.

И, наконец,когда я прочитал:

int enter;
String code = "";
    while((enter =in.read())!=-1) {
            code+=Integer.toBinaryString(enter);
        }

я получил:

Code = 10010

вместо:

Code = 00010010

Также я попытался преобразовать его в набор битов, а затем вБайт [], но у меня та же проблема.

Ответы [ 2 ]

1 голос
/ 05 ноября 2019

Ваш пример: у вас есть строка "10010", и вам нужна строка "00010010". То есть вам нужно дополнить эту строку нулями слева. Обратите внимание, что, поскольку вы присоединяете результаты многих вызовов к Integer.toBinaryString в цикле, вам необходимо добавить эти строки в левый цикл внутри цикла, прежде чем объединять их.

while((enter = in.read()) != -1) {
    String binary = Integer.toBinaryString(enter);
    // left-pad to length 8
    binary = ("00000000" + binary).substring(binary.length());
    code += binary;
}
0 голосов
/ 05 ноября 2019

Возможно, вы захотите взглянуть на алгоритм UTF-8, поскольку он делает именно то, что вы хотите. Он хранит огромные объемы данных, отбрасывая нули, сохраняя соответствующие данные и кодируя их, чтобы занимать меньше места на диске.

Работает с: версия Java 7 +

import java.nio.charset.StandardCharsets;
import java.util.Formatter;

public class UTF8EncodeDecode {

    public static byte[] utf8encode(int codepoint) {
        return new String(new int[]{codepoint}, 0, 1).getBytes(StandardCharsets.UTF_8);
    }

    public static int utf8decode(byte[] bytes) {
        return new String(bytes, StandardCharsets.UTF_8).codePointAt(0);
    }

    public static void main(String[] args) {
        System.out.printf("%-7s %-43s %7s\t%s\t%7s%n",
                "Char", "Name", "Unicode", "UTF-8 encoded", "Decoded");

        for (int codepoint : new int[]{0x0041, 0x00F6, 0x0416, 0x20AC, 0x1D11E}) {
            byte[] encoded = utf8encode(codepoint);
            Formatter formatter = new Formatter();
            for (byte b : encoded) {
                formatter.format("%02X ", b);
            }
            String encodedHex = formatter.toString();
            int decoded = utf8decode(encoded);
            System.out.printf("%-7c %-43s U+%04X\t%-12s\tU+%04X%n",
                    codepoint, Character.getName(codepoint), codepoint, encodedHex, decoded);
        }
    }
}

https://rosettacode.org/wiki/UTF-8_encode_and_decode#Java

UTF-8 - кодировка символов переменной ширины, способная кодировать все 1112 064 [nb 1] действительных кодовых точек в Unicode, используя от одного до четырех 8-битных байтов. [Nb 2]Кодировка определяется стандартом Unicode и первоначально была разработана Кеном Томпсоном и Робом Пайком. [1] [2]Название происходит от формата преобразования Unicode (или универсального набора кодированных символов) - 8 бит. [3]

Он был разработан для обратной совместимости с ASCII. Кодовые точки с более низкими числовыми значениями, которые, как правило, встречаются чаще, кодируются с использованием меньшего количества байтов. Первые 128 символов Unicode, которые соответствуют один к одному с ASCII, кодируются с использованием одного байта с тем же двоичным значением, что и ASCII, так что действительный текст ASCII также является действительным Unicode в кодировке UTF-8. Поскольку байты ASCII не возникают при кодировании кодовых точек, отличных от ASCII, в UTF-8, UTF-8 безопасно использовать в большинстве языков программирования и документов, которые интерпретируют определенные символы ASCII особым образом, например, "/" (косая черта) вимена файлов, «\» (обратная косая черта) в escape-последовательностях и «%» в printf.

https://en.wikipedia.org/wiki/UTF-8

Двоичный 11110000 10010000 10001101 10001000 становится F0 90 8D 88 в UTF-8. Так как вы сохраняете его как текст, вы переходите от необходимости хранить 32 символа к хранению 8. И поскольку это хорошо известная и хорошо разработанная кодировка, вы можете легко изменить ее. Вся математика сделана для вас.

Ваш пример 00010010100010101000100100 (или, скорее, 00000001 0010100 0101010 00100100) преобразуется в *$ (два непечатаемых символа на моей машине). Это кодировка UTF-8 двоичного файла. Я по ошибке использовал другой сайт, который использовал данные, введенные в виде десятичного числа вместо двоичного.

https://onlineutf8tools.com/convert-binary-to-utf8

Для действительно хорошего объяснения UTF-8 и его примененияна ответ:

https://hackaday.com/2013/09/27/utf-8-the-most-elegant-hack/

...