【问题标题】:Search for specific strings of data from a binary .dat file, only extract text从二进制 .dat 文件中搜索特定的数据字符串,仅提取文本
【发布时间】:2015-02-13 02:44:00
【问题描述】:

Sub ReadEntireFileAndPlaceOnWorksheet()
    Dim X As Long, Ys As Long, FileNum As Long, TotalFile As String, FileName As String, Result() As String, Lines() As String, rng As Range, i As Long, used As Range, lc As Long
    
         FileName = "C:\Users\MEA\Documents\ELCM2\DUMMY_FILE.dat"
        FileNum = FreeFile
         Open FileName For Binary As #FileNum
        TotalFile = Space(LOF(FileNum))
        Get #FileNum, , TotalFile
        Close #FileNum
        Lines = Split(TotalFile, vbNewLine)
         Ys = 1
         lc = Sheet3.Cells(1, Columns.Count).End(xlToLeft).Column
        For X = 1 To UBound(Lines)
            Ys = Ys + 1
            ReDim Preserve Result(1 To Ys)
            Result(Ys) = "'" & Lines(X - 1)
            Set used = Sheet1.Cells(Sheet1.Rows.Count, lc + 1).End(xlUp).Rows
            Set rng = used.Offset(1, 0)
            rng.Value = Result(Ys)
         Next
         
End Sub

我正在尝试在 .dat(二进制文件)中查找一些数据。数据应如下所示:

MiHo14.dat
MDF     3.00    TGT 15.0
Time: 06:40:29 PM
Recording Duration: 00:05:02
Database: DB
Experiment: Min Air take
Workspace: MINAIR
Devices: ETKC:1,ETKC:2
Program Description: 0delivupd2
Module_delivupd2
WP: _AWD_5
RP: _AWD
§@
Minimum intake - + revs - Downward gear ​

我目前从 .dat 文件中提取所有数据并放在 Excel 文件中的代码如下所示:

