跨平台编程问题(文件I / O)

时间:2009-10-28 06:57:54

标签: c++ cross-platform ubuntu-9.04

我有一个看起来有点像这样的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. 在Linux计算机上编译相同的库(在上面的1中使用)
  3. 问题:上面1中创建的文件可以在Linux机器上读取吗(2)吗?

    如果不是,请解释原因,以及我如何解决这个问题。

7 个答案:

答案 0 :(得分:1)

这完全取决于二进制编码的细节。关于Linux与XP的不同之处在于,您更有可能发现自己处于大端平台上,如果您的二进制编码是特定于字节序的,那么您最终会遇到问题。

您最终可能会遇到与行尾字符相关的问题。此处没有足够的信息说明您如何使用::std::iostream为这个问题提供一个很好的答案。

我强烈建议查看protobuf library。它是用于创建快速跨平台二进制编码的出色库。

答案 1 :(得分:1)

std::basic_streambuf派生。这就是他们的目的。注意,大多数STL类不是为了派生而设计的。我提到的是一个例外。

答案 2 :(得分:1)

如果您希望代码可以在具有不同endianess的计算机上移植,则需要坚持在文件中使用一个endianess。无论何时读取或写入文件,都要在主机字节顺序和文件字节顺序之间进行转换。当您想要编写可在所有计算机上移植的文件时,通常使用您所谓的网络字节顺序。网络字节顺序被定义为大端,并且有预先制作的功能来处理这些转换(尽管它们很容易自己编写)。

例如,在将long写入文件之前,应使用htonl()将其转换为网络字节顺序,并且在从文件读取时,应使用ntohl()将其转换回主机字节顺序。在big-endian系统上,htonl()和ntohl()只返回传递给函数的相同数字,但在little-endian系统中,它会交换变量中的每个字节。

如果你不关心支持大端系统,虽然这仍然是一个很好的做法,但这一切都不是问题。

另一个需要注意的重要事项是填充您编写的结构/类,如果直接将它们写入文件(例如Header和Row)。不同平台上的不同编译器可以使用不同的填充,这意味着变量在内存中的排列方式不同。如果您在不同平台上使用的编译器使用不同的填充,这可能会破坏大量时间。因此,对于您打算直接写入文件/其他流的结构,应始终指定填充。您应该告诉编译器打包您的结构:

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

请记住,在您的应用程序中使用结构时,这样做会使结构使用效率更低,因为访问未对齐的内存地址意味着系统需要更多的工作。这就是为什么对于写入流的打包结构具有单独类型以及实际在应用程序中使用的类型通常是个好主意(您只需将成员从一个复制到另一个)。

EDIT。当然,处理这个问题的另一种方法是自己序列化这些结构,这不需要使用#pragma(pragma是编译器相关的功能,尽管我所知的所有主要编译器都支持pragma包)。

答案 3 :(得分:1)

以下是与您的问题相关的文章Endianness。查找“文件中的字节顺序和字节交换”。简单地说,如果您的Linux机器具有相同的endianes而不是它可以,如果不是 - 那么migth就会出现问题。

例如,当在XP上的文件中写入整数1时,它看起来像这样:10 00

但是当整数1写在机器上的文件中并带有另一个字节时,它将如下所示:00 01

但如果你只使用一个字节字符就一定没有问题。

答案 4 :(得分:0)

只要它是普通的二进制文件就可以使用

答案 5 :(得分:0)

因为您将STL用于所有内容,所以您的程序无法在不同平台上读取文件。

答案 6 :(得分:0)

如果您正在直接向光盘写入结构/类,则不要。

这可能在同一编译器上的不同构建之间不兼容,并且当您移动到不同的平台或编译器时几乎肯定会中断。如果你改用不同的架构,它肯定会破裂。

从上面的代码中不清楚你实际上是在写什么文件。