大字节[]的优化

本文关键字:优化 字节 | 更新日期: 2023-09-27 18:11:52

我有5MB字节[],我以2k的块写入磁盘。要获取2k (c_writeSizeInBytes)的内存,我可以这样做:

int numberOfIterations = bytes.Length / c_writeSizeInBytes;
                    for (int i = 0; i < numberOfIterations; i++)
                    {
                        bool nearEnd = bytes.Length - i == c_writeSizeInBytes;
                        byte[] buffer = nearEnd ? bytes.Skip(i * c_writeSizeInBytes).ToArray() : bytes.Skip(i * c_writeSizeInBytes).Take(c_writeSizeInBytes).ToArray();
                        binaryWriter.Write(buffer, 0, c_writeSizeInBytes);
                    }

2mb文件后5MB文件的性能非常慢。有什么方法可以优化它吗?

谢谢

大字节[]的优化

您在这里使用Skip/Take/ToArray是非常低效的。如果写入块,那么您应该将偏移量传递给Write,即

binaryWriter.Write(buffer, i * CHUNK_SIZE, CHUNK_SIZE);

(可能在最后一个块中使用一些Math.Min来获取剩余的计数,以防它不是完整的块数)

但是,如果您已经将数据作为byte[],则不需要这样做-只需对Write进行一次调用。

binaryWriter.Write(buffer, 0, buffer.Length);

如果您正在编写整个文件(即此数据替换旧数据,如果有的话),则只需使用File.WriteAllBytes

我会这样写:

byte[] input;
using(var inStream = new MemoryStream(input))
using(var outStream = File.OpenWrite("c:''file.dat"))
{
    inStream.CopyTo(outStream, 2048);
}

啊,这里出现了Schlemiel the Painter的情况。for循环涉及一次查找字节数组中的一个元素(通过. skip()),并且每次迭代都会在数组中走得更远一些,因此,完成每次for循环迭代所花费的时间越来越长,迭代次数越多。

既然已经有了字节数组,为什么还需要缓冲区呢?您可以直接从现有数组写入二进制流:

int offset = 0, lastFullWriteIndex = bytes.Length - c_writeSizeInBytes;
while (offset < lastFullWriteIndex)
{
    binaryWriter.Write(bytes, offset, c_writeSizeInBytes);
    offset += c_writeSizeInBytes;
}
binaryWriter.Write(bytes, offset, bytes.Length - offset);

这不仅消除了连续遍历越来越多的数组所带来的减速效应,而且还消除了将字节复制到缓冲区的额外工作。

不知道你有什么约束迫使你只写2k块大小但如果你一定要这样做,那就试试这个方法

  public void Write(Byte[] bytes,System.IO.Stream stream)
    {
        int chunkSize = 2 * 1024; //2k
        int offset = 0;
        do
        {
            var count = offset + chunkSize > bytes.Length ? bytes.Length - offset : chunkSize;
            stream.Write(bytes, offset, count);
            offset += count;
        } while (offset < bytes.Length);
    }

好的,如果你想自己滚动(没有必要),这是一种方法。

const int BufferSize = 2000
for (int left = bytes.Length; left > 0; left -= BufferSize)
{
    if (left < BufferSize)
    {
        binaryWriter.Write(byte, bytes.length - left, left);
        break;
    }
    binaryWriter.Write(byte, bytes.length - left, BufferSize);
}