如何保存字符串字节而不丢失信息?

时间:2019-11-05 16:51:26

标签: java string int byte bitset

我正在开发JPEG解码器(我处于Huffman阶段),并且想将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

我也尝试将其转换为位集,然后转换为Byte [],但我遇到了同样的问题。

2 个答案:

答案 0 :(得分:1)

您的示例是您拥有字符串"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;
}

答案 1 :(得分:-2)

您可能想看看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是一种可变宽度的字符编码,它能够使用一到四个8位字节来编码Unicode中的所有1,112,064 [nb 1]个有效代码点。[nb 2]该编码是由Unicode标准定义的,最初由Ken Thompson和Rob Pike设计。[1] [2]该名称源自Unicode(或通用编码字符集)转换格式– 8位。[3]

     

它旨在与ASCII向后兼容。具有较低数值的代码点(通常会更频繁地出现)使用较少的字节进行编码。 Unicode的前128个字符(与ASCII一对一对应)使用与ASCII相同的二进制值的单个字节进行编码,因此有效的ASCII文本也是有效的UTF-8编码的Unicode。由于在将非ASCII代码点编码为UTF-8时不会出现ASCII字节,因此UTF-8可以安全地用于大多数以特殊方式解释某些ASCII字符的编程语言和文档语言,例如“ /”(斜杠)。文件名,转义序列中的“ \”(反斜杠)和printf中的“%”。

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

二进制数11110000 10010000 10001101 10001000在UTF-8中变成F0 90 8D 88。由于将其存储为文本,因此从必须存储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/

编辑:

我将这个问题作为减少存储值所需的字符数量的一种方法,这是一种编码方式。 UTF-8是一种编码。 OP以“非标准”方式使用,可以使用UTF-8以更短的格式编码其0和1的字符串。这就是答案的相关性。

如果将字符连接起来,则可以轻松地从4x 8位(32位)变为8x 8位(64位),并编码高达9,223,372,036,854,775,807的值。