visual studio 2013 を使い

VBでのバイナリデータの開き方を教えて下さい。
開きたいファイルは下記にあります。

http://23h2.com/00000001.zip

一部、テキストにしたものはこちらです。
http://23h2.com/sample.txt

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2014/03/22 15:42:31
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:cx20 No.3

回答回数607ベストアンサー獲得回数108

ポイント800pt

gizmo5 さんの回答にあった

■ Binary file format for combat logs - ffxiv
http://www.reddit.com/r/ffxiv/comments/1vey94/binary_file_format_for_combat_logs/



を参考に、読み込むサンプルを書いてみました。
(やっつけなので、バグってるかも知れません。)

Imports System
Imports System.IO
Imports System.Text

Module Module1

    ' <参考>
    ' http://i.imgur.com/by3VaAX.png
    Sub Main()
        Dim bytesFile() As Byte = File.ReadAllBytes("00000001.log")
        Dim bytesBody(3) As Byte ' ヘッダ情報取得用
        Dim bytesPos(3) As Byte  ' ヘッダ情報取得用
        Array.Copy(bytesFile, 0, bytesBody, 0, 4) ' 先頭の4バイトを取得
        Dim nLength = BitConverter.ToInt32(bytesBody, 0) ' 先頭の4バイトをレコード数として取得する
        Dim nPos As Integer      ' 現在の位置
        Dim nPrevPos As Integer  ' 一つ前の位置
        Dim nSize As Integer     ' 1レコードのサイズ
        Dim i As Integer
        nPrevPos = 0
        ' レコード数分ループする
        For i = 0 To nLength - 1
            ' レコードの位置を取得
            Array.Copy(bytesFile, 8 + i * 4, bytesPos, 0, 4)
            nPos = BitConverter.ToInt32(bytesPos, 0)
            ' 1レコードのサイズを算出する(現在の位置-1つ前の位置)
            nSize = nPos - nPrevPos
            ' 1レコード取得する
            Dim bytesRecord(nSize - 1) As Byte
            Array.Copy(bytesFile, 8 + nLength * 4 + nPrevPos, bytesRecord, 0, nSize)
            ' データを解析する
            Parse(bytesRecord)
            ' 一つ前の位置を変数に保持しておく
            nPrevPos = nPos
        Next
    End Sub

    ' 解析処理
    ' <参考>
    ' http://www.reddit.com/r/ffxiv/comments/1vey94/binary_file_format_for_combat_logs/
    Sub Parse(bytesRecord() As Byte)
        Dim nLength As Integer = bytesRecord.Length

        ' 日付情報取得
        Dim nTimeStampSize = 14
        Dim bytesTimeStamp(nTimeStampSize - 1) As Byte  ' タイムスタンプ
        Array.Copy(bytesRecord, 0, bytesTimeStamp, 0, nTimeStampSize)
        Dim strTimeStamp = Encoding.UTF8.GetString(bytesTimeStamp)
        Console.WriteLine("Time : {0}", ConvertEpochTime(Left(strTimeStamp, 8)))

        ' メッセージ情報取得
        Dim bytesFieldHeader(10) As Byte  ' フィールドヘッダ取得用
        Array.Copy(bytesRecord, 0, bytesTimeStamp, 0, 14)
        Dim nPos As Integer
        Dim nHeader As Integer
        Dim nType As Integer
        Dim nMessageLength As Integer
        Dim strName As String
        Dim byteData() As Byte
        Dim nDataLength As Integer
        nPos = nTimeStampSize
        While nPos < nLength
            ' フィールドヘッダを読み込み解析処理を行う
            If (nPos + 3) < nLength Then
                nHeader = bytesRecord(nPos)
                nType = bytesRecord(nPos + 1)
                nMessageLength = bytesRecord(nPos + 2)
            End If
            ' 0x02, 0x27 で始まる場合、name として取り扱う
            If nHeader = &H2 And nType = &H27 Then
                Dim byteName(nMessageLength - 6 - 1) As Byte
                Array.Copy(bytesRecord, nPos + 3 + 6, byteName, 0, nMessageLength - 6 - 1)
                strName = Encoding.UTF8.GetString(byteName)
                strName = Replace(strName, vbNullChar, "")
                If strName.Length > 0 Then
                    Console.WriteLine("Name : {0}", strName)
                End If
                nPos += 2 + nMessageLength
            ' 0x03 は読み飛ばす
            ElseIf nHeader = &H3 Then
                ' 読み飛ばす
                nPos += 1
            ' 残りはデータ部としてバイト配列に連結する
            Else
                If byteData Is Nothing Then
                    nDataLength = 0
                Else
                    nDataLength = byteData.Length
                End If
                ReDim Preserve byteData(nDataLength)
                Dim c = bytesRecord(nPos)
                byteData(nDataLength) = c
                nPos += 1
            End If
        End While

        ' データ部をUTF-8でデコードする。一部、特殊記号(外字?)については、ASCII 文字置換。
        Dim strArrow As String = Encoding.UTF8.GetString({&HEE, &H81, &HAF}) ' 特殊記号
        Dim strData As String = Encoding.UTF8.GetString(byteData)
        strData = Replace(strData, strArrow, "=>") ' 特殊記号は ASCII 文字で置換
        Console.WriteLine("Data : {0}", strData)
    End Sub

    ' エポック秒変換
    ' 例)"52978F55" -> "2013/11/29 03:45:41"
    Function ConvertEpochTime(strEpochTime As String) As String
        Dim strResult As String
        Dim unixTimeStamp As Integer = Convert.ToInt32(strEpochTime, 16)
        Dim unixDate As DateTime = (New DateTime(1970, 1, 1)).AddSeconds(unixTimeStamp).ToLocalTime()
        strResult = unixDate.ToString("yyyy/MM/dd HH:mm:ss")
        Return strResult
    End Function
