【问题标题】:How to import and read large binary file data in c#?如何在 C# 中导入和读取大型二进制文件数据?
【发布时间】:2020-05-29 14:22:42
【问题描述】:

我有一个包含不同数据类型的大型二进制文件,我可以访问文件中的单个记录,但我不确定如何循环二进制值并将其逐字节加载到内存流中

我一直在使用二进制阅读器

BinaryReader binReader = new BinaryReader(File.Open(fileName, FileMode.Open));
            Encoding ascii = Encoding.ASCII;
            string authorName = binReader.ReadString();
            Console.WriteLine(authorName);
            Console.ReadLine();

但这不起作用,因为我有一个包含不同数据类型的大文件 简单地说,我需要将文件转换为逐字节读取,然后读取这些数据(如果它是字符串或其他数据)。

希望有任何可以帮助的想法

【问题讨论】:

  • “循环遍历二进制值并将其逐字节加载到内存流中”是什么意思?您的代码中没有内存流。
  • @the.Doc 如果我知道如何将它加载到内存流中,我就不会问这个问题了!
  • 你还没有告诉我们为什么要将它加载到内存流中?

标签: c# file binaryfiles binary-data


【解决方案1】:

这在很大程度上取决于文件的格式。文件中的每个字节可能代表不同的东西,或者它可能只代表一个大数组中的值,或者两者的混合。

您需要知道格式是什么样子才能读取它,因为二进制文件不是自我描述的。读取一个简单的对象可能看起来像

var authorName = binReader.ReadString();
var publishDate = DateTime.FromBinary(binReader.ReadInt64());
... 

如果您有一个项目列表,通常使用长度前缀。类似的东西

var numItems = binReader.ReadInt32();
for(int i = 0; i < numItems; i++){
    var title = binReader.ReadString();
    ...
}

然后,您通常会根据可在应用程序的其余部分使用的数据创建一个或多个对象。即

new Bibliography(authorName, publishDate , books);

如果这是您无法控制的格式,我希望您有详细的规范。否则,除了最复杂的解决方案之外,这对于任何事情都是一种失败的原因。

如果数据量超出内存容量,则需要某种流式传输机制。 IE。读取一项,对该项进行一些处理,保存结果,读取下一项等。

如果您确实控制格式,我会建议更易于管理的替代方案。我用过protobuf.Net,我觉得它很容易使用,但还有其他选择。使用这类库的常用方法是为数据创建一个类,并为应该存储的字段添加属性。该库可以自动管理序列化/反序列化,并且通常以简单的方式处理继承和格式更改等事情。

【讨论】:

  • 问题是我需要将数据导入到结构中
  • 然后读出每个原语并在您拥有所有数据后创建结构。如果结构中只有原始数据,则可以读出缓冲区和convert the buffer directly you your struct。这可能会快一点,但如果类型包含字符串或数组,则不适用。
  • 你能解释清楚一点吗?
  • 如果你有一个由X、Y、Z组成的结构体,那么ReadSingle() 3次,将结果放入临时变量x、y、z中,然后像new一样创建结构体我的结构(x,y,z)。不知道怎么解释更简单。
  • 如果您有 100 个项目,则在运行 100 次的循环中读取这些项目。我不确定这里有什么问题。
【解决方案2】:

这里有一段简单的代码,展示了最基本的方法。

using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace binary_read
{
    class Program
    {
        private static readonly int bufferSize = 1024;

        static async Task Main(string[] args)
        {
            var bytesRead = 0;
            var totalBytes = 0;

            using (var stream = File.OpenRead(args.First()))
            {
                do
                {
                    var buffer = new byte[bufferSize];
                    bytesRead = await stream.ReadAsync(buffer, 0, bufferSize);
                    totalBytes += bytesRead;

                    // Process buffer

                } while (bytesRead > 0);

                Console.WriteLine($"Processed {totalBytes} bytes.");
            }
        }
    }
}

要注意的主要部分是在 using 块内。

首先,在处理文件/流/套接字时,如果可能的话,最好使用using 确定性地自行清理。

如果您只是在获取原始数据,那么实际上只需在stream 上调用Read/ReadAsync。然而,有各种各样的“阅读器”提供了一种抽象,使使用某些格式变得更容易。

因此,如果您知道要读取整数、双精度数和字符串,那么您可以使用 BinaryReader 和它的 ReadIntxx/ReadDouble/ReadString 方法。

如果您正在读取结构,那么您可以按照上面@JonasH 的建议在循环中读取属性。或者使用this answer中的方法。

【讨论】:

  • 该函数正是我正在寻找的,但是如何从字节数组中读取变量数据?
  • 你能用这个更新问题吗?如果您将结构添加到示例中,它也会非常有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-02
  • 1970-01-01
  • 2014-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多