固定長レコードに対する操作って、ハンディターミナルでは以外と需要があったり
本日のお仕事はこんなカンジ。
Compact Frameworkで使用するための、固定長レコードのファイルに対する操作を行うクラスを、下記の様なインタフェースで用意してみましたがどうでしょう(´д`)
// 固定長レコードの操作クラス public class FixedRecordFile : IDisposable { public string FileName { get; } public int RecordSize { get; } public bool IsOpen { get; } public long FileLength { get; } public int RecordCount { get; } public FixedRecordFile(string filename, int recordSize); public FixedRecordFile(string filename, int recordSize, bool keepStream){} public void Dispose(); public void Open(); public void Close() ; // indexの1件取得 public byte[] GetRecordBytes(int index); // finderにマッチする1件取得 public byte[] Select(Func<byte[], int> finder); // finderにマッチする1件の位置取得 public int SelectIndex(Func<byte[], int> finder); // finderにマッチする複数件取得 public List<byte[]> SelectMulti(Func<byte[], int> finder); // finderにマッチする複数件の位置取得 public List<int> SelectIndexMulti(Func<byte[], int> finder); // conditionを使った全件検索 public List<byte[]> SelectIf(Predicate<byte[]> condition); // 最終レコードに追加 public void Add(byte[] data); // indexの位置に挿入 public void Insert(int index, byte[] data); // finderで見つけた位置に挿入 public void Insert(Func<byte[], int> finder, byte[] data); // indexの位置を更新 public void Update(int index, byte[] data); // finderで見つけた位置を更新 public void Update(Func<byte[], int> finder, byte[] data); // finderで見つけた複数件を更新 public void UpdateMulti(Func<byte[], int> finder, Func<byte[], byte[]> updater); // conditionを使った全件検索でupdaterによる更新 public void UpdateIf(Predicate<byte[]> condition, Func<byte[], byte[]> updater); // indexの位置を削除 public void Delete(int index); // finderで見つけた位置を削除 public void Delete(Func<byte[], int> finder); // finderで見つけた複数件の位置を削除 public void DeleteMutli(Func<byte[], int> finder); // conditionを使った全件検索による削除 public void DeleteIf(Predicate<byte[]> condition); // 全件削除SetLength(0) public void DeleteAll(); // sorterによるソート public void Sort(Func<byte[], byte[], int> sorter); }
// FixedRecordFileのByteMarshaler用版 public class FixedRecordFile<T> : FixedRecordFile where T : ByteMarshaler { public FixedRecordFile(string filename); public FixedRecordFile(string filename, bool keepStream); public T GetRecord(int index); public T Select(Func<T, int> finder); public int SelectIndex(Func<T, int> finder); public List<T> SelectMulti(Func<T, int> finder); public List<int> SelectIndexMulti(Func<T, int> finder); public List<T> SelectIf(Predicate<T> condition); public void Add(T data); public void Insert(int index, T data); public void Insert(Func<T, int> finder, T data); public void Update(int index, T data); public void Update(Func<T, int> finder, T data); public void UpdateMulti(Func<T, int> finder, Func<T, T> updater); public void UpdateIf(Predicate<T> condition, Func<T, T> updater); public void Delete(Func<T, int> finder); public void DeleteMutli(Func<T, int> finder); public void DeleteIf(Predicate<T> condition); public void Sort(Func<T, T, int> sorter); }
なぜDBではなく固定長ファイルかと言えば、上位(基幹)のシステムから降ってきたファイルをそのまま使ったりすることもあるため。
ByteMarshalerはStructLayoutAttribute.Packに対する対応策(´・ω・`)
使い方としては、下記の様なデータ構造に対して、
4900000000001,9999,A,20080101 4900000000002, ,A,20080101 4900000000003, 0,A,20080101 4900000000004, 123,A,20080101 4900000000004, 123,B,20080101
こんなカンジのレコードクラスを用意。
[RecordMarshalAttribute( Size = 31, Blank = (byte)',' )] public class Record : ByteMarshaler { [FieldMarshal( Offset = 0, Size = 13 )] [SjisFieldConverter] public string Jancode { get; set; } [FieldMarshal( Offset = 14, Size = 4 )] [SjisFieldConverter( PadLeft = true, EmptyToNull = true )] public Nullable<int> Qty { get; set; } [FieldMarshal( Offset = 19 )] public byte Type { get; set; } [FieldMarshal( Offset = 21, Size = 8 )] [DateStringConverter] public DateTime Date { get; set; } [FieldMarshal( Offset = 29, Length = 2 )] protected byte[] CRLF = new byte[] { 0x0d, 0x0a }; }
っで、検索をしたい時はこんなカンジで(・∀・)
FixedRecordFile<Record> file = new FixedRecordFile<Record>( filename ); Record record = file.Select( x => x.Jancode.CompareTo( "4900000000003" ) );
そして明日からはNet周りの再整理(・ω・)