End Module
id:cx20

実行結果

Time : 2013/11/29 03:45:41
Name : Pibu Parrotking
Data : Pibu Parrotkingの「ステディハンドII」
Time : 2013/11/29 03:45:41
Name : Pibu Parrotking
Data :   => Pibu Parrotkingに「ステディハンドII」の効果。
Time : 2013/11/29 03:45:41
Name : Hermis Forever
Data : Hermis Foreverの「インナークワイエット」
Time : 2013/11/29 03:45:41
Name : Hermis Forever
Data :   => Hermis Foreverに「インナークワイエット」の効果。
Time : 2013/11/29 03:45:42
Name : Porter One
Data : Porter Oneの「コンファートゾーン」
Time : 2013/11/29 03:45:42
Name : Porter One
Data :   => Porter Oneに「コンファートゾーン」の効果。
 :
2014/03/22 15:26:13

その他の回答2件)

id:snow0214 No.1

回答回数470ベストアンサー獲得回数116

ポイント150pt

これでバイナリ・ファイルを変数bytesに読み込みます。

Dim bytes = My.Computer.FileSystem.ReadAllBytes("C:\00000001.log")
id:snow0214

そのファイルの構造が分からないと、文字列だけ切り出すのは無理です。可変長みたいなので。
文字コードはUTF-8みたいなので、上の回答の"shift_jis"→"utf-8"変更で読み込める部分はあると思います。

2014/03/21 15:57:27
id:mac2013

テキストファイルではありませんでした。

このファイルの文字列の開きかたをお願い致します。

id:mac2013

質問文を編集しました。詳細はこちら

id:gizmo5 No.2

回答回数504ベストアンサー獲得回数141

ポイント50pt

FF XIV のデータを解析しようとしてるwww
こちらが参考になるかもしれません。
http://www.reddit.com/r/ffxiv/comments/1vey94/binary_file_format_for_combat_logs/

id:cx20 No.3

回答回数607ベストアンサー獲得回数108ここでベストアンサー

ポイント800pt

gizmo5 さんの回答にあった

■ Binary file format for combat logs - ffxiv
http://www.reddit.com/r/ffxiv/comments/1vey94/binary_file_format_for_combat_logs/



を参考に、読み込むサンプルを書いてみました。
(やっつけなので、バグってるかも知れません。)

Imports System
Imports System.IO
Imports System.Text

