[英]Encoding and efficient IO in Haskell
您好,对于将数据从String
编码为ByteString
以进行有效写入所需的所有Haskell模块,我有些困惑。
我不明白你怎么转换Data.ByteString.Lazy
到Data.ByteString.Char8
,反之亦然。
我需要知道些什么? 因为我无法获得所有这些可能的用法组合.... Data.ByteString
, Data.ByteString.Lazy
, Data.ByteString.Char8
,所以有Data.Text
.....我需要什么来编写字符串轻松有效地保存到文件,反之亦然? (使用正确的编码)
PS目前正在阅读Real World Haskell,我对所有这些模块都感到困惑。
这是路线图的镜头。
您可能已经知道,Haskell String
类型只是[Char]
的类型同义词,其中Char
是可以表示单个Unicode代码点的数据类型。 这使String
成为表示文本数据的理想数据类型,除了较小的问题(作为盒装Char
值的链接列表)外,它还有可能效率极低。
来自text
包的Text
数据类型解决了此问题。 Text
也像String
一样,表示Char
值列表,但不是使用实际的Haskell列表,而是使用节省时间和空间的表示形式。 每当您需要有效处理文本(Unicode)数据时,它都应该成为String
首选替代品。
像标准Haskell库中的许多其他数据类型一样,它具有惰性和严格的变体形式。 两种变体的名称都为Text
,但它们包含在单独的模块中,因此您可以这样做:
import qualified Data.Text as TS
import qualified Data.Text.Lazy as TL
如果需要在同一程序中同时使用TS.Text
和TL.Text
变体。
变量之间的确切区别在Data.Text文档中进行了描述 。 简而言之,您应该默认使用严格版本。 在两种情况下,仅使用惰性版本。 首先,如果您打算一次处理一个较大的Text
值,将其更像是文本“流”而不是“字符串”,那么惰性版本是一个不错的选择。 (例如,读取大型CSV文件的程序可能会将文件读取为长时间的惰性Text
流,并将结果存储在有效的数字类型中,例如未装箱的Double
值的Vector
,以避免将整个输入文本保留在内存中。 )其次,如果您要用许多小片段构建一个大的Text
字符串,那么您就不想使用严格的版本,因为它们的不变性意味着每次添加内容时都需要复制它们。 相反,您想将lazy变体与Data.Text.Lazy.Builder
函数Data.Text.Lazy.Builder
。
另一方面, bytestring
包中的ByteString
数据类型是bytestring
列表的有效表示形式。 就像Text
是[Char]
的有效版本一样,您应该将ByteString
视为[Word8]
的有效版本,其中Word8
是Haskell类型,代表单个值为0-255的数据的无符号字节。 等效地,您可以将ByteString
视为代表要从文件读取或写入文件的内存块或数据块,就一个字节一个字节而言。 它也有懒惰和严格的口味:
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BL
并且使用变体的注意事项与Text
的注意事项相似。
在Haskell程序中,通常将内部的Unicode字符串表示为String
或Text
值。 但是,要从文件中读取或写入文件,需要将它们编码为字节序列或从字节序列中解码。
解决此问题的最简单方法是使用可自动处理编码和解码的Haskell函数。 您可能已经知道, Prelude
中已经有两个函数可以直接读写字符串:
readFile :: FilePath -> IO String
writeFile :: FilePath -> String -> IO ()
此外, text
中有readFile
和writeFile
函数可以执行此操作。 您可以在Data.Text.IO
和Data.Text.Lazy.IO
找到版本。 它们似乎具有相同的签名,但是一个在严格的Text
类型上运行,另一个在懒惰的Text
类型上运行:
readFile :: FilePath -> IO Text
writeFile :: FilePath -> Text -> IO ()
您可以告诉这些函数自动执行编码和解码,因为它们返回并接受Text
值,而不是ByteString
值。 使用的默认编码将取决于操作系统及其配置。 在典型的现代Linux发行版中,它将是UTF-8。
或者,您可以使用bytestring
包中的函数(还是懒惰版本或严格版本,具体取决于模块)从文件读取或写入原始字节:
readFile :: FilePath -> IO ByteString
writeFile :: FilePath -> ByteString -> IO ()
这些具有与text
版本相同的名称,但是您可以看到它们正在处理原始字节,因为它们返回并接受ByteString
参数。 在这种情况下,如果要将这些ByteString
用作文本数据,则需要自己对其进行解码或编码。 例如,如果ByteString
表示文本的UTF-8编码版本,那么您正在寻找的是Data.Text.Encoding
(对于严格版本)或Data.Text.Lazy.Encoding
(对于惰性版本)中的这些函数。 :
decodeUtf8 :: ByteString -> Text
encodeUtf8 :: Text -> ByteString
现在, Data.ByteString.Char8
和Data.ByteString.Lazy.Char8
中的模块是特例。 当使用几种“保留ASCII”编码方案(包括ASCII本身,Latin-1和其他Latin-x编码以及UTF-8)之一对纯ASCII文本进行编码时,事实证明,已编码的ByteString
只是简单的Unicode代码的每个字符一个字节的编码指向0到127。一般来说,当文本以Latin-1编码时,编码后的ByteString
只是Unicode代码点的一个简单的每个字符一个字节编码0到255。在这些情况下,并且仅在这些情况下,可以安全地使用这些模块中的功能来绕过显式的编码和解码步骤,而直接通过自动转换直接将字节字符串视为ASCII和/或Latin-1文本单字节来对Char
值进行Unicode Char
并返回。
因为这些功能仅在特殊情况下起作用,所以通常应避免在专门的应用程序中使用它们。
而且,正如评论中提到的那样,这些Char8
模块中的ByteString
变体与普通的strict和lazy ByteString
变体没有任何不同。 这些模块中的函数将它们视为是Char
值的字符串而不是Word8
值的字符串-数据类型相同,只是函数接口不同。
所以,如果你正在使用纯文本和您的操作系统的默认编码工作,只需要用严格的Text
从数据类型Data.Text
从(高效)的IO功能Data.Text.IO
。 您可以使用惰性变体进行流处理或从小片段构建大字符串,还可以使用Data.Text.Read
进行一些简单的解析。
在大多数情况下,您应该可以避免使用String
,但是如果发现需要来回转换,则Data.Text
(或Data.Text.Lazy
)中的这些转换函数将非常有用:
pack :: String -> Text
unpack :: Text -> String
如果您需要对编码进行更多控制,则仍要在整个程序中使用Text
,但在读取或写入文件的“边缘”处除外。 在那些边缘,使用来自I / O功能Data.ByteString
(或Data.ByteString.Lazy
),和编码/解码功能从Data.Text.Encoding
或Data.Text.Lazy.Encoding
。
如果发现需要混合严格变型和惰性变型,请注意Data.Text.Lazy
包含:
toStrict :: TL.Text -> TS.Text -- convert lazy to strict
fromStrict :: TS.Text -> TL.Text -- vice versa
和Data.ByteString.Lazy
包含ByteString
值的相应函数:
toStrict :: BL.ByteString -> BS.ByteString
fromStrict :: BS.ByteString -> BL.ByteString
这取决于您要处理的数据类型以及计划如何处理这些数据。
如果你正在处理Unicode字符串,用Text
从文本包。
如果您不需要一次将所有数据读入内存,请使用该模块的Lazy
版本。 否则,整个数据将被加载到单个数据结构中。
何时使用Data.ByteString
或Data.ByteString.Char8
取决于您希望该字节字符串表示什么:字节序列或8位字符序列。 ByteString
是一种数据结构,可用于存储字节序列(每种类型为Word8
或8位字符序列(每种类型为Char
。 只有一种ByteString
类型。
因为通常我们可能会处理二进制数据和基于字符的数据,所以如果将字节和字符的操作分别放在不同的模块中会很方便。 这样,当我们需要处理基于字符的数据时,只需使用Char8模块中的操作即可。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.