C#で、バイナリファイル内で指定した16進数の値を検索し、そのバイト位置を返すメソッドを作成したので公開します。
仕様
本メソッドの仕様を簡単に説明します。
バイナリファイルと検索したい16進数の値を指定することで、その値のバイト位置を返します。
(実装時の環境は、C#[.NET Framework 8.0]です)
例えば、検索する値に「905682B582A2」を指定して実行した場合、
「16進数の値はファイルのバイト位置 30 にあります。」が出力されます。
(検索する値が始まる前までのバイト数を取得します)

ソースコード
本メソッドのソースコードです。
フォームアプリとして作成しているので、ボタンのクリック時に処理が開始するメソッドになっています。
フォームアプリのデザインコードですが、ボタンが1つあるだけのものなので、ここでは割愛します。
using System.Diagnostics;
namespace WinFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// 対象のバイナリファイルのパス
string filePath = @"C:\Workspace\sample.zip";
// 検索したい16進数の値
string hexValue = "905682B582A2";
try
{
long position = FindHexInFile(filePath, hexValue);
if (position >= 0)
{
Debug.WriteLine($"16進数の値はファイルのバイト位置 {position} にあります。");
}
else
{
Debug.WriteLine("指定した16進数の値はファイル内に存在しません。");
}
}
catch (Exception ex)
{
Debug.WriteLine($"エラー: {ex.Message}");
}
}
/// <summary>
/// バイナリファイル内で指定した16進数の値を検索し、そのバイト位置を返す
/// </summary>
/// <param name="filePath">検索対象のバイナリファイルのパス</param>
/// <param name="hexValue">検索したい16進数の文字列(例: "1A2B3C")</param>
/// <returns>16進数の値が最初に見つかったバイト位置(見つからなければ-1)</returns>
private static long FindHexInFile(string filePath, string hexValue)
{
// 16進数の文字列をバイト配列に変換
byte[] searchBytes = HexStringToByteArray(hexValue);
// バイナリファイルを開く
using FileStream fs = new(filePath, FileMode.Open, FileAccess.Read);
byte[] buffer = new byte[searchBytes.Length];
long filePosition = 0;
while (fs.Position < fs.Length)
{
// 現在位置から検索する長さのバイトを読み込む
int bytesRead = fs.Read(buffer, 0, searchBytes.Length);
if (bytesRead < searchBytes.Length)
{
break;
}
// 読み込んだバイト列と検索対象が一致するかチェック
if (IsMatch(buffer, searchBytes))
{
// 見つかった場合、そのバイト位置を返す
return filePosition;
}
// 1バイト進めて再度読み込み
filePosition++;
fs.Seek(filePosition, SeekOrigin.Begin);
}
// 見つからなかった場合
return -1;
}
/// <summary>
/// 16進数の文字列をバイト配列に変換する
/// </summary>
/// <param name="hexString">16進数の文字列(例: "1A2B3C")</param>
/// <returns>対応するバイト配列</returns>
static byte[] HexStringToByteArray(string hexString)
{
int length = hexString.Length;
byte[] bytes = new byte[length / 2];
for (int i = 0; i < length; i += 2)
{
bytes[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
}
return bytes;
}
/// <summary>
/// バイト配列同士が一致するかどうかを確認する
/// </summary>
/// <param name="array1">1つ目のバイト配列</param>
/// <param name="array2">2つ目のバイト配列</param>
/// <returns>一致すればtrue、それ以外はfalse</returns>
private static bool IsMatch(byte[] array1, byte[] array2)
{
if (array1.Length != array2.Length)
{
return false;
}
for (int i = 0; i < array1.Length; i++)
{
if (array1[i] != array2[i])
{
return false;
}
}
return true;
}
}
}
実行するには、以下を設定すればいいかと思います。
・フォームアプリにボタンを配置する(名前は「button1」です)
・15行目に値を検索したいバイナリファイルのパスを指定する
・18行目に検索したい16進数の値を指定する
リンク
コメント