Module Module1

    ' <参考>
    ' http://i.imgur.com/by3VaAX.png
    Sub Main()
        Dim bytesFile() As Byte = File.ReadAllBytes("00000001.log")
        Dim bytesBody(3) As Byte ' ヘッダ情報取得用
        Dim bytesPos(3) As Byte  ' ヘッダ情報取得用
        Array.Copy(bytesFile, 0, bytesBody, 0, 4) ' 先頭の4バイトを取得
        Dim nLength = BitConverter.ToInt32(bytesBody, 0) ' 先頭の4バイトをレコード数として取得する
        Dim nPos As Integer      ' 現在の位置
        Dim nPrevPos As Integer  ' 一つ前の位置
        Dim nSize As Integer     ' 1レコードのサイズ
        Dim i As Integer
        nPrevPos = 0
        ' レコード数分ループする
        For i = 0 To nLength - 1
            ' レコードの位置を取得
            Array.Copy(bytesFile, 8 + i * 4, bytesPos, 0, 4)
            nPos = BitConverter.ToInt32(bytesPos, 0)
            ' 1レコードのサイズを算出する(現在の位置-1つ前の位置)
            nSize = nPos - nPrevPos
            ' 1レコード取得する
            Dim bytesRecord(nSize - 1) As Byte
            Array.Copy(bytesFile, 8 + nLength * 4 + nPrevPos, bytesRecord, 0, nSize)
            ' データを解析する
            Parse(bytesRecord)
            ' 一つ前の位置を変数に保持しておく
            nPrevPos = nPos
        Next
    End Sub

    ' 解析処理
    ' <参考>
    ' http://www.reddit.com/r/ffxiv/comments/1vey94/binary_file_format_for_combat_logs/
    Sub Parse(bytesRecord() As Byte)
        Dim nLength As Integer = bytesRecord.Length

        ' 日付情報取得
        Dim nTimeStampSize = 14
        Dim bytesTimeStamp(nTimeStampSize - 1) As Byte  ' タイムスタンプ
        Array.Copy(bytesRecord, 0, bytesTimeStamp, 0, nTimeStampSize)
        Dim strTimeStamp = Encoding.UTF8.GetString(bytesTimeStamp)
        Console.WriteLine("Time : {0}", ConvertEpochTime(Left(strTimeStamp, 8)))

        ' メッセージ情報取得
        Dim bytesFieldHeader(10) As Byte  ' フィールドヘッダ取得用
        Array.Copy(bytesRecord, 0, bytesTimeStamp, 0, 14)
        Dim nPos As Integer
        Dim nHeader As Integer
        Dim nType As Integer
        Dim nMessageLength As Integer
        Dim strName As String
        Dim byteData() As Byte
        Dim nDataLength As Integer
        nPos = nTimeStampSize
        While nPos < nLength
            ' フィールドヘッダを読み込み解析処理を行う
            If (nPos + 3) < nLength Then
                nHeader = bytesRecord(nPos)
                nType = bytesRecord(nPos + 1)
                nMessageLength = bytesRecord(nPos + 2)
            End If
            ' 0x02, 0x27 で始まる場合、name として取り扱う
            If nHeader = &H2 And nType = &H27 Then
                Dim byteName(nMessageLength - 6 - 1) As Byte
                Array.Copy(bytesRecord, nPos + 3 + 6, byteName, 0, nMessageLength - 6 - 1)
                strName = Encoding.UTF8.GetString(byteName)
                strName = Replace(strName, vbNullChar, "")
                If strName.Length > 0 Then
                    Console.WriteLine("Name : {0}", strName)
                End If
                nPos += 2 + nMessageLength
            ' 0x03 は読み飛ばす
            ElseIf nHeader = &H3 Then
                ' 読み飛ばす
                nPos += 1
            ' 残りはデータ部としてバイト配列に連結する
            Else
                If byteData Is Nothing Then
                    nDataLength = 0
                Else
                    nDataLength = byteData.Length
                End If
                ReDim Preserve byteData(nDataLength)
                Dim c = bytesRecord(nPos)
                byteData(nDataLength) = c
                nPos += 1
            End If
        End While

        ' データ部をUTF-8でデコードする。一部、特殊記号(外字?)については、ASCII 文字置換。
        Dim strArrow As String = Encoding.UTF8.GetString({&HEE, &H81, &HAF}) ' 特殊記号
        Dim strData As String = Encoding.UTF8.GetString(byteData)
        strData = Replace(strData, strArrow, "=>") ' 特殊記号は ASCII 文字で置換
        Console.WriteLine("Data : {0}", strData)
    End Sub

    ' エポック秒変換
    ' 例)"52978F55" -> "2013/11/29 03:45:41"
    Function ConvertEpochTime(strEpochTime As String) As String
        Dim strResult As String
        Dim unixTimeStamp As Integer = Convert.ToInt32(strEpochTime, 16)
        Dim unixDate As DateTime = (New DateTime(1970, 1, 1)).AddSeconds(unixTimeStamp).ToLocalTime()
        strResult = unixDate.ToString("yyyy/MM/dd HH:mm:ss")
        Return strResult
    End Function
