我想要一些看起来像文件句柄但实际上由内存缓冲区支持的东西,用于 I/O 重定向。我怎样才能做到这一点?
6 回答
我刚刚编写了一个提供此功能的库,称为“knob”[ hackage ]。您可以使用它来创建Handle
引用/修改 a 的 s ByteString
:
import Data.ByteString (pack)
import Data.Knob
import System.IO
main = do
knob <- newKnob (pack [])
h <- newFileHandle knob "test.txt" WriteMode
hPutStrLn h "Hello world!"
hClose h
bytes <- Data.Knob.getContents knob
putStrLn ("Wrote bytes: " ++ show bytes)
如果您可以用 C 或系统调用来表达您想要做的事情,您可以使用 Haskell 的外部函数接口 (FFI)。我开始建议使用 mmap,但转念一想,我认为 mmap 可能是错误的映射方式,即使您将它与匿名选项一起使用也是如此。
您可以在 haskell.org wiki 上找到有关 Haskell FFI 的更多信息。
这实际上是库设计中的一个错误,也是一个让我恼火的错误。我看到了两种做你想做的事的方法,这两种方法都不是很有吸引力。
创建一个新的类型类,使当前句柄成为它的实例,编写另一个实例来执行内存中数据的事情,并更改所有需要使用此工具的程序。可能这就像导入
System.SIO
(或任何您想调用的名称)而不是System.IO
. 但是,如果您使用库中的自定义 I/O 例程,例如Data.ByteString
,还有更多工作要做。重写 I/O 库以扩展它们以支持这一点。不是微不足道的,而且工作量很大,但它不会是特别困难的工作。但是,您会遇到与没有此库的系统的兼容性问题。
这可能是不可能的。至少, GHC似乎需要一个句柄来拥有一个用于所有读/写/查找操作的 OS 文件描述符。
参见/libraries/base/IOBase.lhs
GHC 来源。
您可以通过获取操作系统的帮助来获得相同的效果:创建一个临时文件,将句柄连接到它,然后内存映射该文件以进行 I/O 重定向。这样,所有句柄 I/O 将在内存映射部分中变得可见。
要为这个问题添加现代答案,您可以使用createPipe
from System.Process
:
createPipe :: IO (Handle, Handle)
https://www.stackage.org/haddock/lts-10.3/process-1.6.1.0/System-Process.html#v:createPipe
不修改编译器是不可能的。这是因为 Handle 是一种抽象数据类型,而不是类型类。