C ++: Как сохранить независимые от платформы двоичные файлы?

У меня есть 3D-объем, представленный как вектор вектора вектора плавания, который я хочу сохранить в двоичный файл. (Это объем плотности, восстановленный по рентгеновским изображениям, полученным с помощью компьютерного томографа.)

Теперь я мог сделать это следующим образом:

        //iterate through the volume
        for (int x = 0; x < _xSize; ++x){
            for (int y = 0; y < _ySize; ++y){
                for (int z = 0; z < _zSize; ++z){
                    //save one float of data
                    stream.write((char*)&_volume[x][y][z], sizeof(float));
                }
            }
        }

Это в основном работает. Однако я спрашиваю себя, насколько это не зависит от платформы. Я хотел бы создать файл, который будет идентичным независимо от системы, в которой он был создан. Таким образом, могут быть машины под управлением Windows, Linux или Mac, у них может быть 32-битная или 64-битная длина слова и порядок байтов с прямым или обратным порядком байтов.

Полагаю, если бы я сделал это так, как это было сделано выше, этого не было бы. Как я мог этого добиться? Я слышал о сериализации, но не нашел конкретного решения для этого случая.


person bweber    schedule 30.04.2015    source источник
comment
без использования двоичных форматов. Доступно множество хороших текстовых форматов, и если вам ничего не подходит, легко создать свой собственный, специализированный для вашего приложения.   -  person Some programmer dude    schedule 30.04.2015
comment
Двоичные форматы: укажите каждый бит, каким должен быть ваш файл, а затем начните читать для каждой платформы, как вы можете читать / писать именно этот формат. Точная компоновка битов int и float, наборов символов и т. Д. И т. Д. Да, это сложно. Кстати. сериализация, о которой вы слышали, является именно такой, включая все проблемы. О текстовых форматах: хотя и проще, но и не идеален. Снова кодировка, гарантированные диапазоны значений ...   -  person deviantfan    schedule 30.04.2015
comment
@ user1488118 Взгляните на ASN.1 и BER. Или BSON.   -  person Biffen    schedule 30.04.2015
comment
Текстовые файлы? Действительно? Накладные данные, связанные с этим, будут огромными. Эти тома уже занимают около 80 ГБ ОЗУ. Что касается упомянутых форматов двоичного кодирования, есть ли библиотеки, которые поддерживают это за вас?   -  person bweber    schedule 30.04.2015
comment
Здесь вы должны использовать стандарт с плавающей запятой, такой как IEEE 754: en.wikipedia.org/wiki/IEEE_floating_point Обратите внимание, что в зависимости от вашей платформы ваше float или double может или не может соответствовать представлению IEEE 754, поэтому дело не только в сериализации байтов ваших переменных. Вместо этого вам понадобится инструмент, поддерживающий платформу, для записи / анализа IEEE 754 бит. Я нашел этот beej.us/guide/bgnet/output/html / multipage /, где предоставляются некоторые инструменты, хотя они кажутся неполными.   -  person Ramón Gil Moreno    schedule 30.04.2015
comment
Qt, по-видимому, сериализует определенные типы данных при использовании QDataStream, также с плавающей запятой (32-битное число с плавающей запятой в стандартном формате IEEE 754, doc.qt.io/qt-4.8/datastreamformat.html). Может, я попробую.   -  person bweber    schedule 30.04.2015
comment
Обычно медицинские изображения сохраняются в виде файлов DICOM. Я бы использовал подходящую библиотеку (GDCM, DCMTK ...) для этого.   -  person drescherjm    schedule 30.04.2015


Ответы (3)


Буферы протокола Google: бесплатно, кодируются в двоичные файлы, доступны на нескольких языках, также работают на большинстве платформ. Для ваших требований я бы серьезно рассмотрел GPB. Однако будьте осторожны, Google выпустил несколько версий, и они не всегда были обратно совместимы, то есть старые данные не обязательно читаются новыми версиями кода GPB. Я чувствую, что он все еще развивается, и будут происходить дальнейшие изменения, которые могут быть неприятными, если ваш проект также будет развиваться в течение многих лет.

ASN.1, дедушка их всех, очень хороший язык схемы (можно установить ограничения по значению и размеру, что является отличным способом избежать переполнения буфера и обеспечивает автоматическую проверку потоков данных при условии, что автоматически сгенерированный код верен), некоторые бесплатные инструменты см. эту страницу (хотя в большинстве случаев они стоят денег). Язык схемы GPB представляет собой плохую имитацию ASN.1.

person bazza    schedule 01.05.2015
comment
У меня была эта идея раньше, и я разговаривал с коллегой, который раньше использовал буферы протокола Google для сериализации объектов. Однако мне кажется, слишком много накладных расходов связано с созданием прото-файлов и запуском на них компилятора. Тем более, что моя цель не сериализовать целые объекты, а просто написать несколько простых примитивных типов данных. В итоге я использовал Qt Datastream, который, по-видимому, работает довольно хорошо и не зависит от платформы. - person bweber; 03.05.2015
comment
@ user1488118 Достаточно честно! Одним из преимуществ использования чего-то вроде GPB является то, что он дает вам «единую точку истины», так что любая программа, использующая его, получает точно такие же объекты и сериализацию. Если вы пишете весь код на Qt, вы можете получить ту же «единую точку истины», повторно используя код. Для справки в будущем накладные расходы на использование GPB (или чего-то подобного) не так уж и плохи, если компиляция вызывается как этап предварительной сборки. Удачи! - person bazza; 04.05.2015

Решил проблему с помощью класса Qt Datastream. Qt в любом случае является частью моего проекта, поэтому дополнительные усилия минимальны. Я могу точно сказать объекту Datastream, хочу ли я сохранить свой floats, используя одинарную точность (32 бит) или двойную точность (64 бит), и хочу ли я использовать порядок байтов с прямым или обратным порядком байтов. Этого вполне достаточно для того, что мне нужно; Мне не нужно сериализовать объекты. Файлы, которые я сейчас сохраняю, имеют одинаковый формат на всех платформах (по крайней мере, должны), и это все, что мне нужно. Впоследствии они будут прочитаны сторонними приложениями, которым будет предоставлена ​​эта информация (порядок байтов, точность). Таким образом, не имеет значения, как мои поплавки сохраняются, но то, что я знаю, как они сохраняются, и что это согласуется, независимо от того, на какой платформе вы запускаете программу. .

Вот как теперь выглядит код:

QDataStream out(&file);
out.setFloatingPointPrecision(QDataStream::SinglePrecision);
out.setByteOrder(QDataStream::LittleEndian);

for (int x = 0; x < _xSize; ++x){
    for (int y = 0; y < _ySize; ++y){
        for (int z = 0; z < _zSize; ++z){
            //save one float of data
            out<<_volume[x][y][z];
        }
    }
}
person bweber    schedule 03.05.2015

Я удивлен, что нет упоминания о заголовке <rpc/xdr.h> для представления внешних данных. Я считаю, что он есть во всех unix-версиях и может даже работать в Windows: https://github.com/ralight/oncrpc-windows/blob/master/win32/include/rpc/xdr.h

XDR хранит все примитивные типы данных с прямым порядком байтов и заботится о преобразованиях за вас.

person wessel    schedule 17.05.2017