streams 模块是 Nim\lib\pure\streams.nim 文件,该模块提供了一个流接口和两个实现,一个是字符串流`StringStream`,一个是文件流`FileStream`。很显然字符串流是通过字符串来实现 stream接口的,文件流是通过 Nim中的”File" 对象来实现的。下面先看一个例子:
import streams
var
ss = newStringStream("""The first line
the second line
the third line""")
line = ""
while ss.readLine(line):
echo line
ss.close()
var fs = newFileStream("somefile.txt", fmRead) ##第二个参数是读文件的模式
if not isNil(fs):
while fs.readLine(line):
echo line
fs.close()
从streams 模块中也可以看出在 Nim 中怎么构造接口,怎么实现接口。如果看 streams 文件感觉乱的话,可以看我之前的一篇博文。里面简单的介绍了 Nim 中“接口” 的实现。 这个模块提供了很多操作流的过程,有读取也有写操作,其中基本上读取操作提供了两个相同功能的过程,这两个过程不同之处是一个读取数据后标记位会有相应的增加,一个不会增加。例如:
import streams
var
ss = newStringStream("""The first line
the second line
the third line""")
line = ""
echo ss.getPosition()
echo ss.readLine()
echo ss.getPosition()
echo ss.peekLine()
echo ss.getPosition()
ss.close()
这样的过程还有readChar、peekChar,readStr、peekStr 等等。
这里还有一个需要注意的是,过程readInt 系列。这里的readInt8、readInt16、readInt32等,读取的是相应字节数的位数,返回的是整型,读取多字节时,后读取的字节在高位。例如过程 readInt16() 读取字符串流 “10”, 返回的是12337。12337是 16位的二进制数。高8位是字符 ‘0’ 的二进制数,低8位是字符'1' 的二进制数。同样文件流也是这样读取的。
import streams
var
ss = newStringStream("0123456789")
fs = newFileStream(stdin)
x:int16
y:int16
x = ss.readInt16()
y = fs.readInt16()
echo "x = ", x
echo "y = ", y
那有人可能希望得到这样的效果:在终端输入10,得到的就是整型10。那么我想到的有两种方法,一种是读取字符串,再转换为整型。一种是通过C FFI (C 的外部接口函数)来实现,下面来看看怎么实现的。
转换字符串:
import streams,strutils
var
ss = newStringStream("0123456789")
fs = newFileStream(stdin)
x:int8
y:int16
x = int8(parseInt(ss.readStr(sizeof(x))))
y = int16(parseInt(fs.readStr(sizeof(int16))))
echo "x = ", x
echo "y = ", y
C FFI
# declare a C procedure..
proc unsafeScanf(f: File, s: cstring)
{.varargs,
importc: "fscanf",
header: "<stdio.h>".}
# ..and use it...
var x: cint
stdin.unsafeScanf("%d", addr x)
如果我们用过程 readInt 系列读取数据,有读取后的整型数据,想要知道原来的数字字符串怎么办呢。可以通过下面的程序来实现:
#这个程序是把使用标准输入文件流或字符串流读取的整型转换为原来的字符串。注意后读取的字符的二进制在高位。
import streams
proc StreamReadIntToString[T](strInt:T, size:int):string =
##strInt是从文件流读取的整型,stdin.readInt16()
##size是字节数
var
temp = strInt
judge = size
singleChar:char
singleInt:int
result = ""
while(judge > 0) :
judge = judge - 1
singleInt = temp shr ((size - 1)*8) #整型右移 (size-1)*8 位,剩余最高八位。
singleChar = char(singleInt) #把最高8位转换为char型
result = singleChar & result #小端在前,大端在后
if judge > 0:
temp = temp shl (8) #左移读取过的高8位
else:
return result
var
fs = newFileStream(stdin)
ss = newStringStream("0123456789")
strInt1:int32
strInt2:int32
strInt1 = fs.readInt32()
strInt2 = ss.readInt32()
echo "strInt1 = ",StreamReadIntToString(strInt1,sizeof(type(strInt1)))
echo "strInt2 = ",StreamReadIntToString(strInt2,sizeof(type(strInt1)))