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