将从.bin文件读取的数据解码为字段

时间:2013-12-03 11:37:54

标签: c# arrays visual-studio-2008 struct .net-3.5

我原本打算通过数组读取文件,pin到struct,转换和显示。我一直试图找到另一个解决方案(我已经删除了原来的细节,以减少混淆)。我有一个.bin文件,我可以通过使用简单的和和 FileInfo 来正确识别文件中有多少条记录。

我看过:

导入的文件具有相同的结构,看起来类似于以下内容:_(注意截图显示文件中的行数,然后我使用此处生成的Adding rows to second column ONLY - populating data using a for loop的总和来计算DataGridView表的行数:

long Count = 1;
FileInfo Fi = new FileInfo(import.FileName);
long sum = (Fi.Length / 1024) - Count;

for (int i = 0; i < sum; i++)
{
    DataGridView1.Rows.Add(null, Count++);
    ReadWeldRecs(sum); // Added after question was published & called in ReadWeldRecs
}

首先显示总共21行,第二行显示为9:

enter image description here enter image description here


我有一个名为 DecodeDate 的方法,另一个名为 ReadWeldRecs DecodeDate 通过 ReadWeldRecs 提供,然后是通过按钮点击事件激活。我知道应该显示什么日期,但是当从DecodeDate查看结果时,它是错误的。 我希望能够读取文件中的日期。 import.FileName 是使用<打开的文件名(@Kevin) em> OpenFileDialog ,日期显示在文件的第5位。

我的第一次去:

日期显示为: 22/08/2123

但应该是: 21/10/2008

我想过,可能是位置问题?但我确定它的位置是5.

更新:原来我看错了位置...... Duh。

private DateTime DecodeDate(int Start)
{
    int Year = Strings.Asc(Strings.Mid(import.FileName, Start, 1)) + 2000;
    int Month = Strings.Asc(Strings.Mid(import.FileName, Start + 1, 1));
    int Day = Strings.Asc(Strings.Mid(import.FileName, Start + 2, 1));

    return DateAndTime.DateSerial(Year, Month, Day);
}

原件:

这是原始的VB 代码,它在过时的程序中运行良好:(我主要是为了在C#中重构DecodeDate方法......)

Public Function DecodeDate(Start As Integer) As Date
    YYear = Asc(Mid$(ImportRecord, Start, 1)) + 2000
    MMonth = Asc(Mid$(ImportRecord, Start + 1, 1))
    DDay = Asc(Mid$(ImportRecord, Start + 2, 1))
    DecodeDate = DateSerial(YYear, MMonth, DDay)
End Function

ImportRecord定义如下:(全局字符串)

Open ImportFileName For Random As #1 Len = Len(ImportRecord)
// ...
Get #1, Index + 1, ImportRecord
// ...
.Date = DecodeDate(5) 

电流:

private void ReadWeldRecs(long RecordNumber)
{
    byte[] Rec = new byte[1024];

    using (FileStream Fs = new FileStream(import.FileName, FileMode.Open, FileAccess.Read))
    using (BinaryReader Br = new BinaryReader(Fs))
    {
        int Rec_Len;

        RecordNumber = 0; // Start with Record 0
        while (true)
        {
            Fs.Seek(RecordNumber * 1024, SeekOrigin.Begin); // Position file to record
            Rec_Len = Br.Read(Rec, 0, 1024); // Read the record here

            if (Rec_Len == 0) // If reached end of file, end loop
            {
                break;
            }

            if (Rec[0] != 0) // If there is a record, let's display it
            {
                Label_Date1.Text = DecodeDate(Rec, 28).ToShortDateString();
            }

            RecordNumber++; // Read first record ++
        }

        Br.Close();
        Fs.Close();
    }
}

Plus @ Kevin的更新解决方案:)


然而,这也解决了一个主要问题,我还在另一个问题,我试图通过我的其他方法 DecodeString 的@Kevin解决方案的指南和模板。

在VB中:

Public Function DecodeString(Start As Integer, Length As Integer) As String
Dim Count As Integer
Dummy = Mid(ImportRecord, Start, Length)
For Count = 1 To Len(Dummy)
  If (Mid$(Dummy, Count, 1) = Chr$(0)) Or (Mid$(Dummy, Count, 1) = Chr$(255)) Then
    Mid$(Dummy, Count, 1) = Chr$(32)
  End If
Next
DecodeString = Trim(Dummy)
End Function

再次注意,我正在考虑将此解决方案用作此模板

1 个答案:

答案 0 :(得分:2)

有几件事......

  1. 你正在寻找这个C#或VB,因为它被标记为C#但是Strings和DateAndTime是VB。
  2. 您只是从文件名字符串解析日期吗?
  3. 日期值是否真的表示为字符的 ASCII 值?真?这似乎非常奇怪...这意味着要获得年份= 8,月份= 10,日期= 20,您的文件名将类似于abcde [BackspaceCharacter] [LinefeedCharacter] [设备控制4]。我绝对不认为你有控制字符,除非它当然是首先填充到字符串中的二进制数据。
  4. 我将假设这些问题的答案是...... C#,是和否。很容易从C#转换 - &gt; VB,如果这是一个不正确的假设。我不认为我在这里使用过任何特定于C#的东西。请注意,为了便于阅读,我已将其分为几行。

    private DateTime DecodeDate(int Start)
    {
        // If your filename is 'ABC-01234 2008-10-21@012345.bin' then Start should = 10
        DateTime date;
        var datePart = filename.Substring(Start, 10);
        var culture = CultureInfo.InvariantCulture;
        var style = DateTimeStyles.None;
        // note since you are telling it the specific format of your date string
        // the culture info is not relevant.  Also note that "yyyy-MM-dd" below can be
        // changed to fit your parsing needs yyyy = 4 digit year, MM = 2 digit month
        // and dd = 2 digit day.
        if (!DateTime.TryParseExact(datePart, "yyyy-MM-dd", culture, style, out date))
        {
            // TryParseExact returns false if it couldn't parse the date.
            // Since it failed to properly parse the date... do something 
            // here like throw an exception.
            throw new Exception("Unable to parse the date!");
        }
        return date;
    }
    

    查找DateAndTime之后,如果文件名中没有控制字符,您可以通过另一种方式获取所看到的数字...但在这种情况下,我仍然认为您不想使用DateAndTime.DateSerial,因为它只会混淆错误。 (如果你不小心给它月份25它返回的日期是月份的1月份,并且每年增加2年)

    如果这不能解决它...给出你的文件名格式,这将更容易弄清楚究竟是什么问题。

    编辑:根据您的更新...看起来您正在尝试解析二进制数据......

    使用BinaryReader上的.NET框架方法(如BinaryReader.ReadByte,.ReadDouble等)更简单的方法。

    对于您的代码,虽然您需要传入字节数组,以便可以从中提取值。你希望限制或消除全局变量使用的风格......

    private DateTime DecodeDate(byte[] bytes, int start)
    {
        // Note that Length is 1 based and the indexer is 0 based so 
        if (bytes.Length < start + 3)
            throw new Exception("Byte array wasn't long enough");
        int year = Convert.ToInt32(bytes[start]) + 2000;
        int month = Convert.ToInt32(bytes[start+1]);
        int day = Convert.ToInt32(bytes[start+2]);
    
        return new DateTime(year, month, day);
    }
    

    然后你对它的调用看起来像这样......

    Label_Date1.Text = DecodeDate(Rec, 5).ToShortDateString();
    

    我想提一些风格指针...这些都是个人偏好,但我觉得它们很有帮助。

    1. 不要使用全局变量或严格限制它们的使用 - import在您的方法中使用,但在其他地方定义 - 这使您更难看到您的代码正在做什么,并且让您无法使用它。
    2. 命名以lowerCase开头的局部变量,以便更容易看到什么是方法,什么是变量。
    3. While(true)非常小心 - 如果你可以重新编写它以便在退出循环时更清楚,那就更好了。
    4. 还有一件事!你说你的日期是在第5位。在VB数组中,通常从1开始,所以第5个元素是数组索引5 ...在C#数组中以0开始,所以第5个元素将是索引4.我不知道你应该从你的代码中检查哪些,因为我不知道数据的结构所以请记住这一点。

      编辑2: 对于DecodeString来说,它既简单又难...代码非常简单......但是......字符串比你想象的要复杂得多。要从字符串转换为二进制或反之,您必须选择编码。编码是用于将字符转换为二进制数据的算法。他们的名字对你来说很熟悉,如ASCII,UTF8,Unicode等。问题的一部分是某些编程语言会混淆你的编码,而且很多时候程序员可能会对它们一无所知。在你的情况下,似乎你的二进制文件是用ASCII编写的,但是我不可能知道...所以我的代码如果在ASCII中是有效的...如果遇到你的字符串没有正确解码的情况你可能要改变它。

      private static string DecodeString(byte[] bytes, int start, int length)
      {
          return Encoding.ASCII.GetString(bytes, start, length);
      }
      

      奖金阅读 - Joel Spolsky's post on Encodings