【问题标题】:Understanding the Size of Byte Arrays了解字节数组的大小
【发布时间】:2020-12-04 10:53:04
【问题描述】:

我正在阅读这个流行的堆栈溢出问题 Creating a byte array from a stream,并希望了解字节数组的工作原理。

在这段代码中:

 byte[] buffer = new byte[16 * 1024];
            using (MemoryStream ms = new MemoryStream())
            {
                int read;
                while ((read = PictureStream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    ms.Write(buffer, 0, read);
                }

                return ms.ToArray();
            }

以下是我不明白的地方:

我迷失了这个数组设置的大小。例如,我使用该代码块将图像流转换为字节数组,但我通常读取大于 2 兆字节的图像,这远大于图片中读取的数组的大小 - 16* 1024 字节。但是,上面的代码完全可以将图像从流转换为字节数组,不会出现“超出范围索引”错误。

那么我的数组怎么比我正在阅读的照片更小,但仍然可以完全正常地阅读呢?

【问题讨论】:

  • 它以块的形式读取和写入它——它被称为流式传输。读取缓冲区满,然后写入缓冲区,然后重复,直到传输完所有数据。
  • 我明白了。我将不得不阅读更多关于流媒体的内容。你如何确定字节数组的大小?为什么是 16 * 1024,而不是其他数字?
  • 这有点武断——一次一个字节意味着它真的很慢,但一次 1 GB 会浪费大量内存。 16K 只是一个合理的缓冲区大小。

标签: c# arrays byte buffer


【解决方案1】:

正如 cmets 中已经提到的。 图片流的read函数只读取了一块数据, 实际上正是传输缓冲区的数量。 我们读取这个数量,然后将其从传输缓冲区写入输出流。

我尝试编写一些代码片段来演示发生了什么:

    int inputBufferSizeInByte = 1024 * 1000 * 5;  // 5 MiB = 5000 KiB
    //                    AmountKiloByte * factor MiB * factorWhatWeWant
    Byte[] inputBuffer = new Byte[inputBufferSizeInByte];
    //we fill our inputBuffer with random numbers
    Random rnd = new Random();
    rnd.NextBytes(inputBuffer);

    //we define our streams
    MemoryStream inputMemoryStream = new MemoryStream(inputBuffer);
    MemoryStream outPutMemoryStream = new MemoryStream();

    //we define a smaller buffer for reading
    int transportBufferSizeInByte = 1024 * 16; // 16 KiB
    byte[] transportBufferFor = new byte[transportBufferSizeInByte]; 

    int amountTotalWeReadInByte = 0;
    int tempReadAmountInByte = 0;
    int callWriteCounter = 0;
    do
    {
        tempReadAmountInByte = inputMemoryStream.Read(transportBufferFor, 0, transportBufferSizeInByte);

        //we write what we got to the output
        if(tempReadAmountInByte>0)
        {
            outPutMemoryStream.Write(transportBufferFor, 0, tempReadAmountInByte);
            callWriteCounter++;
        }

        //we calc how the total amout
        amountTotalWeReadInByte += tempReadAmountInByte;

    } while (tempReadAmountInByte > 0);

    //we sum up 
    Console.WriteLine("input buffer size:   \t" + inputBufferSizeInByte + " \t in Byte");
    Console.WriteLine("total amount read   \t" + amountTotalWeReadInByte  + " \t in Byte");
    Console.WriteLine("output stream size: \t" + outPutMemoryStream.Length + " \t in Byte");
    Console.WriteLine("called strean write \t" + callWriteCounter + "\t\t times");

输出:

input buffer size:      5120000      in Byte
total amount read       5120000      in Byte
output stream size:     5120000      in Byte
called strean write     313      times

所以我们调用了 313 次流写入函数,一切都正常运行。

这让我想到了关键问题:

为什么内存和硬盘的图片大小有差异?

我确实认为图片编码是原因。

一张图片在硬盘上的大小和它的内存表示的区别属于经常 到图片编码。我通过使用 cpp 库 opencv 知道这一事实。 我宁愿猜测 c# 实现的行为类似。

查看有关此主题的一些问答: 【问题】:JPEG image memory byte size from OpenCV imread doesn't seem right

【讨论】:

    【解决方案2】:

    您传递的数组只是一个缓冲区。当您从流中读取时,它会返回读取的字节数并用那么多元素填充缓冲区数组(它并不总是完全填充)。然后你将那么多字节写入内存流。重复这个过程,直到没有更多字节可以从文件中读取。

    您会注意到ToArray 生成的数组远大于您的缓冲区大小。

    【讨论】:

      猜你喜欢
      • 2019-11-02
      • 1970-01-01
      • 1970-01-01
      • 2017-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-21
      • 1970-01-01
      相关资源
      最近更新 更多