Вставка байтов в середине двоичного файла - PullRequest
11 голосов
/ 09 мая 2011

Я хочу добавить строку в середине блока метаданных изображения.Под каким-то конкретным маркером.Я должен сделать это на уровне байтов, поскольку .NET не поддерживает настраиваемые поля метаданных.

Блок построен как 1C 02 XX YY YY ZZ ZZ ZZ ..., где XX - идентификатор поля, которое мне нужно добавить, а YY YY -его размер, ZZ = data.

Я полагаю, что более или менее возможно прочитать все данные изображения до этого маркера (1C 02 XX), затем увеличить размер байтов (YY YY), добавить данныев конце ZZ, а затем добавить остальную часть исходного файла?Это правильно?

Как мне продолжать это?Он должен работать как можно быстрее с 4-5 МБ файлами JPEG.

Ответы [ 3 ]

7 голосов
/ 09 мая 2011

Как правило, нет возможности ускорить эту операцию. Вы должны прочитать хотя бы часть, которую необходимо переместить, и снова записать ее в обновленный файл. Создание нового файла и копирование в него содержимого может быть быстрее, если вы сможете распараллелить операции чтения и записи.

Примечание. В вашем конкретном случае может оказаться невозможным просто вставить содержимое в середину файла, поскольку большинство форматов файлов не предназначены для таких изменений. Часто есть смещения к частям файла, которые будут недействительными, когда вы сдвигаете часть файла. Указание формата файла, с которым вы пытаетесь работать, может помочь другим людям улучшить подход.

2 голосов
/ 16 мая 2011

Решена проблема с этим кодом:

            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);                
1 голос
/ 21 октября 2013

Вот простое и довольно быстрое решение. Он перемещает все байты после заданного смещения на новую позицию в соответствии с заданными лишними байтами, поэтому вы можете вставить свои данные.

public void ExpandFile(FileStream stream, long offset, int extraBytes)
{
  // /2902318/failovyi-vvod-vyvod-s-potokami-luchshii-razmer-bufera-pamyati
  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);
  }

Нужно проверить, хотя ...

...