본문 바로가기
.NET

C# 구조체 바이너리 파일 읽기

by leo21c 2022. 8. 10.
SMALL

C#에서 구조체 파일을 읽어 처리하는 간단한 예제이다.

구조체 바이너리 파일은 C++ MFC로 제작이 되어 있었다.

 

C++ 구조체는 아래와 같다.


typedef struct {
    TCHAR   Name[20];
    TCHAR   ID[20];
    TCHAR   Passwd[20];
    uint    Grade;
}   stUserInfo;

위와 같은 구조체로 만들어지 바이너리 파일을 C#에서 읽어 클래스 리스트에 넣도록 처리 예정이다.

C#에서는 아래와 같은 구조체가 C++ 구조체와 같은 모습니다. 


    [Serializable]
    [StructLayout(LayoutKind.Sequential)]
    public struct UserInfo
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
        public char[] Name;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
        char[] ID;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
        char[] Passwd;

        uint nGrade;
    }

    public class CUserInfo
    {
        public string Name { get; set; }
        public string ID { get; set; }
        public string Passwd { get; set; }
        public uint Grade { get; set; }

        public CUserInfo()
        {
             Grade = 0;
        }
    }

C#에서는 MarshalAs를 이용해서 배열의 크기를 지정할 수 있다.

 

아래 소스는 바이너리를 읽어서 클래스 리스트에 추가하는 예제 함수이다.


private void buttonTest_Click(object sender, EventArgs e)
{
    UserInfo user = new UserInfo();
    //구조체 크기를 확인 한다.
    int useSize = Marshal.SizeOf(user);

    using (FileStream fs2 = new FileStream("sample.dat", FileMode.Open))
    {

        int size = (int)fs2.Length; //파일 크기를 구한다.
        int nCount = size / useSize;//파일 크기를 구조체 크기로 나눠 구조체 개수 확인

        byte[] buff = new byte[40]; //임시 버퍼
        
        for (int i = 0; i < nCount; i++)
        {
            CUserInfo user2 = new CUserInfo(); //클래스 생성

            Array.Clear(buff, 0, buff.Length); //버퍼 초기화              
            int n = fs2.Read(buff, 0, 40); //40바이트 바이너리 읽기
            user2.Name = Encoding.Unicode.GetString(buff); //TCHAR 유니코드 변환
            user2.Name = user2.Name.Substring(0, user2.Name.IndexOf('\0')); //널 이후 제거

            Array.Clear(buff, 0, buff.Length);
            n = fs2.Read(buff, 0, 40);
            user2.ID = Encoding.Unicode.GetString(buff);
            user2.ID = user2.ID.Substring(0, user2.ID.IndexOf('\0'));

            Array.Clear(buff, 0, buff.Length);
            n = fs2.Read(buff, 0, 40);
            user2.Passwd = Encoding.Unicode.GetString(buff);
            user2.Passwd = user2.Passwd.Substring(0, user2.Passwd.IndexOf('\0'));

            Array.Clear(buff, 0, buff.Length);
            n = fs2.Read(buff, 0, 4);
            user2.nGrade = BitConverter.ToUInt32(buff, 0);

            if (user2.Name.Length == 0) continue;

            UserInfoList.Add(user2);
        }
    }
}

바이트 Array를 초기화는 아래와 같은 방식으로 처리를 한다.

Array.Clear(buff, 0, buff.Length);

 

바이너리를 string으로 컨버트 하는 것은 Encoding 클래스를 이용한다.

user2.Name = Encoding.Unicode.GetString(buff);

구조체가 TCHAR으로 unicode이기 때문에 위와 같이 컨버트를 진행한다.

 

스트링에 쓰레기 값이 있으면 삭제를 하기 위해서 Substring를 처리하였다.

user2.Name = user2.Name.Substring(0, user2.Name.IndexOf('\0'));

첫번째 null 값이 나오면 그 이후로 삭제를 한다.

 

위와 같은 방식으로 바이너리를 읽어서 클래스에 넣도록 처리를 한다.

LIST