Здравствуйте, TailWind, Вы писали: TW>Хочется чтобы сейф файлы старых версий открывались в новых версиях программы TW>С удовольствием послушаю про опыт старших товарищей )
Ну собственно путей как бы немного:
1) Первым параметром в файле сделать версию. В более новых версиях софта файл читается разными методами, типа ReadV1, ReadV2, etc.
или
2) Использовать XML, в этом случае добавление фич обычно ничего не ломает, просто появляются новые теги, которых нет в ранних файлах.
Вот чувствую будет проблема с Read_v1
Структура программы то меняется, объекты меняются
А Read_v1 будет пытаться заполнить несуществующие поля например
Придётся эти Read_v1, v2, v3 исправлять каждый раз когда я меняю интерфейс классов
А тестировать уже не на чем
Вот как бы этого избежать?
Может делать бинарные конвертеры v1 -> v2, v2 -> v3, которые не заполняют основные объекты, а конвертируют бинарные данных из сэйф файла?
TW>Хочется чтобы сейф файлы старых версий открывались в новых версиях программы
Отказаться от идеи "гружу бинарную структуру целиком".
Иницаилизировать каждый объект дефолтным состоянием, потом читать свойство за свойством и менять состояние.
Иерархический объект можно сериализовать через что-то, прендазначенное для подобного --
XML / JSON / Binary JSON / CBOR / Protobuf.
Да хоть старый добрый RIFF.
И читать соответственно -- пропуская те блоки/теги, что неизвестны текущей версии.
Для гарантии можно изначальное завести тег "минимально необходимая версия парсера" и ругаться если парсер слишком старый.
Здравствуйте, TailWind, Вы писали:
TW>Придётся эти Read_v1, v2, v3 исправлять каждый раз когда я меняю интерфейс классов TW>А тестировать уже не на чем
TW>Вот как бы этого избежать?
TW>Может делать бинарные конвертеры v1 -> v2, v2 -> v3, которые не заполняют основные объекты, а конвертируют бинарные данных из сэйф файла?
Да не будет у вас зоопарк версий, в конце концов устаканится формат. Первый байт в файле — версия.
Здравствуйте, TailWind, Вы писали:
ЧВ>>ReadV1, ReadV2, etc.
TW>Вот чувствую будет проблема с Read_v1 TW>Структура программы то меняется, объекты меняются TW>А Read_v1 будет пытаться заполнить несуществующие поля например
не будет, во первых читать нужно в буфер и из него парсить, а во вторых заполнение несуществующих уже полей просто убирать из кода Read_v1
Здравствуйте, TailWind, Вы писали: TW>И формат сейф файла будет меняться
TW>Хочется чтобы сейф файлы старых версий открывались в новых версиях программы
Это вообще не проблема. Ты формат проектируй с тем расчетом, чтобы _старая_ версия программы могла открыть более новый формат файла.
Здравствуйте, marcopolo, Вы писали:
M>Это вообще не проблема. Ты формат проектируй с тем расчетом, чтобы _старая_ версия программы могла открыть более новый формат файла.
А есть ли в это хоть какой-то практический смысл?
— Все данные всё равно не прочитаются. В плохом раскладе может и формат отдельных полей поменяться между версиями.
— Дополнительный пинок проапгрейдиться для юзера.
Здравствуйте, TailWind, Вы писали:
K13>>XML / JSON / Binary JSON / CBOR / Protobuf.
TW>Рекомендуете текстовый формат сейф файла?
TW>Я то думал место экономить. Типа: TW>1 byte = код поля в объекте TW>1 byte = размер данных TW>4 byte = скажем int
А смысл сейчас байтики экономить? Скомпрессируйте данные перед сохранением и всё. Если же у вас сотни мегабайт в файле — то всё равно придётся что-то свое придумывать для ускорения загрузки и сохранения такого количества данных и простые рекомендации уже не помогут.
Здравствуйте, Ivanoff, Вы писали:
vsb>>Не обязательно XML. В принципе в любом формате можно предусмотреть расширяемость.
I>Так куча либ для сериализации того же XML/JSON уже есть, зачем велосипедить?
Ну некоторым людям нравится (: А так да, смысла немного по сути. Если сжимать через zip или gzip, то особо ничего и не выиграешь на этих ручных форматах, ещё и проиграть можно.
Здравствуйте, TailWind, Вы писали:
TW>Хочется чтобы сейф файлы старых версий открывались в новых версиях программы
изначально спроектировать документ как дерево объектов, каждый класс сохраняемого объекта имеет свой отдельный номер версии, увеличивающийся при внесении изменений в класс.
Так как в пределах одного класса изменения в формате обычно невелики, легко реализовать поддержку чтения старых версий объекта.
практикую такой подход много лет. ни разу не подвел.
Мудрого человека невозможно оскорбить, потому что правда – это не оскорбление, а ложь не стоит того, чтобы обращать на нее внимания.
Здравствуйте, TailWind, Вы писали:
TW>С удовольствием послушаю про опыт старших товарищей )
То что тебе нужно называется protobuf. На выходе оч компактные бинарные данные. Автогенеренный код сохранения/чтения по описанию схемы данных. Не написав ни строчки кода получаешь классы, которые умеют сохраняться. И — главное, совместимость в обе стороны. Старый код открывает новую схему, а новый старую (если нет required полей).
Внутри программы переколбашивай контроллеры и прочую лабуду сколько хочешь, классы с данными определяются схемой.
опа опа мы воюем с нато
любит хавать этот кал
путинская вата
Здравствуйте, TailWind, Вы писали:
TW>Пишу редактор
Как писали, первой хранится сигнатура, за ней — версия файла.
Отказаться от идеи считывать "блоб" из файла в объект в памяти целиком.
Можно использовать тэговый формат. Как пример, xml или json, где объекты доступны по именам/иерархиям, при этом не важно, где они лежат в файле физически. В двоичном виде такое тоже нетрудно организовать. При этом будет шанс (можно пытаться добиваться этого специально, если хочется), что старая версия будет читать более новый формат, предварительно предупредив пользователя о возможности трабла.
Здравствуйте, goto, Вы писали:
G>Отказаться от идеи считывать "блоб" из файла в объект в памяти целиком.
G>Можно использовать тэговый формат. Как пример, xml или json, где объекты доступны по именам/иерархиям, при этом не важно, где они лежат в файле физически. В двоичном виде такое тоже нетрудно организовать. При этом будет шанс (можно пытаться добиваться этого специально, если хочется), что старая версия будет читать более новый формат, предварительно предупредив пользователя о возможности трабла.
Это же очень просто. В двоичном файле после идетификатора секции пишется размер данных. Если идентификатор неизвестен — программа пропускает этот сегмент данных и читает следующий. Вроде так формат RIFF организован.
Здравствуйте, kgd, Вы писали:
kgd>Это же очень просто. В двоичном файле после идетификатора секции пишется размер данных. Если идентификатор неизвестен — программа пропускает этот сегмент данных и читает следующий. Вроде так формат RIFF организован.
Тэговые форматы часто так и устроены. А так, вплоть до использования БД.