在二进制文件中间插入字节

发布于 2024-11-06 15:53:31 字数 308 浏览 5 评论 0原文

我想在图像元数据块的中间添加一些字符串。在一些特定的标记下。我必须在字节级别上执行此操作,因为 .NET 不支持自定义元数据字段。

该块的构建方式类似于 1C 02 XX YY YY ZZ ZZ ZZ ...,其中 XX 是我需要附加的字段的 ID,YY YY 是它的大小,ZZ = 数据。

我想应该或多或少有可能读取直到该标记(1C 02 XX)的所有图像数据,然后增加大小字节(YY YY),在ZZ末尾添加数据,然后添加原始文件的其余部分?这是正确的吗?

我该怎么继续呢?它需要尽可能快地处理 4-5 MB JPEG 文件。

I want to add some string in the middle of image metadata block. Under some specific marker. I have to do it on bytes level since .NET has no support for custom metadata fields.

The block is built like 1C 02 XX YY YY ZZ ZZ ZZ ... where XX is the ID of the field I need to append and YY YY is the size of it, ZZ = data.

I imagine it should be more or less possible to read all the image data up to this marker (1C 02 XX) then increase the size bytes (YY YY), add data at the end of ZZ and then add the rest of the original file? Is this correct?

How should I go on with it? It needs to work as fast as possible with 4-5 MB JPEG files.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

入怼 2024-11-13 15:53:31

一般来说,没有办法加速此操作。您必须至少读取需要移动的部分并将其再次写入更新的文件中。如果可以并行读取和写入操作,创建新文件并将内容复制到其中可能会更快。

注意:在您的特定情况下,可能无法仅在文件中间插入内容,因为大多数文件格式在设计时并未考虑到此类修改。通常,当您移动文件的一部分时,文件的某些部分的偏移量将无效。指定您尝试使用的文件格式可能会帮助其他人提供更好的方法。

In general there is no way to speed up this operation. You have to read at least portion that needs to be moved and write it again in updated file. Creating new file and copying content to it may be faster if you can parallelize read and write operations.

Note: In you particular case it may not be possible to just insert content in the middle of the file as most of file formats are not designed with such modifcations in mind. Often there are offsets to portions of the file that will be invalid when you shift part of the file. Specifying what file format you trying to work with may help other people to provide better approaches.

堇色安年 2024-11-13 15:53:31

用这段代码解决了这个问题:

            List<byte> dataNew = new List<byte>();
            byte[] data = File.ReadAllBytes(jpegFilePath);

            int j = 0;
            for (int i = 1; i < data.Length; i++)
            {
                if (data[i - 1] == (byte)0x1C) // 1C IPTC
                {
                    if (data[i] == (byte)0x02) // 02 IPTC
                    {
                        if (data[i + 1] == (byte)fileByte) // IPTC field_number, i.e. 0x78 = IPTC_120
                        {
                            j = i;
                            break;
                        }
                    }
                }
            }

            for (int i = 0; i < j + 2; i++) // add data from file before this field
                dataNew.Add(data[i]); 

            int countOld = (data[j + 2] & 255) << 8 | (data[j + 3] & 255); // curr field length
            int countNew = valueToAdd.Length; // new string length
            int newfullSize = countOld + countNew; // sum
            byte[] newSize = BitConverter.GetBytes((Int16)newfullSize); // Int16 on 2 bytes (to use 2 bytes as size)
            Array.Reverse(newSize); // changes order 10 00 to 00 10
            for (int i = 0; i < newSize.Length; i++) // add changed size
                dataNew.Add(newSize[i]);

            for (int i = j + 4; i < j + 4 + countOld; i++) // add old field value
                dataNew.Add(data[i]);

            byte[] newString = ASCIIEncoding.ASCII.GetBytes(valueToAdd);
            for (int i = 0; i < newString.Length; i++) // append with new field value
                dataNew.Add(newString[i]);

            for (int i = j + 4 + newfullSize; i < data.Length; i++) // add rest of the file
                dataNew.Add(data[i]);

            byte[] finalArray = dataNew.ToArray();
            File.WriteAllBytes(Path.Combine(Path.GetDirectoryName(jpegFilePath), "newfile.jpg"), finalArray);                

