この記事は公開から3年以上経過しています。
.NET開発で固定長テキストファイルデータ利用する際、区切り位置を見ながら分割するなどゴリゴリとテキストを読み込むロジックを書くことなく、手軽に汎用的に構造体にマッピングしてしまう方法。
サンプルソースコード(C#)
この例はC#ですが、VB.NETの場合についても属性の定義方法が異なる以外は同様です。
ちなみに、この構造体上はNULL終端ではない文字列をバイト配列の形で保持していますが、NULL終端文字であることが保証される場合はMarshal.StructureToPtr()
MarshalAs(UnmanagedType.XXXStr)
で直接文字列型で扱うことも可能です。
using System.IO;
using System.Runtime.InteropServices;
namespace StructureTest210227
{
internal class Program
{
private static void Main(string[] args)
{
// 構造体サイズを取得
var structSize = Marshal.SizeOf(typeof(FixedWidthData));
// テキストファイルをアンマネージメモリにロード
var data = File.ReadAllBytes("fixed-width-text.txt");
// テキストファイルのデータをアンマネージメモリにコピー
var pData = Marshal.AllocHGlobal(structSize);
Marshal.Copy(data, 0, pData, structSize);
// アンマネージメモリを構造体にマーシャリング
var structure = Marshal.PtrToStructure(pData, typeof(FixedWidthData));
// アンマネージメモリ解放
Marshal.FreeHGlobal(pData);
}
}
// 構造体
[StructLayout(LayoutKind.Sequential)]
internal struct FixedWidthData
{
// 1 byte
public byte byte1;
// 5 bytes
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public byte[] byte2to6;
// 5 * 2 bytes(ネスト)
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public RepeatableData[] repetition;
// 1 byte
public byte byte17;
}
// 構造体(ネスト用)
[StructLayout(LayoutKind.Sequential)]
internal struct RepeatableData
{
// 2 bytes
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] byte1to2;
// 3 bytes
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] byte3to5;
}
}
実行結果
本例ではネストした構造体配列を持つ構造体に固定長テキストファイルをマッピングしていますが、テキストデータがしっかりと構造体にマッピングできていることが確認できます。
入力ファイルサンプル
(12345abCDEfgHIJ)
マッピング状態
読み込んだ構造体のバイト配列を文字列として扱う場合はEncoding.XXX.GetString(byte[])
で文字列を取得します。
本例は固定長テキストファイルから構造体へのマッピングですが、Marshal.StructureToPtr()
を使えば、これとは逆に構造体から固定長テキストファイルへ書き戻すことも可能です。
参考ウェブサイトなど
-
Microsoft Docs
MarshalAsAttribute クラス -
Microsoft Docs
Marshal.PtrToStructure メソッド
以上です。