バイナリファイルの入出力には
FileStreamクラスを用います。
次は、ファイルを1バイトずつ読んでは書いて、
ファイルをコピーするプログラムです。
cp.js
-------------------------------------------------------------------
import System;
import System.IO;
var args : String[] = Environment.GetCommandLineArgs();
if(args.length != 3) {
System.Console.Error.WriteLine("usage : cp file1 file2.");
Environment.Exit(1);
}
var ifs : FileStream;
var ofs : FileStream;
try {
ifs = new FileStream(args[1], FileMode.Open, FileAccess.Read);
ofs = new FileStream(args[2], FileMode.Create);
}
catch(e) { //ファイルがオープンできない
System.Console.Error.WriteLine("error : can't open file.");
Environment.Exit(1);
}
var b : byte;
while(ifs.Position != ifs.Length) { //ファイル終端の判定
b = byte(ifs.ReadByte()); //1バイト読む
ofs.WriteByte(b); //1バイト書く
}
ifs.Close();
ofs.Close();
入力・出力ストリームは次のように作成します。
ifs = new FileStream(args[1], FileMode.Open, FileAccess.Read);
ofs = new FileStream(args[2], FileMode.Create);
FileModeと
FileAccess
は適当に設定します。
1バイト読むのは次のようにします。
b = byte(ifs.ReadByte());
ReadByte
の返り値はintなのでbyteにキャストしているところに注意してください。
1バイト書くのは次のようにします。
ofs.WriteByte(b);
最後に入出力ストリームとも
Closeで閉じます。
Byteだけ読めても多くの場合はあまり役に立たないでしょう。
intなどのプリミティブデータ型の入出力には
BinaryReader・
BinaryWriter
を用います。
次はGIFファイルから画像の幅・高さを抽出します。
cp.js
-----------------------------------------------------------------------
import System;
import System.IO;
import System.Console;
var args : String[] = Environment.GetCommandLineArgs();
if(args.length == 1) { //引数がない場合
Console.Error.WriteLine("usage : gifinfo gif1 [gif2 ...].");
Environment.Exit(1);
}
var fs : FileStream;
var br : BinaryReader;
var header : byte[] = new byte[6];
var width : short;
var height : short;
//引数ごとに出力
for(var i = 1; i < args.length; i++) {
try {
fs = new FileStream(args[i], FileMode.Open, FileAccess.Read);
}
catch(e) { //ファイルがオープンできない
Console.Error.WriteLine("error : can't open " + args[i] + ".");
Environment.Exit(1);
}
br = new BinaryReader(fs);
br.Read(header, 0, 6); //6バイト読み飛ばし
width = br.ReadInt16(); //7・8バイト目をshortで読む
height = br.ReadInt16(); //9・10バイト目をshortで読む
print("width : " + width + "\nheight : " + height);
fs.Close();
}
これは次のように使います。
>gifinfo b.gif
width : 104
height : 122
まず、
BinaryReader
は次のようにFileStreamから得ます。
fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
br = new BinaryReader(fs);
幅・高さはGIFファイルのそれぞれ7・8バイト目と9・10バイト目に
short(Int16)で書かれています。
そこで、
Readで6バイト読み、
その後、
ReadInt16で読みます
(もっとも、ファイル構造を知らなくても
簡単に画像情報を得ることができるようですが)。
このように読むメソッドは、
ReadInt32とか
ReadDoubleとか
読みたいデータ型の種類ごとに用意されています。
詳しくは、
BinaryReader メンバ(MS)
をご覧ください。
BinaryWriterクラスは次のように用います。
stripe.js
--------------------------------------------------------------------------
...
//パラメータの決定
var Bpr : int = (int((width * 3 - 1) / 96) + 1) * 4; //1行あたりのバイト数
var imagesize : int = Bpr * height; //イメージサイズ
var filesize : int = 0x3E + imagesize; //ファイルサイズ
//作成するファイルをオープン
var ofs : FileStream;
try {
ofs = new FileStream(args[1], FileMode.Create);
}
catch(e) { //ファイルがオープンできない
System.Console.Error.WriteLine("error : can't open file.");
Environment.Exit(1);
}
var bw : BinaryWriter = new BinaryWriter(ofs);
//ヘッダ部を書く
bw.Write(short(0x4D42)); //shortで書き込む
bw.Write(filesize); //intで書き込む
...
ofs.Close();
これは縞模様のBMPファイルを作るプログラムです
(肝心の縞模様の部分は上では省略していますが)。
次のように、ファイル名と幅・高さを指定してBMPファイルを作ります。
>stripe b.bmp 235 317
試してみてください。
上にあるように、
BinaryWriterの
Writeメソッドで書き込みます。
Writeメソッドはオーバーロードされていて、
引数がshortならshortで、intならintで書き込みます。
バイナリファイルを開いて、一部変えるということをしたいときもあるでしょう。
この場合、FileAccessを
ReadWriteにすればよいです。
次はGIFファイルの色を変えるプログラムです。
colorchange.js
-----------------------------------------------------------------------
...
//色を変換
var old_color : byte[] = new byte[3];
var new_color : byte[] = new byte[3];
...
//入出力ストリームを開く
var fs : FileStream;
try {
fs = new FileStream(args[1], FileMode.Open, FileAccess.ReadWrite);
}
...
var p_size : int;
var b : byte;
var color : byte[] = new byte[3];
try {
//10バイト分進む
fs.Seek(10, SeekOrigin.Current);
//パレットのサイズを得る
b = byte(fs.ReadByte());
p_size = 2 << (b & 7);
//2バイト分進む
fs.Seek(2, SeekOrigin.Current);
//パレットを読んで
//もしold_colorだったらnew_colorにする
for(i = 0; i < p_size; i++) {
fs.Read(color, 0, 3);
if(color[0] == old_color[0]
&& color[1] == old_color[1] && color[2] == old_color[2]) {
fs.Seek(-3, SeekOrigin.Current); //今読んだ分だけ戻って
fs.Write(new_color, 0, 3); //新しい色を書く
}
}
}
...
fs.Close();
これは次のように使います。
>colorchange b.gif ffffff 0000ff
こうすると画像の白の部分が青になるはずです。
ならなかったら自分で直してください。
パレットの部分で、
fs.Read(color, 0, 3);
としてcolorという配列に3バイト分読んでいます。
もしこれがold_colorと一致すれば、
fs.Seek(-3, SeekOrigin.Current);
として今の位置から3バイト戻り、そこで、
fs.Write(new_color, 0, 3);
としてnew_colorという配列を3バイト分書き込みます。
Seekメソッドの2つ目の引数は、
SeekOrigin.Begin SeekOrigin.Current SeekOrigin.End
のいずれかを取ることができます。