Solved the problem with this code:

            List<byte> dataNew = new List<byte>();
            byte[] data = File.ReadAllBytes(jpegFilePath);

            int j = 0;
            for (int i = 1; i < data.Length; i++)
            {
                if (data[i - 1] == (byte)0x1C) // 1C IPTC
                {
                    if (data[i] == (byte)0x02) // 02 IPTC
                    {
                        if (data[i + 1] == (byte)fileByte) // IPTC field_number, i.e. 0x78 = IPTC_120
                        {
                            j = i;
                            break;
                        }
                    }
                }
            }

            for (int i = 0; i < j + 2; i++) // add data from file before this field
                dataNew.Add(data[i]); 

            int countOld = (data[j + 2] & 255) << 8 | (data[j + 3] & 255); // curr field length
            int countNew = valueToAdd.Length; // new string length
            int newfullSize = countOld + countNew; // sum
            byte[] newSize = BitConverter.GetBytes((Int16)newfullSize); // Int16 on 2 bytes (to use 2 bytes as size)
            Array.Reverse(newSize); // changes order 10 00 to 00 10
            for (int i = 0; i < newSize.Length; i++) // add changed size
                dataNew.Add(newSize[i]);

            for (int i = j + 4; i < j + 4 + countOld; i++) // add old field value
                dataNew.Add(data[i]);

            byte[] newString = ASCIIEncoding.ASCII.GetBytes(valueToAdd);
            for (int i = 0; i < newString.Length; i++) // append with new field value
                dataNew.Add(newString[i]);

            for (int i = j + 4 + newfullSize; i < data.Length; i++) // add rest of the file
                dataNew.Add(data[i]);

            byte[] finalArray = dataNew.ToArray();
            File.WriteAllBytes(Path.Combine(Path.GetDirectoryName(jpegFilePath), "newfile.jpg"), finalArray);                
嘿嘿嘿 2024-11-13 15:53:31

这是一个简单且相当快速的解决方案。它根据给定的 extraBytes 将给定偏移量后的所有字节移动到新位置,以便您可以插入数据。

public void ExpandFile(FileStream stream, long offset, int extraBytes)
{
  // http://stackoverflow.com/questions/3033771/file-io-with-streams-best-memory-buffer-size
  const int SIZE = 4096;
  var buffer = new byte[SIZE];
  var length = stream.Length;
  // Expand file
  stream.SetLength(length + extraBytes);
  var pos = length;
  int to_read;
  while (pos > offset)
  {
    to_read = pos - SIZE >= offset ? SIZE : (int)(pos - offset);
    pos -= to_read;
    stream.Position = pos;
    stream.Read(buffer, 0, to_read);
    stream.Position = pos + extraBytes;
    stream.Write(buffer, 0, to_read);
  }

不过还是需要检查一下...

Here is an easy and quite fast solution. It moves all bytes after given offset to their new position according to given extraBytes, so you can insert your data.

public void ExpandFile(FileStream stream, long offset, int extraBytes)
{
  // http://stackoverflow.com/questions/3033771/file-io-with-streams-best-memory-buffer-size
  const int SIZE = 4096;
  var buffer = new byte[SIZE];
  var length = stream.Length;
  // Expand file
  stream.SetLength(length + extraBytes);
  var pos = length;
  int to_read;
  while (pos > offset)
  {
    to_read = pos - SIZE >= offset ? SIZE : (int)(pos - offset);
    pos -= to_read;
    stream.Position = pos;
    stream.Read(buffer, 0, to_read);
    stream.Position = pos + extraBytes;
    stream.Write(buffer, 0, to_read);
  }

Need to be checked, though...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文