【C#】バイト位置検索メソッド


この記事はプロモーションを含みます。

C#

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進数の値を指定する

コメント

タイトルとURLをコピーしました