读取文件A并附加到文件B,跳过一些字节

时间:2013-03-27 12:52:46

标签: c# arrays byte filestream

我需要在一起添加一些BMP图像。您可能知道,BMP图像有一个54字节的标题。我将自己的新标题写入一个新文件,然后我需要遍历一个BMP文件列表并将它们相互附加,但我需要跳过每个文件的前54个字节。

这适用于千兆像素图像拼接项目。我会使用已经存在的软件,除了图像中没有重叠(但我知道图块布局)。我需要能够将一些非常大的BMP文件(192,000x1080)作为行接收并将它们一个接一个地附加到另一个以创建最终图像,即20.7千兆像素。虽然我有32GB的内存,但最终的20.7千兆像素图像将是62.2GB(我将转换为PNG)。

鉴于这些巨大的内存要求,我如何阅读每个BMP并将它们附加到最终文件而不使用我的所有内存?我想尽可能使用字节数组;因为这些是无压缩的BMP,它们可以像这样读取并保存到另一个文件而不使用任何GDI对象。

3 个答案:

答案 0 :(得分:4)

您可以写入文件中的任意位置。即:

using(var s = new FileStream("myBigImage.bmp", FileMode.Create, FileAccess.Write)) {
    //assume that you write out the header here
    foreach(var tileFile in tiles) {
        byte[] imgData = /*read image data into a byte[]*/;
        long y = /*obtain the correct y offset*/;

        s.Position = y * pixelWidth * imageWidth + 58;
        s.Write(imgData, 0, imgData.Length);

    }
}

基本上,您可以跳转文件以填写您想要的任何位置。 Position是一个长值,因此您不必担心会遇到32位整数的限制。

幸运的是,因为你的图像基本上只是一堆高的瓷砖,所以你不必担心处理每一行。在这种情况下,为了减少内存,你必须分别写出每个tile的行。

答案 1 :(得分:1)

您无需将所有生成的文件数据保存在内存中。只需打开FileStream并将数据写入文件即可。即使你写了数千兆字节的数据,FileStream也不会占用太多内存。

答案 2 :(得分:0)

如果有人跟我有兴趣,这就是我发现的工作:

for (int i = 0; i < reverseImageFiles.Length; i++)
        {
            string curBMP = reverseImageFiles[i];

            using(Stream inStream = File.OpenRead(curBMP))
            using (Stream writeStream = new FileStream(outputBMP,FileMode.Append,FileAccess.Write,FileShare.None))
            {
                BinaryReader reader = new BinaryReader(inStream);
                BinaryWriter writer = new BinaryWriter(writeStream);

                byte[] buffer = new Byte[134217728];
                int bytesRead;
                int totalBytes = 0;

                while ((bytesRead = inStream.Read(buffer, 0, 134217728)) > 0)
                {
                    totalBytes += bytesRead;

                    if (totalBytes <= 134217729)  //if it's the first round of reading to the buffer, you need to get rid of 54-byte BMP header
                    {
                        writeStream.Write(buffer, 54, bytesRead - 54);
                    }
                    else
                    {
                        writeStream.Write(buffer, 0, bytesRead);
                    }
                }

            }
        }

两件事:

特别是对于BMP,我发现你需要在追加时反转文件列表。例如,如果要追加的三个文件标记为001.bmp,002.bmp,003.bmp,其中001.bmp应位于顶部,则需要实际以003.bmp开始并向下运行。显然,BMP是向后编码的。

如您所见,我使用了128MB缓冲区。如果我想减少寻求硬盘驱动器,那么使用不同尺寸会更好吗?我的驱动器最近被碎片整理。谢谢你的帮助!