当我将它放入与将其从数据库中拉出时,new String(byte[]) 会给出不同的结果

Posted

技术标签:

【中文标题】当我将它放入与将其从数据库中拉出时,new String(byte[]) 会给出不同的结果【英文标题】:new String(byte[]) gives different results when I put it in vs pull it out of the database 【发布时间】:2013-02-12 19:09:07 【问题描述】:

在我将字节数组保存到数据库之前,如果我打印new String(data) 的输出,它会返回一个可读的字符串,例如“foobar”,但在我将它从数据库中拉出后,new String(data) 会读起来像一堆乱码比如“9238929384739427349327...”。这里有很多部分,我将尝试将它们全部列出。我正在使用 eclipselink 并且我的数据列已定义:

@Lob
@Column(name = "data")
private byte[] data;

如果我运行这段代码:

public static void main(String[] args) 
    System.out.println(Charset.defaultCharset());

它输出windows-1250

我的数据库定义为:

CREATE DATABASE project_trunk
  WITH OWNER = project
       ENCODING = 'UTF8'
       TABLESPACE = pg_default
       LC_COLLATE = 'English_United States.1252'
       LC_CTYPE = 'English_United States.1252'
       CONNECTION LIMIT = -1;

我也在这样定义的数据库上试过这个:

CREATE DATABASE project_trunk
  WITH OWNER = project
       ENCODING = 'UTF8'
       TABLESPACE = pg_default
       LC_COLLATE = 'en_US.UTF-8'
       LC_CTYPE = 'en_US.UTF-8'
       CONNECTION LIMIT = -1;

问题依旧存在。

我认为正在发生的事情是我的数据库与我的应用服务器的编码不同。当我将内容放入数据库并再次将其取出时,它以错误的方式对其进行解码,因此看起来像乱码。我有什么事情吗?

现在,当谈到解决这个问题时,我有点困惑。我认为我应该做的是将我的应用服务器的文件编码更改为与数据库相同。我正在使用 Glassfish 2.1.1。当我转到application server -> advanced -> domain attributes 并将语言环境设置为“UTF8”或“UTF-8”时,它告诉我需要重新启动。重新启动 glassfish 后,该字段仍为空白,并且仍然出现错误。我想也许它没有节省财产。我会手动将它放在配置文件中,但我不知道该放在哪里或放什么。

或者,我尝试使用 ENCODING = 'WIN1250' 创建我的数据库,但是当我这样做时,它说我的 LC_CTYPE 需要是“WIN1252”。当我将 LC_CTYPE 设置为“WIN1252”时,它说编码不存在。


我在这方面花了很多时间,我想知道我是否在这里做一些事情。我的“appserver 和 db 之间的编码不同步”的理论听起来是正确的,还是我在追逐红鲱鱼?如果有人可以帮助我弄清楚如何更改 glassfish 2.1.1 的此设置,那也将非常有帮助。谢谢

编辑:人们问我为什么将字符串存储为原始字节。这不完全是我正在做的事情,有时原始字节代表图像或pdf或二进制文件,有时是文本。我的 test 正在插入一个纯文本字符串并将其拉出以确保它被正确保存。该测试通过了我们在 linux 上的 CI 服务器。

EDIT2:我被要求显示原始二进制输入与原始二进制输出。

预期:[116, 104, 105, 115, 32, 105, 115, 32, 109, 121, 32, 97, 116, 116, 97, 99, 104, 109, 101, 110, 116, 32, 97、115、32、97、32、83、116、114、105、110、103]

实际:[60, 54, 56, 54, 57, 55, 51, 50, 48, 54, 57, 55, 51, 50, 48, 54, 100, 55, 57, 50, 48, 54, 49, 55, 52, 55, 52, 54, 49, 54, 51, 54, 56, 54, 100, 54, 53, 54, 101, 55, 52, 50, 48, 54, 49, 55, 51, 50、48、54、49、50、48、53、51、55、52、55、50、54、57、54、101、54、55]

我对使用 mac 的同事进行了同样的测试,检查字节,他通过了。

【问题讨论】:

