【问题标题】:Reading and writing two-dimensional array to file读写二维数组到文件
【发布时间】:2021-02-12 10:34:03
【问题描述】:

我以特定时间间隔从设备获取二维数组。我将这些系列放在一个列表中。我需要将列表中的序列写入计算机上的文件。看完这些系列 我会再次将其放入列表中。我找到了一种方法。我可以写系列。我在阅读时有一些问题。

当我写一个固定的数组时;示例short[,] array2D = new short[,] { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };

当我想阅读同一系列知道它的尺寸时,我会正确阅读它。

但是当我连续写多个系列时,我想逐个阅读。我在这方面失败了。如何从文件中读取序列?

编写代码

private void testWriteArray()
    {
        for (int i = 0; i<Globals.logArrayList.Count; i++)
        {
            array2D = Globals.logArrayList[i];

            FileStream writeStream = new FileStream(filename, FileMode.Append);
            BinaryWriter writeBinary = new BinaryWriter(writeStream);
            GCHandle arrHandle = GCHandle.Alloc(array2D, GCHandleType.Pinned);
            IntPtr arrPtr = arrHandle.AddrOfPinnedObject();

            unsafe
            {
                int arrLen = array2D.Length;
                if (arrLen > 0)
                {
                    IEnumerator enumerator = array2D.GetEnumerator();
                    enumerator.MoveNext();
                    int arrSize = System.Runtime.InteropServices.Marshal.SizeOf(enumerator.Current) * arrLen;

                    using (UnmanagedMemoryStream arrStream =
                    new UnmanagedMemoryStream((byte*)arrPtr.ToPointer(), arrSize))
                    {
                        arrStream.CopyTo(writeBinary.BaseStream, (int)arrStream.Length);
                    }
                }
            }

            arrHandle.Free();

            writeStream.Flush();
            writeStream.Close();

        }
    }

阅读代码

   static Array testReadArray()
    {

        int[,] array2D = new int[1000, 2000];

        FileStream readStream = new FileStream(filename, FileMode.Open);
        BinaryWriter readBinary = new BinaryWriter(readStream);
        GCHandle arrHandle = GCHandle.Alloc(array2D, GCHandleType.Pinned);
        IntPtr arrPtr = arrHandle.AddrOfPinnedObject();

        unsafe
        {
            int arrLen = array2D.Length;
            if (arrLen > 0)
            {
                IEnumerator enumerator = array2D.GetEnumerator();
                enumerator.MoveNext();
                int arrSize =
                System.Runtime.InteropServices.Marshal.SizeOf(enumerator.Current) * arrLen;

                using (UnmanagedMemoryStream arrStream = new UnmanagedMemoryStream
                ((byte*)arrPtr.ToPointer(), arrSize, arrSize, FileAccess.Write))
                {
                    readBinary.BaseStream.CopyTo(arrStream, (int)arrStream.Length);
                }
            }
        }

        arrHandle.Free();
        readStream.Close();
        return array2D;
    }

在阅读代码中,我不知道数组在文件中有多少维。这就是我给数组大小 1000,2000 的原因。通常,虽然我的数据在 0-255 之间,但我在阅读时会阅读 6-7 位数字。

我可以知道文件中字符串的数量吗?如果有怎么办?

【问题讨论】:

  • 您可以逐行阅读并从该行中提取数字docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…
  • 阅读时需要能够确定每个块的大小。如果所有块的大小相同,则没有问题。你阅读直到你得到EOF。如果块的大小不同,则需要在每个块之前指定长度或类型,以便确定块的大小。
  • @TobyB :行不适用于二进制数据。二进制的行尾是什么???除非每个二进制数据块都具有唯一的决定性字符,而不是不是数据的一部分,否则您的解决方案将无法工作。
  • 您好,感谢您的cmets。问题很简单,我在下面解释了解决方法。
  • 我在每个数据包的开头和结尾都有一个标头。所以我会这样把我读到的数据分块。

标签: c# arrays binaryfiles


【解决方案1】:

这并不是真正的答案,而是向您展示另一种方法,因为您使用的是 unsafe 并且知道数组的大小和维度。所以我给你一个最小分配,基于通用指针跨度的常量多维多数组读写器

给定

public static unsafe void Write<T>(T[,] source, Stream stream) where T : unmanaged
{
   fixed (void* asd = source)
      stream.Write(new Span<byte>(asd, source.Length * sizeof(T)));
}
public static unsafe bool Read<T>(T[,] source, Stream stream) where T : unmanaged
{
   fixed (void* asd = source)
      return stream.Read(new Span<byte>(asd, source.Length * sizeof(T))) != 0;
}

世界上最人为的例子

var array = new short[,] {{1, 2,}, {3, 4}, {5, 6}};

using (var rs = new FileStream(@"D:\test.dat", FileMode.Create))
   for (int i = 0; i < 10; i++)
   {
      array[0, 0] = (short) i; // to prove its working
      Write(array, rs);
      Console.WriteLine(string.Join(", ", array.Cast<short>()));
   }

Console.WriteLine();

using (var ws = new FileStream(@"D:\test.dat", FileMode.Open))
   while (Read(array, ws))
      Console.WriteLine(string.Join(", ", array.Cast<short>())); // to prove its working

输出

0, 2, 3, 4, 5, 6
1, 2, 3, 4, 5, 6
2, 2, 3, 4, 5, 6
3, 2, 3, 4, 5, 6
4, 2, 3, 4, 5, 6
5, 2, 3, 4, 5, 6
6, 2, 3, 4, 5, 6
7, 2, 3, 4, 5, 6
8, 2, 3, 4, 5, 6
9, 2, 3, 4, 5, 6

0, 2, 3, 4, 5, 6
1, 2, 3, 4, 5, 6
2, 2, 3, 4, 5, 6
3, 2, 3, 4, 5, 6
4, 2, 3, 4, 5, 6
5, 2, 3, 4, 5, 6
6, 2, 3, 4, 5, 6
7, 2, 3, 4, 5, 6
8, 2, 3, 4, 5, 6
9, 2, 3, 4, 5, 6

注意:你可以修改它来创建和返回一个数组。然而这只是一个可以重用数组的低分配版本

注意:如果只在数组前写2个整数,则可以读取任意大小的数组和任意数量的数据包

【讨论】:

  • 感谢您的宝贵时间。我收到命令 new Span 缺少参考错误。你能指出我应该包括哪个参考吗?
  • @saklanmaz 您似乎还停留在过去,使用 .net 框架 :) 升级到 core 或 .net5
  • 不幸的是:)。由于该项目是一个老项目,我担心升级可能会出现不同的问题。但是,我会尝试分享一个空项目。我将其标记为花时间的答案。虽然我的解决方案不是很健康,但它可以在初始阶段工作。遇到此类问题的朋友可以两者兼顾。 :)
【解决方案2】:

这个问题太简单了,我不知道我是怎么错过的。我在读取时定义的数组类型是integer,但我的数据是short。当数组的数据类型为short 时,整个问题就消失了。

我还解决了文件中的序列总数如下。

在写的时候二维数组的长度是48 * 64。我把文件中的总字节数除以48 * 64。另外,由于我的数据是short(2 bytes)我将它除以 2 得到字符串的总数。

var arrayCount = readBinary.BaseStream.Length / (48*64) / 2;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-23
    • 2019-10-16
    • 2018-03-08
    • 2014-04-15
    • 2013-03-11
    相关资源
    最近更新 更多