Вопрос кроссплатформенного программирования (файловый ввод / вывод)

У меня есть класс C++, который выглядит примерно так:

class BinaryStream : private std::iostream
{
    public:
        explicit BinaryStream(const std::string& file_name);
        bool read();
        bool write();

    private:
        Header m_hdr;
        std::vector<Row> m_rows;        
}

Этот класс читает и записывает данные в двоичном формате на диск. Я не использую какую-либо платформо-зависимую кодировку - вместо этого я полагаюсь на STL. Я успешно скомпилировал на XP. Мне интересно, могу ли я FTP файлы, написанные на платформе XP, и читать их на своем компьютере с Linux (как только я перекомпилирую библиотеку двоичного потока в Linux).

Резюме:

  1. Файлы, созданные на компьютере Xp с использованием кроссплатформенной библиотеки, скомпилированной для XP.
  2. Скомпилируйте ту же библиотеку (используется в 1 выше) на машине Linux

Вопрос: Можно ли читать файлы, созданные в пункте 1 выше, на компьютере с Linux (2)?

Если нет, пожалуйста, объясните, почему нет, и как я могу обойти эту проблему.

7 ответов

Это полностью зависит от специфики двоичного кодирования. Отличительной чертой Linux от XP является то, что вы с большей вероятностью окажетесь на платформе с прямым порядком байтов, и если ваша двоичная кодировка имеет специфический порядок байтов, вы столкнетесь с проблемами.

Вы также можете столкнуться с проблемами, связанными с символом конца строки. Здесь недостаточно информации о том, как вы используете ::std::iostream чтобы дать вам хороший ответ на этот вопрос.

Я настоятельно рекомендую посмотреть на библиотеку protobuf. Это отличная библиотека для создания быстрых кроссплатформенных двоичных кодировок.

Вытекают из std::basic_streambuf, Вот для чего они здесь. Обратите внимание, что большинство классов STL не предназначены для использования в. Тот, который я упоминаю, является исключением.

Вот статья Endianness, связанная с вашим вопросом. Ищите "Порядковый номер в файлах и обмен байтов". Вкратце, если на вашей машине Linux те же порядковые номера, что и в норме, если нет - проблемы могут возникнуть.

Например, когда в XP записано целое число 1 в файле, оно выглядит так: 10 00

Но когда целое число 1 записывается в файл на компьютере с другим порядком байтов, оно будет выглядеть так: 00 01

Но если вы используете только один байт, проблем не должно быть.

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

Например, перед записью long в файл вы должны преобразовать его в сетевой порядок байтов с помощью htonl(), а при чтении из файла вы должны преобразовать его обратно в байтовый порядок хоста с помощью ntohl(). В системе с прямым порядком байтов htonl () и ntohl () просто возвращают то же число, что было передано в функцию, но в системе с прямым порядком байтов он меняет каждый байт в переменной.

Если вы не заботитесь о поддержке систем с прямым порядком байтов, ни одна из этих проблем не является проблемой, хотя это все еще хорошая практика.

Еще одна важная вещь, на которую следует обратить внимание, это заполнение ваших структур / классов, которые вы пишете, если вы записываете их непосредственно в файл (например, Header и Row). Разные компиляторы на разных платформах могут использовать разные отступы, что означает, что переменные выровнены по-разному в памяти. Это может сильно испортить ситуацию, если компиляторы, которые вы используете на разных платформах, используют разные отступы. Поэтому для структур, которые вы намереваетесь записывать непосредственно в файлы / другие потоки, вы всегда должны указывать заполнение. Вы должны сказать компилятору упаковать ваши структуры следующим образом:

#pragma pack(push, 1)
struct Header {
  // This struct uses 1-byte padding
  ...
};
#pragma pack(pop)

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

РЕДАКТИРОВАТЬ. Конечно, еще один способ решить эту проблему - это самим сериализовать эти структуры, для чего не потребуется использовать #pragma (прагмы зависят от компилятора, хотя все основные компиляторы, насколько мне известно, поддерживают пакет прагмы).

Пока это простые двоичные файлы, это должно работать

Поскольку вы используете STL для всего, нет причины, по которой ваша программа не сможет читать файлы на другой платформе.

Если вы пишете struct / class прямо на диск, то не делайте этого.

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

Из приведенного выше кода не ясно, что вы на самом деле пишете в файл.

Другие вопросы по тегам