UWSCでバイナリーファイルの読み書き

ADODB.Streamを使えば、バイナリーファイルの読み書きももちろん可能。
バイナリーが使えない、という記述を見たのでやってみた。




メイン部分に書いた、テスト用スクリプトで使い方は分かるでしょうけど、
読み書きは1オクテット単位(0〜255)でしか考えていません。
あと、Binary.Initの引数で、同時に扱うファイル数が指定できます。
初期値は、32。否、33だった。
-1とか指定する人は知りません。
スレッドで多重アクセスも知ったことではありません。
どちらもチェックを追加すれば良い話ではありますが。


Binary.uws

OPTION EXPLICIT


IFB GET_UWSC_NAME = "Binary.uws" THEN
	WITH Binary
		DIM path = "Binary.test.dat"
		// 書き込み
		DIM h = .Open(path), i
		IFB h <> .INVALID_HANDLE THEN
			// 単体書き込み
			FOR i = 255 TO 0 STEP -1
				.Write(h, i)
			NEXT
			// 配列書き込み
			DIM add[] = 13, 10, 48
			.WriteArray(h, add)
			// 最後のバイトを上書き
			.Position(h, -1)
			.Write(h, 49)
		ENDIF
		.Close(h, TRUE)

		// 読み込み
		h = .Open(path)
		IFB h <> .INVALID_HANDLE AND .Exist(h) THEN
			WHILE !.EOS(h)
				PRINT .Position(h) + ": " + .Read(h)
			WEND
			// 後ろ3バイトカットしてみる
			.Position(h, -3)
			.EOS(h, TRUE)
		ENDIF
		.Close(h, TRUE)

		// 読み込み一括
		h = .Open(path)
		IFB h <> .INVALID_HANDLE AND .Exist(h) THEN
			DIM read = .ReadArray(h), m = .Size(h) - 1
			.Close(h)	// 既に読み込み済みなのでClose可
			FOR i = 0 TO m
				PRINT read[i]
			NEXT
		ENDIF
		.Close(h)	// 二回Closeしても、問題はない
	ENDWITH
ENDIF


MODULE Binary
	CONST MAX = 32

	CONST BINARY = 1
	CONST TEXT = 2

	CONST INVALID_HANDLE = -1

	CONST ALL = -1
	CONST LINE = -2

	CONST CREATENEW = 1
	CONST OVERWRITE = 2

	DIM _max = MAX
	DIM _adodb[MAX]
	DIM _box[MAX]
	DIM _path[MAX]
	DIM _exist[MAX]

	PROCEDURE Binary()
		Init()
	FEND

	PROCEDURE Init(m=MAX)
		RESIZE(_adodb, m)
		RESIZE(_box, m)
		RESIZE(_path, m)
		RESIZE(_exist, m)
		// ADODB.Streamを作成し、書き込み用・バリアント配列の箱を確保する
		_adodb[0] = CREATEOLEOBJ("ADODB.Stream")
		WITH _adodb[0]
			.Open()
			.Type = TEXT
			.WriteText(CHR(0))
			.Position = 0
			.Type = BINARY
			_box[0] = .Read(1)
			.Close()
		ENDWITH
		_adodb[0] = NULL
		_path[0] = EMPTY
		_exist[0] = FALSE
		DIM i
		FOR i = 1 TO m
			_adodb[i] = NULL
			_box[i] = _box[0]
			_path[i] = EMPTY
			_exist[i] = FALSE
		NEXT
		_max = m
	FEND

	FUNCTION Open(path)
		RESULT = INVALID_HANDLE
		DIM i
		FOR i = 0 TO _max
			IF _adodb[i] = NULL THEN BREAK
		NEXT
		IFB i <= _max THEN
			_adodb[i] = CREATEOLEOBJ("ADODB.Stream")
			WITH _adodb[i]
				.Open()
				.Type = BINARY
				TRY
					_adodb[i].LoadFromFile(path)
					_exist[i] = TRUE
				EXCEPT
					// ファイルがなくても良いじゃない
					_exist[i] = FALSE
				ENDTRY
			ENDWITH
			_path[i] = path
			RESULT = i
		ENDIF
	FEND

	FUNCTION Read(i)
		DIM read = ReadArray(i, 1)
		RESULT = read[0]
	FEND

	FUNCTION ReadArray(i, num=ALL)
		RESULT = _adodb[i].Read(num)
	FEND

	FUNCTION Write(i, bData)
		RESULT = FALSE
		IFB bData >= 0 AND bData < 256 THEN
			DIM box = _box[i]
			box[0] = bData
			_adodb[i].Write(box)
			RESULT = TRUE
		ENDIF
	FEND

	FUNCTION WriteArray(i, bData[],s=0,e=-1)
		RESULT = TRUE
		DIM j, m = e
		IF e = -1 THEN m = RESIZE(bData)
		FOR j = s TO m
			RESULT = RESULT AND Write(i, bData[j])
		NEXT
	FEND

	FUNCTION Save(i, o=OVERWRITE)
		TRY
			_adodb[i].SaveToFile(_path[i], o)
			RESULT = TRUE
		EXCEPT
			RESULT = FALSE
		ENDTRY
	FEND

	FUNCTION Close(i, bSave=FALSE)
		RESULT = FALSE
		IFB _adodb[i] <> NULL THEN
			IF bSave THEN Save(i)
			_adodb[i].Close()
		ENDIF
		_adodb[i] = NULL
		_path[i] = EMPTY
		_exist[i] = FALSE
		RESULT = TRUE
	FEND

	FUNCTION CopyTo(i, j, num = ALL)
		RESULT = FALSE
		_adodb[i].CopyTo(_adodb[j], num)
		RESULT = TRUE
	FEND

	FUNCTION EOS(i, set=FALSE)
		IF set THEN _adodb[i].SetEOS()
		RESULT = _adodb[i].EOS
	FEND

	FUNCTION Size(i, val=ALL)
		IF val > ALL THEN _adodb[i].Size = val
		RESULT = _adodb[i].Size
	FEND

	FUNCTION State(i)
		RESULT = _adodb[i].State
	FEND

	FUNCTION Position(i, pos=NULL)
		IFB pos <> NULL THEN
			IF pos < 0 THEN pos = pos + _adodb[i].Size
			_adodb[i].Position = pos
		ENDIF
		RESULT = _adodb[i].Position
	FEND

	FUNCTION Exist(i)
		RESULT = _exist[i]
	FEND

ENDMODULE