【问题标题】:Original file bytes from StreamReader, magic number detection来自 StreamReader 的原始文件字节,幻数检测
【发布时间】:2013-01-25 16:48:14
【问题描述】:

我试图区分“文本文件”和“二进制”文件,因为我实际上想忽略具有“不可读”内容的文件。

我有一个我认为是 GZIP 存档的文件。我试图通过检测幻数/文件签名来忽略这种文件。如果我在 Notepad++ 中使用十六进制编辑器插件打开文件,我可以看到前三个十六进制代码是 1f 8b 08

但是,如果我使用 StreamReader 读取文件,我不确定如何获取原始字节。..

using (var streamReader = new StreamReader(@"C:\file"))
{
    char[] buffer = new char[10];
    streamReader.Read(buffer, 0, 10);
    var s = new String(buffer);

    byte[] bytes = new byte[6];
    System.Buffer.BlockCopy(s.ToCharArray(), 0, bytes, 0, 6);
    var hex = BitConverter.ToString(bytes);

    var otherhex = BitConverter.ToString(System.Text.Encoding.UTF8.GetBytes(s.ToCharArray()));
}

在 using 语句的末尾,我有以下变量值:

hex: "1F-00-FD-FF-08-00"
otherhex: "1F-EF-BF-BD-08-00-EF-BF-BD-EF-BF-BD-0A-51-02-03"

两者都不以 Notepad++ 中显示的十六进制值开头。

是否可以从StreamReader读取文件的结果中获取原始字节?

【问题讨论】:

  • 只测试字节数组中的字节,你不需要所有字符串的东西
  • 问题是(尽管有上面的例子)我实际上是从一个字符串开始的(我知道它是由 StreamReader 生成的),我希望不必更改字符串的提供方式。 This answer 似乎表明可以从字符串中获取原始字节。我错过了什么?
  • 您在十六进制阅读器中看到的 1F 是 31 转换为 49(x31) ('1') 和 70(x46) 'F' Char(x1f) 是 ascii 美国字符(单位分隔符)一个不可打印的,如 esc 或 bell。因此,如果您在有效地将字符转换为字符后查找字节,则必须查找 Char(x1f) Char(8B) char(8)

标签: c# .net encoding .net-4.0 magic-numbers


【解决方案1】:

你不能。 StreamReader 用于读取文本,而不是二进制。直接使用Stream 读取字节。在你的情况下FileStream

要猜测文件是文本还是二进制文件,您可以将前 4K 读入 byte[] 并解释它。

顺便说一句,您试图将字符强制转换为字节。这在原则上是无效的。我建议您熟悉一下Encoding 是什么:它是唯一以语义正确的方式在字符和字节之间进行转换的方式。

【讨论】:

    【解决方案2】:

    您的代码尝试将二进制缓冲区更改为字符串。字符串在 NET 中是 Unicode,因此需要两个字节。如您所见,结果有点不可预测。

    只需使用 BinaryReader 及其 ReadBytes 方法

    using(FileStream fs = new FileStream(@"C:\file", FileMode.Open, FileAccess.Read))
    {
        using (var reader = new BinaryReader(fs, new ASCIIEncoding()))
        {
            byte[] buffer = new byte[10];
            buffer = reader.ReadBytes(10);
            if(buffer[0] == 31 && buffer[1] == 139 && buffer[2] == 8)
                // you have a signature match....
        }
    }
    

    【讨论】:

      【解决方案3】:

      用法(用于 pdf 文件):

      Assert.AreEqual("25504446", GetMagicNumbers(filePath, 4));
      

      方法 GetMagicNumbers:

      private static string GetMagicNumbers(string filepath, int bytesCount)
      {
          // https://en.wikipedia.org/wiki/List_of_file_signatures
      
          byte[] buffer;
          using (var fs = new FileStream(filepath, FileMode.Open, FileAccess.Read))
          using (var reader = new BinaryReader(fs))
              buffer = reader.ReadBytes(bytesCount);
      
          var hex = BitConverter.ToString(buffer);
          return hex.Replace("-", String.Empty).ToLower();
      }
      

      【讨论】:

        猜你喜欢
        • 2018-01-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-29
        • 1970-01-01
        • 1970-01-01
        • 2011-07-18
        相关资源
        最近更新 更多