MiHo14.dat
MDF     3.00    TGT 15.0
Time: 06:40:29 PM
Recording Duration: 00:05:02
Database: DB
Experiment: Min Air take
Workspace: MINAIR
Devices: ETKC:1,ETKC:2
Program Description: 0delivupd2
Module_delivupd2
WP: _AWD_5
RP: _AWD
§@
Minimum intake - + revs - Downward gear 
Bã|ŽA…@@,s~?
B{À¿…@@@Ý‚Iá 
Á<
"@²n¢”N@ÇÿÈÿj
Ð=“SØ•N@ÇÿÈÿj   
à¨. —N@ÇÿÈÿj
 8²œg˜N@ÇÿÈÿj
0NI,¯™N@ÈÿÈÿj
Ðä$öšN@ÈÿÈÿj
@Q›=œN@ÈÿÈÿj
Пe…N@ÇÿÈÿj
 GàÍžN@ÇÿÈÿj"
etc....​

我需要知道如何使用 instr 函数通过识别包含“:”的行来提取信息,另一个挑战是数据中有最后一行是用户评论这个用户评论基本上可以是任何文本,我需要能够在不提取整个文件的情况下提取它,因为您可以看到它附带了很多符号(乱码)。

【问题讨论】:

  • 在您的帖子中显示您尝试识别合格行的代码。
  • 我得到一个下标超出范围错误,为了解释我的想法,我想我告诉它要做的是检查是否存在 : 存在,如果存在则将其添加到结果中?我是对的还是完全不正确的?
  • @RonRosenfeld 您好,很抱歉再次打扰您!不幸的是,到目前为止,没有一个答案能够成功解决这个问题。但是,我设法找到了一份详细说明二进制文件结构的文档,不幸的是,我对这种事情的掌握有限,但是如果我可以将 PDF 发送给您,也许您可​​以从中获取信息的位置可以建议如何更改代码以获得所需的信息?
  • 如果您可以发布指向 pdf 的链接,我可以访问它。同样重要的是,当您尝试通过例程运行它时,该文件的副本会导致下标超出范围错误。您可以将其放在公共网站上,例如 DropBox 或 OneDrive,然后在此处发布链接。
  • app.box.com/s/qd4oxba6mr40itec5s7meeghhpjh7tjz 是文件的链接,app.box.com/s/ftoqyw5ov9yeegfyhxb2n8edrn9xlmwi 是 PDF 文件的链接。只是为了给你一个更新我不再有下标错误,我已经设法克服这个问题是我仍然在我不需要的 excel 表中得到这个额外的垃圾,我希望你能告诉我如何指定宏以复制该 pdf 的 HD/PR/TX 块(第 3.4/3.5/3.6 节)的行。欢呼

标签: string vba binary extract


【解决方案1】:

我认为您不想复制所有 HD/PR/TX 块来获得所需的输出。

检查您的文件,我可以看到有效数据和无效数据之间的一个区别(从您的角度来看)是无效数据不以 CR-LF 组合结尾,或者包含空字符。如果该特征在您的文件中是一致的,您可以利用它来发挥优势:

下面是我使用的代码和结果。您可以为自己的例程修改变量,看看它是否始终如一地工作。


Option Explicit
Sub ProcessDAT()
    Const sFN As String = "D:\Users\Ron\Desktop\DUMMY_FILE.dat"
    Const sEND As String = vbCrLf
    Dim S As String, COL As Collection, V As Variant, I As Long
    Dim R As Range

Open sFN For Binary Access Read As #1
S = Space(LOF(1))
    Get #1, , S
Close #1

V = Split(S, sEND)
Set COL = New Collection
For I = 0 To UBound(V)
    If InStr(V(I), Chr(0)) = 0 Then COL.Add V(I)
Next I

ReDim V(1 To COL.Count, 1 To 1)
For I = 1 To UBound(V)
    V(I, 1) = COL(I)
Next I

Set R = Range("a1").Resize(UBound(V))
R = V  
End Sub

结果

Time: 11:47:42 AM
Recording Duration: 00:01:09
Database: Testproject
Experiment: Measurement_Dummy
Workspace: Workspace
Devices: ETKC:1
Program Description: LPOOPL14
WP: LPOOPL14d2_1
RP: LPOOPL14d2
§@
Dummy test data

【讨论】:

  • 您好,不幸的是,这个脚本的蜜月期已经结束,现在又开始添加几行乱码,我正在尝试按您说的添加此条件,它要么不包含 CR- LF 或者它包含一个 0。我想添加,如果 InStr(V(I), Chr(0)) = 0 或 inStr(V(I), Chr(CR-LF)) 0 然后 COL.Add V (I),但是我很确定 Chr 正在寻找一个字符而不是 5 个字符,我将如何调整它以使用此解决方案,以便它寻找 0 或确保没有 CR-LF 结尾?跨度>
  • @Samatar 你问错了问题。脚本已经排除了这些字符。您需要检查文件的二进制文件并了解脚本失败的原因。或者像以前一样发布失败文件的副本。
  • 这实际上是一个愚蠢的问题,我想问你的是我所知道的是我需要的信息,如文件所述:“文本(由 CR 和 LF 指示的新行;文本结束由 0)" 表示,此时它正在识别以 CRLF 开头的行,然后检查它们是否包含零,有没有办法查看它们是否以 0 结尾?我想这可以保证我们只得到正确的?
  • 请注意我尝试使用 if right$(V(I),1) =chr(0) then....但是它不起作用。事实上,它只会用我试图避免的胡言乱语填满工作表。我想我误解了一些东西。可能是整个数据块在有 0 时结束,所以我应该在找到 0 时停止搜索,而不是在每行的末尾寻找 0,我猜这就是它已经在做的事情。我真的不知道为什么它不起作用。
  • @Samatar 该代码查找CR-LF 结尾且不包含 Chr(0) 的段。正如我所写,您需要检查文件以了解它失败的原因。正如您所发现的,查找以 Chr(0) 结尾的段没有用。
【解决方案2】:

该代码无法编译,因为您没有循环您的 for 循环。

Sub ReadEntireFileAndPlaceOnWorksheet()
    Dim X As Long, Y As Long, FileNum As Long, sFile As String, FileName As String, Result() As String, Lines() As String, rng As Range, i As Long, used As Range, MyFolder As String

    With Application.FileDialog(msoFileDialogFolderPicker)
        .Show
        MyFolder = .SelectedItems(1)
    End With
    FileName = Dir(MyFolder & "\*.*")
    Do Until FileName = ""
        sFile = ReadFile(MyFolder & "\" & FileName)
        Lines = Split(sFile, vbLf)
        Y = 1
        For X = 1 To UBound(Lines)
            If InStr(1, Lines(X), ":", vbTextCompare) <> 0 Then
                ReDim Preserve Result(Y) '<-- Changed to a 1D array, I don't know why you had a 2D
                Result(Y) = "'" & Lines(X - 1)
                Y = Y + 1 '<-- increases to resize the array as it goes
            End If
        Next '<-- Added that in
        Set used = Sheet1.Cells(1, Sheet1.Columns.Count).End(xlToLeft).Columns
        Set rng = used.Offset(0, 1)
        rng.Resize(UBound(Result)).Formula = WorksheetFunction.Transpose(WorksheetFunction.Transpose(Result))
        FileName = Dir()
    Loop
End Sub


Function ReadFile(ByVal strFile As String) As String
On Error GoTo Error_Handler
    Dim FileNumber  As Integer
    Dim sFile       As String 'Variable contain file content
    FileNumber = FreeFile
    Open strFile For Binary Access Read As FileNumber
    sFile = Space(LOF(FileNumber))
    Get #FileNumber, , sFile
    Close FileNumber

    ReadFile = sFile

Error_Handler_Exit:
    On Error Resume Next
    Exit Function

Error_Handler:
    MsgBox "The following error has occured." & vbCrLf & vbCrLf & _
            "Error Number: " & Err.Number & vbCrLf & _
            "Error Source: ReadFile" & vbCrLf & _
            "Error Description: " & Err.Description, _
            vbCritical, "An Error has Occured!"
    Resume Error_Handler_Exit
End Function

将数组更改为一维

最后,如果你正确缩进你的代码,它会更容易阅读和帮助你。

在此阅读文件:http://www.devhut.net/2012/05/14/vba-read-file-into-memory/

【讨论】:

  • 抱歉代码混乱,下标错误9仍然出现在ReDim Preserve Result(Y)行
  • Result 有几个问题: 1) 它是固定大小的。使用Dim Result() As String(这会导致错误)2)用ReDim Preserve Result(1 To Y)指定下限3)For循环将不起作用,因为Result当时没有初始化。使用For X = 0 To UBound(Lines)(并将索引调整为Lines
  • @chrisneilsen 抱歉,我不理解您的解决方案编号 3。如果我理解正确,您保存的结果字符串中包含“:”的行是否正确?如果您不介意展示它,那么我可以逐行运行并理解它?非常感谢
  • @Samatar 抱歉,第 3 点不是很清楚。实际上存在两个问题:首先,您的逻辑确实需要在 Lines 上进行循环,因此无论如何都需要进行更改。其次,当你声明一个动态数组(当你声明一个没有大小的数组时,它就是这样调用的)它开始时是未初始化的。如果您在未初始化的数组上尝试UBound,您将得到错误 9 下标超出范围。
  • @DanDonoghue 才发现你的改动,一来欢呼,二来它不起作用 Type mismatch error 13,关于转置功能,为什么需要转置?其次,如果与您的第一个解决方案类似,如果您能解释一下它的作用,我对 VBA 还是很陌生,并且想在获得帮助时学习!再次欢呼
【解决方案3】:

Option Explicit
Sub ProcessDAT()
    Const sFN As String = "C:\Users\Mohamed samatar.DSSE-EMEA\Documents\EQVL\Test\WHVP113_140827_TTinsug_TTbana_292Data_WOT_TakeOff_Launch_LaunchPlus_PUoff_REF_1.dat"
    Const sEND As String = vbCrLf
    Dim S As String, COL As Collection, V As Variant, I As Long
    Dim R As Range
    Dim MLocation  As Long
    Dim PRLocation As Long
    Dim Mstuff As String
    Dim MSize As Long
    Dim MSize1 As Integer
      
Open sFN For Binary Access Read As #1
    Get #1, &H49, MLocation

    MSize = MLocation + 2
   
    Get #1, MSize, MSize1
    'MsgBox Hex(MSize1)
    
   
    Mstuff = String$(MSize1, " ")
    Get #1, MLocation, Mstuff
Close #1

V = Split(Mstuff, sEND)
Set COL = New Collection
For I = 0 To UBound(V)
    If InStr(V(I), Chr(0)) = 0 Then COL.Add V(I)
Next I

ReDim V(1 To COL.Count, 1 To 1)
For I = 1 To UBound(V)
    V(I, 1) = COL(I)
Next I

Set R = Range("a1").Resize(UBound(V))
R = V
End Sub

我使用整数,因为它是一个 2 字节的数据类型,现在它可以工作了,如果这就是你所说的解决方案,你能评论一下吗?!

【讨论】:

  • 这是一个二进制文件。所以将文本块位置读入一个四元素字节数组;处理获取TXBLOCK的位置;将 TXBLOCK 的字节 3 和 4 读入一个 2 元素 Byte 数组;处理以获取大小;然后将整个 TXBLOCK(标头和大小字节少四个)读入一个具有正确空格数(TX 大小减四)的字符串。
  • 嗨,所以我把它写成 Size(4) As byte。但是大小是 Little Endian 格式,所以它需要按顺序显示 Size (3), Size(4) 所以我将如何编写 Get 语句是我的问题,以便使用它来获取块的大小.. .我的问题有意义吗?对不起,我尝试了很多方法,似乎要么将它们加在一起,要么以其他不正确的方式组合它们。
  • 或者您的真实数据可能存在与 DUMMY.DAT 类似的问题。可能存在许多问题,而且由于这是您无法分享的公司业务,因此我无法与您进一步讨论。也许您需要找出与我使用的方法不同的方法。也许有一个工具可以比 VBA/Excel 更容易读取文件
  • 最后我使用整数类型来存储大小信息,现在它可以工作了。如果这是您所指的,并且这是一种强大的工作方式,您能否发表评论?我使用 Long 类型,因为它是一个 4 字节的数据类型来存储 TX 块的位置,这样就可以了。
  • 只要没有一个文本块的大小超过最大整数值,就可以了。
猜你喜欢
  • 1970-01-01
  • 2015-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-31
  • 2015-10-15
相关资源
最近更新 更多