使用 [String(byte[] bytes, Charset charset)](docs.oracle.com/javase/7/docs/api/java/lang/…, java.nio.charset.Charset)) 构造函数。 你的字节数组真的代表文本吗?如果是这样,您为什么将它放在byte[] 中?如果没有,您不应该使用String... 另外...为什么将Strings 存储为原始字节? @jlordo 我在我的代码new String(attachment.getData(), Charset.lookup("UTF8")) 中做了这个,它仍然打印出“87474703a2f2f6269742e6c792f617948363977”。 我已经编辑了底部以解释为什么我将字符串保存为字节数组。 【参考方案1】:

有时原始字节表示图像、pdf 或二进制文件,有时是文本

好的,那么您不应该将它们存储为文本。

不管当前出了什么问题,即使您可以让它对实际上文本的数据起作用,但您以后也会遇到问题。

如果您必须将任意二进制数据存储为文本,则应使用 base64 对其进行编码 - 这样您就可以毫无问题地返回原始二进制数据。 (您只需要能够传输 ASCII 字符串,这通常相当容易。)Base64 有很多第三方库。我喜欢this self-contained public domain one。

或者,将数据作为二进制数据存储在数据库中,例如使用bytea 数据类型的字段。这样你就不需要做任何转换工作:你应该能够将它作为一个字节数组放入数据库,然后将它作为一个字节数组取出。

编辑:好的,看起来您正在取回二进制数据的 hex 表示形式,但使用的是 ASCII。这显然很奇怪。

【讨论】:

对不起,我的沟通不太好。我没有将二进制文件存储为文本,而是将二进制文件存储为二进制文件。但是为了测试我输入的二进制文件是否与我取出的二进制文件相同,我在二进制数据上使用了new String(...)。当该字符串恰好是文本时,很明显它的出现方式不同。在 DB 中,它是一个 bytea,而在 JPA 中,它是一个 @Lob @tieTYT:根本不要将其转换为字符串。这只是使问题变得模糊(非常重要)。你为什么不在前后发布exact bytesArrays.toString(byte[]) 应该可以获取诊断数据。当您处理二进制数据时,您发布的有关语言环境和字符集的所有内容都应该完全无关紧要。 好的,我用这些信息编辑了我的问题。它们看起来有点遥远。 除此之外,我刚刚给使用 Mac 的同事做了同样的测试,测试通过了 @tieTYT:看起来您正在返回十六进制(输入的每个字节都作为输出的两个字节返回,解码为 ASCII 将是十六进制表示)。你能用一个简短但完整的程序重现这个吗?您的 Mac 同事是否使用相同的代码和所有库的相同版本?【参考方案2】:

事实证明,这是由于 PostgreSQL 在版本 9 和版本 8 中的工作方式造成的。我的大多数同事都使用版本 8,但我最近有了一台新计算机,所以我使用了最新的 PostgreSQL。

您需要将 output_bytea 设置为“escape”。

Getting nearly double the length when reading byte[] from postgres with jpa

虽然我没有找到足够的答案,但我在邮件列表中找到了这个并解决了我的问题:http://www.postgresql.org/message-id/AANLkTikkE-jQ9srZ9VL1JuJ5h=UCutx8ZLim+OfQ1T4z@mail.gmail.com

亲爱的名单,

最近在 9.0 中将 bytea_output 格式从转义更改为十六进制显然中断了 流行的持久会话处理 perl 模块,如 Apache::Session::Postgres 它将腌制数据结构存储在 db 表的 bytea 列中。 从抛出的异常中很难猜出根本原因 所述模块。 问题已通过添加解决 postgresql.conf 中的 bytea_output='escape' 并发出 pg_ctl reload。

例如,在 RT 应用程序中,错误是: 错误:RT 无法存储您的会话。 这可能意味着目录 /blah/blah/foo/bar 不是 可写或数据库表丢失或损坏

注册 拉杰什·库马尔·马拉。

【讨论】:

以上是关于当我将它放入与将其从数据库中拉出时,new String(byte[]) 会给出不同的结果的主要内容,如果未能解决你的问题,请参考以下文章

当我将我的 laravel 项目放入 xampp 时,我的登录不起作用

将 Unicode 字符插入 JavaScript

WCF 配置 - 将其从 app.config 中拆分出来

C# 类库 - 将图像构建操作更改为资源会将其从项目中删除

当我将它添加到我的 html 文档时,向上/向下投票系统不起作用

Ruby返回的HTTPVersionNotSupported对象