End Module
id:cx20

実行結果

Time : 2013/11/29 03:45:41
Name : Pibu Parrotking
Data : Pibu Parrotkingの「ステディハンドII」
Time : 2013/11/29 03:45:41
Name : Pibu Parrotking
Data :   => Pibu Parrotkingに「ステディハンドII」の効果。
Time : 2013/11/29 03:45:41
Name : Hermis Forever
Data : Hermis Foreverの「インナークワイエット」
Time : 2013/11/29 03:45:41
Name : Hermis Forever
Data :   => Hermis Foreverに「インナークワイエット」の効果。
Time : 2013/11/29 03:45:42
Name : Porter One
Data : Porter Oneの「コンファートゾーン」
Time : 2013/11/29 03:45:42
Name : Porter One
Data :   => Porter Oneに「コンファートゾーン」の効果。
 :
2014/03/22 15:26:13
  • id:cx20
    何かのゲームデータのようですね。。。

    ファイルのレコード仕様が分からないと、読み込むのは厳しいと思います。
    ---------------------------------------------------------------
    [35][32][39][37][38][46][35][35][31][30][32][42][3A][3A]
    ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
    "52978F55102B::"(ASCII)
    [02][27][16][01][01][01][01][FF][10]
    ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
    (バイナリ部)
    [50][69][62][75][20][50][61][72][72][6F][74][6B][69][6E][67]
    ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
    "Pibu Parrotking"(ASCII)
    [03]

    (バイナリ部)
    [50][69][62][75][20][50][61][72][72][6F][74][6B][69][6E][67]
    ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
    "Pibu Parrotking"(ASCII)
    [02][27][07][CF][01][01][01][FF][01][03]
    ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
    (バイナリ部)
    [E3][81][AE][E3][80][8C][E3][82][B9][E3][83][86][E3][83][87][E3][82][A3][E3][83][8F][E3][83][B3][E3][83][89][49][49][E3][80][8D]
    ↓↓↓↓↓↓↓↓↓↓↓
    "の「ステディハンドII」"(UTF-8)
    ---------------------------------------------------------------

    ちなみに、Visual Studio 2014 は、まだ出ていなかったかと。。。
  • id:cx20
    データ構造的には
    「いつ」+「誰が」+「何をした」
    というような構造になっている気がします。

    ゲームのセーブデータとかだとすると、ファイルを公開するのはまずい気が。。。
  • id:mac2013
    文字のみのデータですのでご安心を。
    一部テキストにしたものを公開します。

    http://23h2.com/sample.txt

    またバイナリの表示の方法だけでも
    教えて頂けると助かります。
  • id:cx20
    バイナリファイルの読み込みについては「バイト配列」について調べてみてください。

    ■ バイナリ・ファイルを簡単に読み書きするには?[2.0のみ、C#、VB] - @IT
    http://www.atmarkit.co.jp/fdotnet/dotnettips/670readallbytes/readallbytes.html

    ちなみに、時間部分については、以下のような変換で情報が取得できるかと思います。

    [35][32][39][37][38][46][35][35][31][30][32][42][3A][3A]
    ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
    "52978F55102B::"(ASCII)
     ↓ ↓ ↓(8,2,2桁で分割
    "52978F55","10","2B"
     ↓(16進数→10進数に変換)
    1385664341,16,43
     ↓(エポック秒から変換)
    2013/11/29 03:45:41

    <参考情報>
    ■ エポック秒(UNIX時間)変換マシーン
    http://exp777.cs.land.to/epochsec.html

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません