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

У меня есть класс 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)?

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


person skyeagle    schedule 28.10.2009    source источник
comment
Я добавил несколько комментариев о бережливости и протобуфе. Я еще раз взглянул на них обоих, и мне НАМНОГО больше нравится protobuf. Почему тебе больше нравится бережливость?   -  person Omnifarious    schedule 28.10.2009
comment
Вкратце: бережливость больше похожа на C / C ++, а также имеет структуру для сервисов и т. Д.   -  person skyeagle    schedule 30.10.2009


Ответы (7)


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

person dirkgently    schedule 28.10.2009

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

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

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

person Omnifarious    schedule 28.10.2009
comment
Я беспокоился именно о `` порядке байтов '' (и о том, что послужило поводом для публикации) - однако, как ни удивительно, когда я прочитал ваш комментарий, я понял, что это не будет проблемой, поскольку обратный порядок байтов находится на аппаратной стороне - и обе машины являются ПК с архитектурой i86 (причем обе 32-битные машины) - person skyeagle; 28.10.2009
comment
Все машины x86, x86_64 и т. д. имеют обратный порядок байтов. Примером платформы с прямым порядком байтов являются старые компьютеры Mac на базе PowerPC. - person reko_t; 28.10.2009
comment
Да, если вы уверены, что рассматриваемая машина Linux также является машиной с прямым порядком байтов, то в этом отношении вы в безопасности. Мне не нравится делать такие предположения, и я настоятельно рекомендую вам изучить библиотеку, специально разработанную для создания межплатформенных двоичных кодировок. - person Omnifarious; 28.10.2009
comment
protobuf выглядит круто. Я читаю его, чтобы увидеть, какие усилия требуются для изменения моего кода ... - person skyeagle; 28.10.2009
comment
Что ж, бережливость создается бывшим человеком из Google, который зашел в Facebook и внедрил бережливость. :-) Я посмотрел на них обоих, и Protobuf мне нравится больше. Я не могу вспомнить причину, по которой мне больше нравится этот, но я помню, что это была довольно техническая причина. Я открыто признаю некоторую предвзятость, поскольку главный специалист по Protobuf в Google - мой личный друг. - person Omnifarious; 28.10.2009
comment
Ах, вот почему. Thrift слишком сильно фокусируется на протоколе RPC. И, IMHO, RPC ужасно злой. Протоколы должны быть ориентированы на данные, а не на операции, в основном по причинам уменьшения связи и поощрения проектов, которые хорошо справляются с задержками. Кроме того, кодирование protobuf более эффективно. - person Omnifarious; 28.10.2009

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

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

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

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

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

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

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

person reko_t    schedule 28.10.2009
comment
И-эй! - назовите меня слабаком, но именно такого кода я стараюсь избегать - person skyeagle; 28.10.2009
comment
Мне не нравится, когда ЭТО приближается к машине. Смотрю на фреймворк facebook, интересно смотрится ... - person skyeagle; 28.10.2009
comment
Если вы имеете в виду тему #pragma, то это хорошо. Всегда - хорошая идея - сериализовать данные самостоятельно, так как запись структур непосредственно в потоки рано или поздно вызовет проблемы совместимости (а это некрасиво). - person reko_t; 28.10.2009
comment
И когда я сказал, что это хорошо, я имел в виду, что это хорошо, что вы хотите этого избежать. - person reko_t; 28.10.2009

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

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

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

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

person Community    schedule 28.10.2009

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

person dutt    schedule 28.10.2009
comment
простой двоичный файл? - Скажите, пожалуйста, что это могло значить? - person skyeagle; 28.10.2009
comment
в отличие от двоичного кода, который интерпретируется как текст, когда вам нужно беспокоиться о концах строк, я бы предположил - person Steve Gilham; 28.10.2009

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

person Adam Maras    schedule 28.10.2009

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

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

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

person MarkR    schedule 28.10.2009