繁体   English   中英

Haskell中的编码和高效IO

[英]Encoding and efficient IO in Haskell

您好,对于将数据从String编码为ByteString以进行有效写入所需的所有Haskell模块,我有些困惑。

我不明白你怎么转换Data.ByteString.LazyData.ByteString.Char8 ,反之亦然。

我需要知道些什么? 因为我无法获得所有这些可能的用法组合.... Data.ByteStringData.ByteString.LazyData.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.TextTL.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字符串表示为StringText值。 但是,要从文件中读取或写入文件,需要将它们编码为字节序列或从字节序列中解码。

解决此问题的最简单方法是使用可自动处理编码和解码的Haskell函数。 您可能已经知道, Prelude中已经有两个函数可以直接读写字符串:

readFile :: FilePath -> IO String
writeFile :: FilePath -> String -> IO ()

此外, text中有readFilewriteFile函数可以执行此操作。 您可以在Data.Text.IOData.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

Char8模块

现在, Data.ByteString.Char8Data.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.EncodingData.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.ByteStringData.ByteString.Char8取决于您希望该字节字符串表示什么:字节序列或8位字符序列。 ByteString是一种数据结构,可用于存储字节序列(每种类型为Word8或8位字符序列(每种类型为Char 只有一种ByteString类型。

因为通常我们可能会处理二进制数据和基于字符的数据,所以如果将字节和字符的操作分别放在不同的模块中会很方便。 这样,当我们需要处理基于字符的数据时,只需使用Char8模块中的操作即可。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM