在系统之间传输二进制文件

时间:2010-06-15 16:13:54

标签: c unix binary transfer

我正在尝试在2个UNIX群集之间传输我的文件,数据是二进制形式的纯数字(double的向量)。不幸的是,其中一个系统是IBM ppc997,另一个系统是AMD Opteron,这些系统中的二进制数字似乎不同。

到目前为止,我尝试了3种方式:

1-将我的文件更改为ASCII格式(即在文本文件的每一行保存一个数字),将它们发送到目标并在目标系统上再次将它们更改为二进制(它们都是UNIX,没有行尾性格差异??!)

2-将纯二进制文件发送到目的地

3-使用uuencode将它们发送到目的地并解码它们

不幸的是,这些方法中的任何一个都不起作用(我的目标系统中的代码生成垃圾,而它在第一个系统上工作,我100%确定代码本身是可移植的)。我不知道我还能做什么?你有什么主意吗?我不是专业人士,请不要使用计算机科学家的术语!

并且:我的代码在C中,所以二进制是指内存和硬盘之间的一对一映射。

由于

5 个答案:

答案 0 :(得分:3)

如果要将内存内容写入文件,则代码不是100%可移植的。

您需要一些名为序列化的内容。好的,计算机科学术语,但它基本上意味着您获取数据并将其转换为明确定义和记录的字节序列,以后可以通过相同或其他程序将其读回内存。这个字节序列是体系结构和独立于平台的。

大多数Unix环境都附带XDR实现,它提供了数据序列化的例程。

一个简单的示例,将4个双精度编码为stdout(您可以使用shell重定向,或使用fopen()打开文件而不是stdout):

XDR xdrs;
double data[4] = { 1.0, 255.41, -357.1, 123.4 };
int i;

xdrstdio_create(&xdrs, stdout, XDR_ENCODE);
for (i = 0; i < 4; i++)
    xdr_double(&xdrs, &data[i]);

现在,为了获得这些双打(来自stdin)并打印它们:

XDR xdrs;
double data;
int i;

xdrstdio_create(&xdrs, stdin, XDR_DECODE);
for (i = 0; i < 4; i++) {
    xdr_double(&xdrs, &data);
    printf("%g\n", data);
}

您可以使用XDR对复杂结构进行编码和解码。这是向文件发送四个双打的非常愚蠢的方式,通常你应该使用xdr_array()来读/写某些数据类型的数组。保存和加载文件时,必须执行相同顺序的相同命令。实际上,您可以使用rpcgen自动生成C结构及其相应的xdr函数。

答案 1 :(得分:2)

方法1应该有效。只需创建一个值为1,2,...,10的测试向量并将其发送出去。您可以阅读已创建的ascii(因此可以验证“导出”),因此也可以检查重新读取文件的“导入”步骤。你可能会以这种方式失去精确度,但它应该让你可以运作。

方法2将在您使用诸如XDR之类的库处理不同的字节顺序时起作用。这些东西曾经是更大的问题'回来的时候'并且有解决方案。这是例如像R这样的系统如何允许你在架构之间共享二进制文件。

除非你在传输文件时做一些非常尴尬的事情,否则不需要方法3.

答案 2 :(得分:2)

提供的细节很少。尽力回答我的理解。

  

..其中一个系统是IBM ppc997,另一个是AMD Opteron

前系统一般(*)使用big-endian演示,稍后 - little-endian。 Read this

(*)这取决于操作系统。 IBM的POWER CPU可以同时执行小端和大端,但实际上没有运行的操作系统使用小端模式。

通常情况下,对于二进制表示,可以选择一个字节序,然后将其用于二进制表示。对于网络资料,大端数字表示是一种常态。

这意味着所有做这样事情的地方:

/* writing to binary */
int a = 1234;
write(fd,&a,sizeof(a));
/* reading from binary */
int x;
read(fd,&x,sizeof(x));

应该转换成这样的东西:

/* writing to binary */
int a = htonl(1234);
write(fd,&a,sizeof(a));
/* reading from binary */
int x;
read(fd,&x,sizeof(x));
x = ntohl(x);

另一种方法是保存字节顺序指示符(例如,写魔术并在另一侧检查它:MAGIC = 0x12345678 v.MAGIC = 0x78563412)以及二进制数据,并仅在字节顺序不同时应用转换。虽然这种方法不那么优雅,但我并没有真正的优势。

答案 3 :(得分:0)

解决方案2和3通常不起作用,因为不同的处理器可能会使用不同的内部表示形式。对于整数而不是浮点数/双精度数,你可以使用一些只需要处理不同机器的字节顺序的东西。 浮点表示更加棘手,您必须详细查看不同体系结构使用的表示形式。但是仍然是双倍的,例如,对精度的要求最低,你可能会发现自己必须截断到两者的较小表示。 这些问题与您正在使用的操作系统(Unix与否)没有太大关系,但与硬件的喜好有关。

答案 4 :(得分:0)

支持IEEE 754的所有处理器对于浮点数(技术上称为单个)和双精度具有相同的二进制表示。唯一的区别在于处理器的字节顺序。

因此,IBM PPC和AMD Opteron之间唯一不兼容的应该是双打的字节序。

当你将双打的磁盘从磁盘换到内存时,不要这样做

double swap(double a); // THIS IS NEVER THE RIGHT THING TO DO.

传入double by value可以通过浮点寄存器传入。因为并非所有位组合都是有效双精度数,所以处理器可以静默地将双精度转换为NaN,其可能具有与传入的值不同的位表示。这更有可能发生在具有相反字节顺序的有效双精度。 (有关更详细的说明,请参阅here。)

换句话说,将你想要的double传递给byteswap作为指针或字符数组。 (字符数组应该是最好的选择。)