Nimでバイトオーダ(エンディアン)を意識してデータ読み書きする
概要
Nimでstreamsモジュールを使ってのデータ読み書きについてまとめる
バイトオーダ(エンディアン)を意識する必要がある
エンディアン - Wikipedia
WAVだとリトルエンディアンで数値データが格納されている
SMFだとビッグエンディアンで数値が格納されている
Nimでエンディアンを扱うにはendiansモジュールを使う
Nimのstream読み書きを調べてみた
streamsの読み書きのエンディアンを調べる
streamsモジュールには何のエンディアンでデータを読み書きするのか説明がない
調べた
数値の読み書きのエンディアン
Nimでは数値型についてはリトルエンディアンで読み書きを行う
code:little.nim
import streams
block:
var strm = newFileStream("9.dat", fmWrite)
strm.write(9'u32)
strm.close()
block:
var strm = newFileStream("9.dat", fmRead)
echo strm.readUint32()
strm.close()
このコードを実行した結果生成される9.datのバイナリを調べると以下のようになる
code:9.sh
$ xxd 9.dat
00000000: 0900 0000 ....
一番下位のバイトが先頭に来ている
これはリトルエンディアン
そしてreadUint32で取得した値を出力すると9が出力される
よってreadUint32もリトルエンディアンとしてデータを読み込んでいる
文字列の読み書きのエンディアン
Nimのstring型においてはビッグエンディアンで読み書きを行う
code:str.nim
import streams
block:
var strm = newFileStream("hello.dat", fmWrite)
strm.write("hello")
strm.close()
block:
var strm = newFileStream("hello.dat", fmRead)
echo strm.readStr(5)
strm.close()
このコードを実行した結果生成されるhello.datのバイナリを調べると以下のようになる
code:9.sh
$ xxd hello.dat
00000000: 6865 6c6c 6f hello
helloがhelloの順序のまま格納されている
これはビッグエンディアン
そしてreadStrで取得した値を出力するとhelloが出力される
よってreadStrはビッグエンディアンとして読み込む
数値をビッグエンディアンで読み取る
数値型はリトルエンディアンで読み取ることが分かった
数値型をビッグエンディアンで読み取るにはendiansモジュールを使う
以下のコードは、リトルエンディアンとして読み取ったデータをビッグエンディアンに直す
code:big.nim
import streams, endians
block:
var strm = newFileStream("big.dat", fmWrite)
strm.write(0'u8)
strm.write(0'u8)
strm.write(0'u8)
strm.write(9'u8)
strm.close()
block:
var strm = newFileStream("big.dat", fmRead)
var src = strm.readUint32()
echo "littleEndian32: " & $src
var dst: uint32
bigEndian32(addr(dst), addr(src))
echo "bigEndian32: " & $dst
strm.close()
code:result.txt
littleEndian32: 150994944
bigEndian32: 9
ビッグエンディアンで書き込んだデータをreadUint32で読み取ると当然9にならない
endiansで数値をビッグエンディアンに直す