使用 chardet 检测带有 JDBC 的 MySQL 数据库中的错误编码

Posted

技术标签:

【中文标题】使用 chardet 检测带有 JDBC 的 MySQL 数据库中的错误编码【英文标题】:Using chardet to detect bad encoding in a MySQL db with JDBC 【发布时间】:2011-11-25 14:26:34 【问题描述】:

最近我们将 mysql 数据库从 Latin1 移到了 UTF8。在尝试了几种不同的方法来转换它之后,我们找不到任何不引入一些非常讨厌的数据丢失的方法(而且许多人根本什么也没做)。

这让我想知道我们是否有很多不同的编码正在进行,因为似乎没有一种方法可以涵盖我们的测试用例(我们数据库中的各种帖子)。为了验证这个理论,我写了一个小的 scala 应用程序(我的第一个,随意取笑它是多么的鹅卵石和非惯用语!:D),它使用 chardet 来查看帖子并告诉我编码。

只有一个问题,一切都是 UTF8。

代码如下:

package main.scala

import org.mozilla.universalchardet.UniversalDetector
import java.sql.DriverManager

object DBConvert 
  def main(args: Array[String]) 
    val detector = new UniversalDetector(null)
    val db_conn_str = "jdbc:mysql://localhost:3306/mt_pre?user=root"
    val connection = DriverManager.getConnection(db_conn_str)

    try 
        val statement = connection.createStatement()
        val rs = statement.executeQuery("SELECT * FROM mt_entry where entry_id = 3886")
        while (rs.next) 
           val buffer = rs.getBytes("entry_text_more")
           detector.handleData(buffer, 0, buffer.length)
           detector.dataEnd()

           val encoding:String = detector.getDetectedCharset;

           if (encoding != null) println("Detected encoding = " + encoding) else println("No encoding detected.");

           detector.reset();

           // Just so we can see the output
           println(rs.getString("entry_text_more"))
        
     catch 
      case _ => e: Exception => println(e.getMessage)
    
    finally 
        connection.close()
    
  

我尝试将 JDBC 查询字符串和字符编码传递给 useUnicode。他们都没有让 UTF-8 总是出现。还尝试使用 getBinaryStream 等,仍然是 UTF-8。

完全承认字符编码让我有点头疼,使用新语言可能不是解决这个问题的最佳方法。 :) 那就是说我很好奇 - 有没有办法从数据库中获取数据并检测它在那里的编码是什么,或者它只是因为它在数据库中被编码为 UTF-8 ,无论您如何检索它,这就是它的本来面目(有趣的角色和所有)?

谢谢!

【问题讨论】:

根据 character_set_connectioncharacter_set_database 的设置,MySQL 将尝试执行转换。如果您的数据有损坏的符号,我认为您需要提前知道处理该问题的源编码是什么。或者尝试将您的字段转换为BLOB 是的,这就是目前最棘手的部分。里面的一些数据是 UTF8,一些是 Latin1,天知道里面还有什么(这是一个相当古老的数据库,它附加了一些内容系统)。因此,当我尝试使用 blob 技术时,它可以很好地转换一些并截断其他一些。 :( 因此我试图先检测然后转换。似乎 JDBC 和 MySQL 之间商定的字符集是所有内容(这是有道理的,只是对我没有帮助。哈) 尝试cast(your_field as binary)。 MySQL 连接器应返回 byte[] 这确实改变了显示中的一些内容,但使用 getBytes 并没有改变。也就是说,做了更多的挖掘和切换字符检测库,似乎有些东西是其他编码,但损坏的总是 UTF-8(尽管在名称设置为 latin1 时正确显示)。也许是因为高 ascii 字符也是有效的 utf8 字符?至少现在我知道这不是数据库在做的。 我不了解 scala,但请看一下 ***.com/q/6824390/1290442 我是否通过更改 String text = fileData.toString(); 解决了类似的问题to String text = new String(fileData.toString().getBytes(), "KOI8_R");使用 Java。 【参考方案1】:

曾经我遇到过类似的问题。请参阅此answer。在连接字符串中设置编码可能会有所帮助。

【讨论】:

【参考方案2】:

请注意,表字符集和连接字符集以及默认数据库编码都是相同的 UTF-8。我有一个实例,其中数据库默认为 UTF-8 ,但表列仍然是拉丁语,所以我遇到了一些问题。请看看是不是这样。

【讨论】:

以上是关于使用 chardet 检测带有 JDBC 的 MySQL 数据库中的错误编码的主要内容,如果未能解决你的问题,请参考以下文章

使用chardet判断编码方式

编码格式检测chardet模块

利用chardet检测网页编码

Python爬虫教程-使用chardet

检测文件的格式——chardet模块

检测文件的格式——chardet模块