そういえばStreamReader/Writerを直接呼び出すだけだったなので、基本を確認していなかった。
ということで、
メモ
using System.IO;
.net core でプロジェクト作ると using System
だけなので、
忘れずに追加する。
ファイルの扱い
文字列(string)を対象にstaticメソッドで扱うFile/Directoryと、
インスタンス作って扱うFileInfo/DirectoryInfoというのがある。
前者はあくまでも文字列なので、staticメソッド内でのみファイル扱い。
後者はインスタンス化時点からファイル扱い、かな?
その性質上パフォーマンス的な差異があるようだが、
- What is the difference between File and FileInfo in C#? | stack overflow
- FileクラスとFileInfoクラスのメソッドの違い | DOBON.NET
混ぜて使わない、常に同じ書き方をしたい、とするなら
FileInfo/DirectoryInfoのほうを使えばよいのかな、と思う。
DirectoryInfoから階層を辿ったり、検索したりができる。
var di = new DirectoryInfo(@"/path/to/working/directory");
foreach (var fi in di.EnumerateFiles(@"*.cs", SearchOption.AllDirectories))
{
Console.WriteLine(fi.FullName);
}
FileInfoでOpen(/OpenRead/OpenWrite)するとFileStreamが得られる。
var fi = new FileInfo(@"Program.cs");
using (var fs = fi.OpenRead()) {}
このストリームはそのまま使えるし、ファイル種に合わせて別のストリームでラップしても良い。
テキストファイル読み書き
StreamReaderとStreamWriterでする。
エンコード指定できる。デフォルトは UTF-8。
末尾まで来たことはEndOfStream
プロパティで判断できる。
var fi = new FileInfo(@"Program.cs");
using (var fs = fi.OpenRead())
using (var sr = new StreamReader(fs))
{
while (!sr.EndOfStream)
{
Console.WriteLine(sr.ReadLine());
}
}
ただ、読み取りメソッドは末尾まで到着するとnullを返したりなど応答が変わるので、それで終わりを判断することが多いかもしれない。
バイナリファイル読み書き
BinaryReaderとBinaryWriterでする。
型ごとのRead/Writeメソッドが用意されている。
Read時はReadByteなど、メソッド名が異なる。
Writeは引数の型で判断される(オーバーロード)。
var fi = new FileInfo(@"data.bin");
using (var fs = fi.OpenWrite())
using (var bw = new BinaryWriter(fs))
{
bw.Write((Byte)0x10);
bw.Write((Int32)100);
}
using (var fs = fi.OpenRead())
using (var br = new BinaryReader(fs))
{
Console.WriteLine(br.ReadByte());
Console.WriteLine(br.ReadInt32());
}
リトルエンディアン強制らしい。
データはメモリ上で解析・構築することにして、バイト配列で一気読み書きする方が簡単なのかもしれない。
エンディアンの変換は自分で書くか、HostToNetworkOrder/NetworkToHostOrder使うか、
あるいはSystem.Buffers.Binary.BinaryPrimitives
(.NET Core v2.1から追加された)を使うか。
BinaryPrimitivesであれば、バイト配列の所定の位置に好きなエンディアンで書き込める。
var data = new byte[8];
BinaryPrimitives.WriteInt32LittleEndian(data.AsSpan().Slice(0, 4), 1732584193);
BinaryPrimitives.WriteInt32BigEndian(data.AsSpan().Slice(4, 4), 1732584193);
// data = {0x01, 0x23, 0x45, 0x67, 0x67, 0x45, 0x23, 0x01}
もちろん、バイト配列の所定の位置から好きなエンディアンで読み込める。
var data = new byte[] {0x01, 0x23, 0x45, 0x67, 0x67, 0x45, 0x23, 0x01};
var little = BinaryPrimitives.ReadInt32LittleEndian(data.AsSpan().Slice(0, 4));
var big = BinaryPrimitives.ReadInt32BigEndian(data.AsSpan().Slice(4, 4));
// big == little