Сохранить короткое целое в двоичном файле вместо текстового файла

Допустим, у меня есть вектор с 9 целыми числами.

всего у меня должно быть 36 байт.

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

Я заметил, что файл с 120 98 99 99 98 257 259 98 0 был 28 байт, и мне интересно, что я сделал не так.

ofstream out(file, ios::binary);
int len = idx.size();                    //idx is the vector<int>
string end = " 0", space = " ";          //end is just to finish the saving.
for(int i = 0; i < len; i++) {
    if(idx[i] <= SHRT_MAX){
        short half = idx[i];
        out<<half;
    }
    else out<<idx[i];
    if(i == len-1) out<<end; else out<<space;
}

person Daniel    schedule 11.12.2016    source источник
comment
Отчасти связано: int не гарантированно будет 4 байта, а short не гарантированно будет 2 байта. Большинство компиляторов используют эти размеры, но стандарт их не навязывает.   -  person UnholySheep    schedule 11.12.2016
comment
как вы собираетесь читать этот файл позже? Я имею в виду, как вы решаете, что читать - int или short?   -  person Ap31    schedule 11.12.2016
comment
Открытие файла как binary не означает, что вывод будет двоичным. Это просто означает, что окончания строк не будут затронуты. Это должен быть дубликат.   -  person Martin Bonner supports Monica    schedule 11.12.2016
comment
Я намеревался читать как int, но если я смогу сохранить его как короткий, я мог бы изменить логику чтения   -  person Daniel    schedule 11.12.2016
comment
@Daniel изменить логику на что? на что я намекаю, что данные, хранящиеся таким образом, невозможно восстановить   -  person Ap31    schedule 11.12.2016
comment
на самом деле я пишу lzw-сжатие, но файл int становится больше, чем исходный строковый файл, поэтому я пытаюсь сохранить его как короткий   -  person Daniel    schedule 11.12.2016


Ответы (1)


Первый совет, используйте заголовок cstdint, если хотите работать с типами гарантированного размера. Такие типы, как uint16_t, являются стандартными и существуют не просто так.

Далее, идея записи иногда двух байтов, а иногда записи четырех. Имейте в виду, что когда вы записываете данные в такой файл, он будет выглядеть как большой кусок данных. Не будет никакого способа волшебным образом узнать, когда читать два байта, а когда четыре. Вы можете хранить метаданные о файле, но это, вероятно, будет более неэффективно, чем просто последовательное использование одного и того же размера. Пишите все как два байта или четыре байта. Это зависит от вас, но что бы это ни было, вы, вероятно, должны придерживаться этого.

Теперь перейдем к тому, почему у вас записано 28 байт данных.

Вы пишете ASCII-представление своих чисел. В итоге получается "120 98 99 99 98 257 259 98 9" размером 28 байт.

При записи ваших данных вы, вероятно, захотите сделать что-то вроде

out.write( (char*)&my_data, sizeof(my_data));

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

Учебник Disch по хорошим двоичным файлам

person Austin Jenkins    schedule 11.12.2016
comment
как это out.write( (char*)&my_data, sizeof(my_data)); относится к vector‹int› ? Я имею в виду, я не понял этого приведения к char * - person Daniel; 11.12.2016
comment
Это работает при написании отдельных интегральных типов. В любом случае вы уже пишете каждый элемент в своем векторе по одному. - person Austin Jenkins; 11.12.2016
comment
Причина, по которой вы приводите к char, заключается в том, что «запись» не понимает другие типы. Он просто заботится о том, чтобы получить то, что выглядит как массив байтов. - person Austin Jenkins; 11.12.2016
comment
так что вы предлагаете вместо того, чтобы делать это с вектором, как только я добавлю элемент x в вектор, я напишу out.write( (char*) &x, sizeof(x)) ? - person Daniel; 11.12.2016
comment
Нет, я просто говорю вам писать свои элементы по-другому. Как вы храните свои данные в памяти, немного не имеет значения. - person Austin Jenkins; 11.12.2016
comment
Вы можете сделать что-то подобное в цикле for, out.write( (char*)&idx[i], sizeof(uint16_t)); - person Austin Jenkins; 11.12.2016
comment
это сработало! какой синтаксис для чтения в int? - person Daniel; 11.12.2016
comment
Давайте продолжим обсуждение в чате. - person Austin Jenkins; 11.12.2016