文件中的变量(long,double ...)是否以错误的方式存储?

Are variables (long, double...) in files stored the wrong way round?

下面的问题让我很困惑:

我正在试验如何将 doubles,尤其是它们的 'special' 值(如 PositiveInfinity)存储在文件中,这没问题。我通过三个简单的步骤完成了此操作:创建 double;将其写入文件;将文件读入 byte 数组。这很简单,现在我知道 Double.NaN 的二进制格式是什么样子了:)

但后来我遇到了以下情况:

根据 .Net-Framework 有一个 NegativeZero:

internal static double NegativeZero = BitConverter.Int64BitsToDouble(unchecked((long)0x8000000000000000));

它的表示方式非常简单(遵循 IEEE 754):

long代表二进制数:10000000...

第一位表示 double 是负数。所以代表 NegativeZero 的是 - 0 * 2^0 因为尾数和指数都是 0.

表示 'normal' 0 将是 64 位全部设置为 0


但问题是将这些数字读入 byte 数组。我认为 NegativeZero 的内容如下:128 0 0... [二进制:100000...]

但实际上是错误的方式:0 0...128! [二进制:00000...0 10000000]

我的第一个想法是:'Maybe File.ReadAllBytes() returns everthing in the wrong order (which would be awkward)'。所以我决定用 string 测试 reader (-> 创建一个带有字符串的文件;将其读入 byte 数组)

结果很好:'Hello' 仍然是 byte 数组中的 'Hello' 而不是上面提出的示例 'olleH'.


再次简而言之:

将二进制数 (10000000 00000000 00000000) 写入文件工作正常。

将同一个二进制数读入byte数组结果为:

[0]00000000 [1]00000000 [2]10000000

读取文件不是问题,因为 strings 保持不变。

但是:将 byte 数组解释回原始变量(long、double...)returns 正确的结果。

所以在我看来,变量的 bytes 存储顺序错误。

这是真的吗?如果是这样,为什么这样做,因为在我看来这似乎违反了 IEEE 754(但它显然有效)?

如果我在这里遗漏了什么,请纠正我,因为在搜索这个问题的答案数小时后我仍然很困惑...

关于多字节结构中的字节顺序没有通用规则。

little-endian 方法会将四字节数字 0x01020304 放入字节中,顺序为 0x040x030x020x01 .

big-endian 方法会将相同的四字节数字按照 0x010x020x030x04.[=32 的顺序放入字节中=]

这些都不是正确的,也不是不正确的,尽管显然使用一种方法的系统需要一些转换才能与使用另一种方法的系统进行互操作。

(甚至还有0x030x040x010x020x020x010x04, 0x03 但它们要少得多,并且通常是由于某些东西将 4 字节值视为两个双字节值,并使用大端排序方法进行排序,然后以小端方式处理这些值方法,反之亦然)。

如果您使用的是 .NET,您可能正在使用 Intel 芯片或与其兼容的芯片,并且它们使用小端顺序在内存中存储值。直接从内存复制到文件或返回将导致小端文件。

现在,字符串是字符序列,它在内存中的表示形式是按某种顺序排列的字节序列。与 "Hello" 一样,我们将有某种形式的 H 后跟 e 后跟 l 等等。

无论系统是小端还是大端,都会出现这种情况。

但是,如果其中一个字符的表示不是单字节,则该表示可能会受到字节顺序的影响。

最常见的现代文件使用表示法(实际上是唯一一种 99% 的时间都在使用)是 UTF-8。 UTF-8 将为代码点高于 U+007F 的字符定义多字节序列,但该序列的顺序由 UTF-8 本身定义,因此不受字节顺序的影响。

第二个最常见的现代表示形式(如果您有充分的理由,将在剩余 1% 的时间内使用该表示形式)是 UTF-16。 UTF-16 将字符作为 16 位单元处理,或者对于 U+FFFF 以上的字符作为两个 16 位单元处理。在使用两个 16 位单元的情况下,这些单元的顺序在 UTF-16 本身中指定。但是,表示那些 16 位单元的两个八位字节的顺序未在此级别指定,因此受字节序的影响。

因此,UTF-16 可以用字节表示为 UTF-16LE 或 UTF-16BE,或者在文件开头带有字节顺序标记的一个或另一个,以便阅读软件确定哪个在采用。因此,使用 UTF-16 "hello" 可能是:

0x00 0x68 0x00 0x65 0x00 0x6C 0x00 0x6C 0x00 0x6F

或者可以是:

0x68 0x00 0x65 0x00 0x6C 0x00 0x6C 0x00 0x6F 0x00