SQLite数据库中的Unicode文本似乎已损坏

SQLite数据库中的Unicode文本似乎已损坏,sqlite,haskell,unicode,utf-8,Sqlite,Haskell,Unicode,Utf 8,我正在使用它绑定到SQLite数据库。在*.db文件中有UTF-8编码的文本,我可以在文本编辑器和sqlite CLI工具中保证这一点 连接到数据库并检索数据时,文本内容被破坏。简单的测试如下: import qualified Database.SQLite as SQL import Control.Applicative ((<$>)) import System.IO buildSkypeMessages dbh = (go <$> (SQL.execSt

我正在使用它绑定到SQLite数据库。在*.db文件中有UTF-8编码的文本,我可以在文本编辑器和sqlite CLI工具中保证这一点

连接到数据库并检索数据时,文本内容被破坏。简单的测试如下:

import qualified Database.SQLite as SQL
import Control.Applicative ((<$>))
import System.IO

buildSkypeMessages dbh = 
  (go <$> (SQL.execStatement dbh "select chatname,author,timestamp,body_xml from messages order by chatname, timestamp")) >>=
  writeIt
  where
    writeIt content = withFile "test.txt" WriteMode (\handle -> mapM_ (\(c:a:t:[]) -> hPutStrLn handle c) content)
    go (Left msg) = fail msg
    go (Right rows) = map f $ concat rows
      where
        f' (("chatname",SQL.Text chatname):
            ("author",SQL.Text author):
            ("timestamp",SQL.Int timestamp):
            r) = ([chatname, author], r)
        f xs = let (partEntry, (item:_)) = f' xs
               in case item of
                 ("body_xml",SQL.Text v) -> v:partEntry
                 ("body_xml",SQL.Null)   -> "":partEntry
        escape (_,SQL.Text v) = v
        escape (_,SQL.Null) = ""
        escape (_,SQL.Int v) = show v
将符合条件的Database.SQLite导入为SQL
导入控件。应用程序(())
导入系统.IO
buildSkypeMessages dbh=
(go(SQL.execStatement dbh“按聊天室名称、时间戳从消息顺序中选择聊天室名称、作者、时间戳、正文xml”)>>=
写
哪里
writeIt content=withFile“test.txt”WriteMode(\handle->mapM\(c:a:t:[])->hPutStrLn handle c)content)
go(左消息)=失败消息
go(右行)=地图f$concat行
哪里
f'(“chatname”,SQL.Text chatname):
(“作者”,SQL.Text作者):
(“时间戳”,SQL.Int时间戳):
r) =([chatname,author],r)
f xs=let(partEntry,(item:))=f'xs
如果项目
(“body_xml”,SQL.Text v)->v:partEntry
(“body_xml”,SQL.Null)->”:partEntry
转义(_,SQL.Text v)=v
转义(389;,SQL.Null)=“”
转义符(551;,SQL.Int v)=显示v

那里可能出了什么问题?我是缺少Sqlite还是缺少Haskell I/O和编码?

实际上,问题与Sqlite绑定无关,而是与Haskell中的字符串处理有关。解决问题的方法-在句柄上放置数据之前调用hSetBinaryMode:

writeIt content = withFile "test.txt" WriteMode (\handle -> hSetBinaryMode handle True >> mapM_ (\(c:a:t:[]) -> hPutStrLn handle c) content)

实际上,问题与SQLite绑定无关,而是与Haskell中的字符串处理有关。解决问题的方法-在句柄上放置数据之前调用hSetBinaryMode:

writeIt content = withFile "test.txt" WriteMode (\handle -> hSetBinaryMode handle True >> mapM_ (\(c:a:t:[]) -> hPutStrLn handle c) content)

一个可能出错的地方是写入文件:GHC将使用您当前的语言环境为该操作选择默认编码。您可以通过调用@DanielWagner来测试这是否是问题所在。我当前的语言环境是en_US.UTF-8,因此不应该是这样。文本文件中的数据看起来像双重编码的utf-8@DanielWagner设置二进制模式有帮助。谢谢在这种情况下,我怀疑您从SQL数据库中得到的不是
字符串
,而是错误地插入类型
字符串
的字节序列。在使用之前,您应该手动解码。我希望有人会给出一个答案:)一个可能出错的地方是写入文件:GHC将使用您当前的语言环境为该操作选择默认编码。您可以通过调用@DanielWagner来测试这是否是问题所在。我当前的语言环境是en_US.UTF-8,因此不应该是这样。文本文件中的数据看起来像双重编码的utf-8@DanielWagner设置二进制模式有帮助。谢谢在这种情况下,我怀疑您从SQL数据库中得到的不是
字符串
,而是错误地插入类型
字符串
的字节序列。你应该在使用它之前手动解码。我希望有人会给出答案:)