Как определить, сколько байтов потребуется BinaryWriter для записи в память? - PullRequest
0 голосов
/ 05 августа 2020

Красный: Сколько байтов займет строка? и Как узнать размер строки в байтах? и некоторые другие, но я не могу понять точное количество байтов, которые строка займет в памяти, используя BinaryWriter поверх MemoryMappedViewStream через MemoryMappedFile.

Иногда принимаемая длина равна длине строки + 1, иногда - длине строки + 2 ???

Я пробовал оба:

  • System.Text.ASCIIEncoding.Default.GetByteCount (str)
  • System.Text.ASCIIEncoding.Unicode.GetByteCount (str)

Но ни один из них не работает. Я попробовал длину строки плюс фиксированное количество, но это тоже не работает.

Если я проверю разницу между BinaryWriter.BaseStream.Position до и после, то я не смогу найти способ определить, что будет точным количеством байтов, записанных для строки (позиция после - позиция перед). Похоже, есть выравнивание или что-то еще, что я не могу понять?

Как иметь правильное количество байтов для записи каждый раз?

Обновление

Сейчас я использую Encoding.UTF8.GetByteCount(str) + 1;, что дает мне почти правильный размер в большинстве случаев, но не всегда.

1 Ответ

0 голосов
/ 06 августа 2020

Я нашел свой ответ на основе исходного кода Microsoft BinaryWriter по адресу https://referencesource.microsoft.com/#mscorlib / system / io / binarywriter.cs, 08f2e8c389fd32df

Примечание: длина строки записана перед строкой и кодируется 7 битами, размер которых может варьироваться в зависимости от размера строки (> = 128,> = 2 ^ 14,> 2 ^ 21).

Код:

    public static int GetBinaryWriterSizeRequired(this string str, Encoding encoding)
    {
        encoding = encoding ?? Encoding.Default;

        int byteCount = encoding.GetByteCount(str);
        int byteCountRequiredToWriteTheSize = 1;

        // EO: This code is based on the Microsoft Source Code of the BinaryWriter at:
        // https://referencesource.microsoft.com/#mscorlib/system/io/binarywriter.cs,2daa1d14ff1877bd
        uint v = (uint)byteCount;   // support negative numbers
        while (v >= 0x80)
        {
            v >>= 7;
            byteCountRequiredToWriteTheSize++;
        }

        return byteCountRequiredToWriteTheSize + byteCount;
    }

Вызов:

...
_writer = new BinaryWriter(_stream);
_writerEncoding = _writer.GetPrivateFieldValue<Encoding>("_encoding");
...
int sizeRequired = name.GetBinaryWriterSizeRequired(_writerEncoding);

Другие (я знаю, что мы не должны вызывать закрытые поля, но я это сделал):

public static T GetPrivateFieldValue<T>(this object obj, string propName)
{
    if (obj == null)
        throw new ArgumentNullException("obj");

    Type t = obj.GetType();
    FieldInfo fi = null;
    while (fi == null && t != null)
    {
        fi = t.GetField(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
        t = t.BaseType;
    }

    if (fi == null)
        throw new ArgumentOutOfRangeException("propName", string.Format("Field {0} was not found in Type {1}", propName, obj.GetType().FullName));

    return (T)fi.GetValue(obj);
}

Просто для справки, все это плохо:

return Encoding.UTF8.GetByteCount(str) + 1;
return System.Text.ASCIIEncoding.Default.GetByteCount(str) + 1; //  sizeof(int); // sizeof int to keep the size
return System.Text.ASCIIEncoding.Unicode.GetByteCount(str) + sizeof(int); // sizeof int to keep the size
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...