Как определить, сколько байт BinaryWriter потребуется для записи в память?

Я красный: Сколько байтов займет строка? и Как узнать размер строки в байтах? и некоторые другие, но я не могу вычислить точное количество байтов, которое строка займет в памяти, используя 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;, который дает мне почти правильный размер в большинстве случаев, но не всегда.


person Eric Ouellet    schedule 04.08.2020    source источник
comment
Что вы собираетесь делать с длиной, когда она у вас есть?   -  person Robert Harvey    schedule 05.08.2020
comment
Хорошо, какие из этих чисел, которые вы вычисляете, вы считаете правильными, если таковые имеются?   -  person Robert Harvey    schedule 05.08.2020
comment
2 коммуникационных процесса (приложение и приложение-логгер). Преимущественно однонаправленный. Я хочу убедиться, что общая память не заполнена, прежде чем добавлять дополнительное сообщение. Если да, то я перевернусь (начну сначала), если читатель (лог) уже прочитал память, куда я хочу записать. Но мне нужно убедиться, что у меня достаточно места для написания сообщения. Я могу аппроксимировать, используя 2 байта на char, но почему бы не сделать это чисто и не получить реальную сумму?   -  person Eric Ouellet    schedule 05.08.2020


Ответы (1)


Я нашел свой ответ на основе исходного кода 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
person Eric Ouellet    schedule 06.08.2020