【问题标题】:Read small binary file, Out of memory exception读取小二进制文件,内存不足异常
【发布时间】:2013-10-28 18:51:27
【问题描述】:

我正在将一个小的二进制文件(大约 32mb)逐字节读取到数据表中,并将前 8 个字节从十六进制转换为二进制。

对于大文件,我遇到系统内存不足异常错误消息,我想不出如何改进我的代码以更流畅或更快地运行。

这是我的代码:

Public Function DecToBin(ByVal DeciValue As Long, Optional ByVal NoOfBits As Integer = 8) As String
    Dim i As Integer
    Do While DeciValue > (2 ^ NoOfBits) - 1
        NoOfBits = NoOfBits + 8
    Loop
    DecToBin = vbNullString
    For i = 0 To (NoOfBits - 1)
        DecToBin = CStr((DeciValue And 2 ^ i) / 2 ^ i) & DecToBin
    Next i
End Function

Private Sub importData(ByVal openFile As String)
    If fullFilePath.EndsWith("variable.dat") Then
        Dim importedData As New DataTable
        Cursor.Current = Cursors.WaitCursor
        Using reader As New BinaryReader(File.Open(openFile, FileMode.Open))
            Dim pos As Integer = 0
            Dim length As Integer = reader.BaseStream.Length
            loadingBar.loadingLabel.Text = "Lines of data: " & length

            loadingBar.loadingProgress.Minimum = 0
            loadingBar.loadingProgress.Maximum = length
            loadingBar.loadingProgress.Step = 1

            importedData.Columns.Add("Data0")
            importedData.Columns.Add("Data1")
            importedData.Columns.Add("Data2")
            importedData.Columns.Add("Data3")
            importedData.Columns.Add("Data4")
            importedData.Columns.Add("Data5")
            importedData.Columns.Add("Data6")
            importedData.Columns.Add("Data7")

            importedData.Columns.Add("Time")
            importedData.Columns.Add("Date")

            importedData.Columns.Add("Day")
            importedData.Columns.Add("Month")
            importedData.Columns.Add("Year")

            importedData.Columns.Add("Blank")

            While pos < length

                For i = 0 To 15
                    Dim value As Decimal = reader.ReadByte
                    rawDataArray(i) = value.ToString()
                    pos += 1
                Next

                loadingBar.BringToFront()
                loadingBar.Show()
                Cursor.Current = Cursors.WaitCursor

                loadingBar.loadingProgress.Value = pos


                convertedDataArray(0) = DecToBin(rawDataArray(0))
                convertedDataArray(1) = DecToBin(rawDataArray(1))
                convertedDataArray(2) = DecToBin(rawDataArray(2))
                convertedDataArray(3) = DecToBin(rawDataArray(3))
                convertedDataArray(4) = DecToBin(rawDataArray(4))
                convertedDataArray(5) = DecToBin(rawDataArray(5))
                convertedDataArray(6) = DecToBin(rawDataArray(6))
                convertedDataArray(7) = DecToBin(rawDataArray(7))

                convertedDataArray(8) = Format((rawDataArray(12) + 0), "00") & ":" & Format((rawDataArray(11) + 0), "00") & ":" & Format((rawDataArray(10) + 0), "00") & "." & Format((rawDataArray(8) * 256) + rawDataArray(9), "000")
                convertedDataArray(9) = Format((rawDataArray(13) + 0), "00") & "." & Format((rawDataArray(14) + 0), "00") & "." & "20" & Format((rawDataArray(15) + 0), "00")

                convertedDataArray(10) = Format((rawDataArray(13) + 0), "00")
                convertedDataArray(11) = Format((rawDataArray(14) + 0), "00")
                convertedDataArray(12) = Format((rawDataArray(15) + 0), "00")

                importedData.Rows.Add(convertedDataArray)
                Application.DoEvents()
            End While
            loadingBar.Close()
            importedData.DefaultView.Sort = "Year,Month,Day,Time"
            dataGrid.DataSource = importedData.DefaultView
        End Using
        dataGrid.Columns(0).Visible = False ' Data 0
        dataGrid.Columns(1).Visible = False ' Data 1
        dataGrid.Columns(2).Visible = False ' Data 2
        dataGrid.Columns(3).Visible = False ' Data 3
        dataGrid.Columns(4).Visible = False ' Data 4
        dataGrid.Columns(5).Visible = False ' Data 5
        dataGrid.Columns(6).Visible = False ' Data 6
        dataGrid.Columns(7).Visible = False ' Data 7
        dataGrid.Columns(8).Visible = True ' Data Time
        dataGrid.Columns(9).Visible = True ' Data Date
        dataGrid.Columns(10).Visible = False ' Data Day
        dataGrid.Columns(11).Visible = False ' Data Month
        dataGrid.Columns(12).Visible = False ' Data Year
        dataGrid.Columns(13).Visible = False ' Data Blank

    Else
        MsgBox("Wrong file selected")
    End If
End Sub

正在读取的数据示例:

3F F3 45 C6 03 00 11 00 00 6F 1F 1D 16 12 07 0D

输出示例:

00111111 11110011 01000101 11000110 00000011 00000000 00010001 00000000 22:29:31.111 18.07.2013 18 07 13

【问题讨论】:

  • 问题属于codereview
  • @peer 我不知道怎么做;它询问一个特定的问题 - OOM 处理什么是,尽管 OP 的描述,一个 small 文件
  • 你为什么要做所有ToString() / DecToBin 的事情? ReadByte() 已经返回一个byte(具体来说,它返回一个int,它对于EOF 来说是负数,或者在0-255 的范围内 - 它只需要被转换为byte 并且:工作完成):您是否有一些示例输入/输出来说明您正在尝试做什么?因为它看起来很像你在中间发明工作......另外:convertedDataArray 的类型是什么? (未显示)
  • 我做了 DecToBin 的事情,将 HEX 值转换为 01101001 等形式的二进制字节,而 ToString() 的东西是获取文件的单独部分并将它们连接在一起以创建时间和文件中的日期。
  • 编辑了第一篇文章以显示输入和输出示例

标签: .net vb.net binary


【解决方案1】:

获取System.OutOfMemoryException 意味着没有可用的所需大小的未分配内存的单个连续 区域。这并不一定意味着你已经没有记忆了,而是记忆碎片太多了。

解决问题的一种方法可能是使用MemoryMappedFile 类(顾名思义),它会将进程的部分虚拟内存映射到硬盘上的数据。

您可以尝试处理此问题的另一种方法是调用GC.Collect,它将压缩内存作为垃圾收集过程的一部分。虽然,我强烈反对使用这种方法。

您可以使用ANTS Memory Profiler 或windbg(作为Windows SDK 的一部分提供)来查看您的内存在哪里使用。

至于您的代码,您似乎没有任何可疑之处(除了 Marc Gravell 已经指出的DecToBin)。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2012-11-05
    • 1970-01-01
    • 1970-01-01
    • 2014-07-22
    • 1970-01-01
    • 1970-01-01
    • 2013-10-06
    • 1970-01-01
    • 2017-10-18
    相关资源
    最近更新 更多