【问题标题】:Reading file A and appending to file B, skipping some bytes读取文件 A 并附加到文件 B,跳过一些字节
【发布时间】:2013-03-27 12:52:45
【问题描述】:

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

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

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

【问题讨论】:

  • >如何在不使用所有内存的情况下读取每个 BMP 并将它们附加到最终文件?流式传输文件。

标签: c# arrays byte filestream


【解决方案1】:

您可以写入文件中的任意位置。也就是说:

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 是一个 long 值,因此您不必担心会碰到 32 位整数的限制。

幸运的是,由于您的图像基本上只是一堆高大的图块,因此您不必担心处理每一行。在这种情况下,为了减少内存,您必须单独写出每个图块的行。

【讨论】:

  • 我的回复有帮助吗?如果是这样,我们将不胜感激!
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    如果我之后的任何人感兴趣,这就是我发现的工作:

    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 的缓冲区。如果我想减少硬盘查找,使用不同的大小会更好吗?我的驱动器最近进行了碎片整理。感谢大家的帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-26
      • 2012-04-16
      相关资源
      最近更新 更多