0

我正在尝试将严格的二进制数据写入文件(无编码)。问题是,当我对文件进行十六进制转储时,我注意到了相当奇怪的行为。使用以下任一方法构造文件都会导致相同的行为。我什至使用 System::Text::Encoding::Default 来测试流。

StreamWriter^ binWriter = gcnew StreamWriter(gcnew FileStream("test.bin",FileMode::Create));

(Also used this method)
FileStream^ tempBin = gcnew FileStream("test.bin",FileMode::Create);
BinaryWriter^ binWriter = gcnew BinaryWriter(tempBin);


binWriter->Write(0x80);
binWriter->Write(0x81);
.
.
binWriter->Write(0x8F);
binWriter->Write(0x90);
binWriter->Write(0x91);
.
.
binWriter->Write(0x9F);

写入该字节序列,我注意到在十六进制转储中唯一转换为 0x3F 的字节是 0x81,0x8D,0x90,0x9D ...我不知道为什么。

我也尝试过制作字符数组,类似的情况也发生了。IE,

array<wchar_t,1>^ OT_Random_Delta_Limits = {0x00,0x00,0x03,0x79,0x00,0x00,0x04,0x88};
binWriter->Write(OT_Random_Delta_Limits);

0x88 将被写为 0x3F。

有任何想法吗?

4

3 回答 3

3

如果你想坚持二进制文件,那么不要使用StreamWriter. 只需使用一个FileStreamWrite/ WriteByte。StreamWriters(和一般的 TextWriters)是专门为text设计的。无论您是否想要编码,都会应用一个 - 因为当您调用 时StreamWriter.Write,那是在写 a char,而不是 a byte

也不要创建wchar_t值数组——同样,这些是用于字符的,即文本。

BinaryWriter.Write应该对你有用,除非它正在提升价值观,char在这种情况下你会遇到完全相同的问题。

顺便说一句,在不指定任何编码的情况下,我希望您获得非 0x3F 值,而是代表这些字符的 UTF-8 编码值的字节。

当您指定 时Encoding.Default,您会看到 0x3F 用于不在该编码中的任何 Unicode 值。

无论如何,基本的教训是Stream当你想处理二进制数据而不是文本时要坚持。

编辑:好的,它会是这样的:

public static void ConvertHex(TextReader input, Stream output)
{
    while (true)
    {
        int firstNybble = input.Read();
        if (firstNybble == -1)
        {
            return;
        }
        int secondNybble = input.Read();
        if (secondNybble == -1)
        {
            throw new IOException("Reader finished half way through a byte");
        }
        int value = (ParseNybble(firstNybble) << 4) + ParseNybble(secondNybble);
        output.WriteByte((byte) value);
    }
}

// value would actually be a char, but as we've got an int in the above code,
// it just makes things a bit easier
private static int ParseNybble(int value)
{
    if (value >= '0' && value <= '9') return value - '0';
    if (value >= 'A' && value <= 'F') return value - 'A' + 10;
    if (value >= 'a' && value <= 'f') return value - 'a' + 10;
    throw new ArgumentException("Invalid nybble: " + (char) value);
}

这在缓冲等方面效率非常低,但应该让你开始。

于 2009-11-04T21:27:34.240 回答
0

0x3F 俗称 ASCII 字符 '?';映射到它的字符是没有可打印表示的控制字符。正如 Jon 所指出的,对原始二进制数据使用二进制流而不是面向文本的输出机制。

编辑——实际上你的结果看起来与我期望的相反。在默认代码页 1252中,该范围内的不可打印字符(即可能映射到“?”的字符)为 0x81、0x8D、0x8F、0x90 和 0x9D

于 2009-11-04T21:29:27.490 回答
0

使用流初始化的BinaryWriter()类将对写入的任何字符或字符串使用默认的 UTF8 编码。我猜是

binWriter->Write(0x80);
binWriter->Write(0x81);
.
.
binWriter->Write(0x8F);
binWriter->Write(0x90);
binWriter->Write(0x91);

调用绑定到Write( char)重载,因此它们要通过字符编码器。我对 C++/CLI 不是很熟悉,但在我看来,这些调用应该绑定到Write(Int32),这不应该有这个问题(也许你的代码实际上是Write()用一个char设置为你的例子中的值的变量调用的。这将解释这种行为)。

于 2009-11-04T21:37:12.953 回答