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)))