ChatGPT解决这个技术问题 Extra ChatGPT

将字节数组转换为字符串(Java)

我正在 Google 应用引擎中编写一个网络应用程序。它允许人们基本上编辑作为 .html 文件存储在 blobstore 中的 html 代码。

我正在使用 fetchData 返回文件中所有字符的 byte[]。我正在尝试打印到 html 以便用户编辑 html 代码。一切都很好!

这是我现在唯一的问题:

字节数组在转换回字符串时存在一些问题。智能引号和几个字符看起来很时髦。 (?或日文符号等)具体来说,我看到的几个字节具有导致问题的负值。

智能引号在字节数组中返回为 -108-109。为什么会这样?如何解码负字节以显示正确的字符编码?

嗨,我知道这是一个非常古老的帖子,但我面临着类似的问题。我正在为 ssl 做一个中间人代理。我面临的问题和你的一样。我监听套接字并将数据输入 InputStream,然后输入 byte[]。现在,当我尝试将 byte[] 转换为字符串(我需要使用响应体进行攻击)时,我得到了非常有趣的字符,其中充满了智能引号和问号等等。我相信你的问题和我的一样,因为我们都在处理 byte[] 中的 html。你能请教吗?
顺便说一句,我使用 Sytem.properties 找到了我系统的编码,发现它是“Cp1252”。现在,我使用了 String str=new String(buffer, "Cp1252"); 但没有帮助。

n
nalply

字节数组包含特殊编码的字符(您应该知道)。将其转换为字符串的方法是:

String decoded = new String(bytes, "UTF-8");  // example for one encoding type

顺便说一下 - 原始字节可能会显示为负小数,因为 java 数据类型 byte 是有符号的,它涵盖了从 -128 到 127 的范围。

-109 = 0x93: Control Code "Set Transmit State"

值 (-109) 是 UNICODE 中不可打印的控制字符。因此 UTF-8 不是该字符流的正确编码。

“Windows-1252”中的 0x93 是您要查找的“智能引用”,因此该编码的 Java 名称是“Cp1252”。下一行提供了一个测试代码:

System.out.println(new String(new byte[]{-109}, "Cp1252")); 

我尝试使用 UTF-8,但它仍然以 ? 的形式出现。为什么没有找到那些负值的映射?
但是,0x93 是 UTF-8 中的有效延续字节 - 如果它没有出现在设置了前两位的字节之后,那么该字节的存在只会排除它是 UTF-8。
@Josh Andreas 解释了原因 - 因为 Java 的 byte 数据类型已签名。 “负”值只是具有最高有效字节集的字节。他还解释了您应该使用的最可能的字符集是 Windows-1252。不过,您应该知道从上下文或约定中使用什么字符集,而不必猜测。
d
davnicwil

Java 7 及以上

您还可以将所需的编码作为 StandardCharsets 中的 Charset 常量传递给 String 构造函数。正如其他答案中所建议的,这可能比将编码作为 String 传递更安全。

例如,对于 UTF-8 编码

String bytesAsString = new String(bytes, StandardCharsets.UTF_8);

这是2011年答案的重复。-1
@james.garriss 我不认为是这样,因为我只是提到了在 java 7 中引入的一个新构造函数,允许编码作为常量传递,我认为这比以前的 api 更好,更安全在前面的答案中提到,如果有的话,编码是作为字符串传递的。
F
Flexo

你可以试试这个。

String s = new String(bytearray);

您可以尝试...但几乎在所有情况下都会失败。
A
Adi Sembiring
public class Main {

    /**
     * Example method for converting a byte to a String.
     */
    public void convertByteToString() {

        byte b = 65;

        //Using the static toString method of the Byte class
        System.out.println(Byte.toString(b));

        //Using simple concatenation with an empty String
        System.out.println(b + "");

        //Creating a byte array and passing it to the String constructor
        System.out.println(new String(new byte[] {b}));

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        new Main().convertByteToString();
    }
}

输出

65
65
A

c
craig
public static String readFile(String fn)   throws IOException 
{
    File f = new File(fn);

    byte[] buffer = new byte[(int)f.length()];
    FileInputStream is = new FileInputStream(fn);
    is.read(buffer);
    is.close();

    return  new String(buffer, "UTF-8"); // use desired encoding
}

如果 read 引发异常,此代码将泄漏资源。
Q
Questioner

我建议Arrays.toString(byte_array);

这取决于你的目的。例如,我想保存一个字节数组,与您在调试时看到的格式完全相同:[1, 2, 3] 如果您想保存完全相同的值而不将字节转换为字符格式,Arrays.toString (byte_array) 可以这个,。但是如果你想保存字符而不是字节,你应该使用 String s = new String(byte_array)。在这种情况下,s 等价于字符格式的 [1, 2, 3]


你能提供更多关于你为什么建议这个的信息吗? (它会解决问题吗?你能说为什么它会解决它吗?)谢谢!
这取决于你的目的。例如,我想保存一个字节数组,就像您在调试时看到的格式一样: [1, 2, 3] 如果您想保存完全相同的值而不将字节转换为字符格式, Arrays.toString (byte_array) 就是这样做的。但是如果你想保存字符而不是字节,你应该使用 String s = new String(byte_array)。在这种情况下,s 等价于字符格式的 [1, 2, 3]。
@sas,您应该将此信息添加到您的答案本身(通过编辑它)而不是作为评论。一般来说,您应该始终记住,评论可能随时被删除——真正重要的信息应该在答案本身中。
S
Simon G.

Andreas_D 之前的回答很好。我只是要补充一点,无论您在哪里显示输出,都会有字体和字符编码,它可能不支持某些字符。

要确定是 Java 还是您的显示器有问题,请执行以下操作:

    for(int i=0;i<str.length();i++) {
        char ch = str.charAt(i);
        System.out.println(i+" : "+ch+" "+Integer.toHexString(ch)+((ch=='\ufffd') ? " Unknown character" : ""));
    }

Java 会将它无法理解的任何字符映射到 0xfffd 未知字符的官方字符。如果你看到一个“?”在输出中,但它没有映射到 0xfffd,这是您的显示字体或编码问题,而不是 Java。