将十六进制字符串转换为bytearray并写入文件

时间:2014-04-24 08:05:29

标签: c# .net winforms io

我使用C#编写了一个应用程序,用于从串行端口读取数据,并以十六进制字符串格式显示文本框中的数据。最后,我将所有数据保存到二进制文件中。如果数据很大(可能> 20mb),则会引发内存不足错误。我怎么解决这个问题?这是我的代码:

private void btn_Save_Click(object sender, EventArgs e)
{
    SaveFileDialog save_log = new SaveFileDialog();
    save_log.DefaultExt = ".bin";
    save_log.Filter = "Binary File (*.bin)|*.bin";
    // Determine if the user selected a file name from the saveFileDialog.
    if (save_log.ShowDialog() == System.Windows.Forms.DialogResult.OK &&
        save_log.FileName.Length > 0)
    {
        try
        {
            string hexString = Content.Text.ToString();
            FileStream stream = new FileStream(save_log.FileName, FileMode.Create, FileAccess.ReadWrite);
            stream.Write(Hex_to_ByteArray(hexString), 0, Hex_to_ByteArray(hexString).Length);
            stream.Close();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
}

private byte[] Hex_to_ByteArray(string s)
{
    s = s.Replace(" ", "");
    byte[] buffer = new byte[s.Length / 2];
    for (int i = 0; i < s.Length; i += 2)
    {
        buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
    }
    return buffer;
}

2 个答案:

答案 0 :(得分:2)

您正在创建两次字节数组。此外,.Replace超过这么长的字符串也无济于事。你可以避免这一切:

try
{
    var stream = new FileStream(
        save_log.FileName,
        FileMode.Create,
        FileAccess.ReadWrite);

    WriteHexStringToFile(Content.Text, stream);

    stream.Close();
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}

private void WriteHexStringToFile(string hexString, FileStream stream)
{
    var twoCharacterBuffer = new StringBuilder();
    var oneByte = new byte[1];
    foreach (var character in hexString.Where(c => c != ' '))
    {
        twoCharacterBuffer.Append(character);

        if (twoCharacterBuffer.Length == 2)
        {
            oneByte[0] = (byte)Convert.ToByte(twoCharacterBuffer.ToString(), 16);
            stream.Write(oneByte, 0, 1);
            twoCharacterBuffer.Clear();
        }
    }
}

另外,请查看Encoding和/或BinaryFormatter,它们可能会为您完成所有这些工作。

<强>更新

首先,请注意,您在字符串中存储数兆字节数据的整个想法是无稽之谈,您不应该这样做。您应该以较小的部分处理数据。由于这种无稽之谈,我无法为您提供工作演示(例如在IDEONE上),因为在线编译器的资源有限。我已经在我的机器上测试了代码,你可以看到我甚至可以处理50 MB的字符串 - 但这一切都取决于你可用的内存量。如果你做这些事情,那么在每台机器上都很容易达到可用内存的极限。你在这个特定问题中提出的方法是无关紧要的 - 问题是因为你在Content.Text字符串中填充了大量数据。当内存几乎已满时,OutOfMemoryException几乎可以在代码中的任何位置出现。

您可以在浏览器中查看整个图片以查看所有详细信息。

note the freehand circles

答案 1 :(得分:1)

使用IEnumerable。这将避免大字节数组。

我不知道Content.Text中有什么。如果它是一个字节数组,也许你可以改变

static internal IEnumerable<byte>Hex_to_Byte(string s)

进入

static internal IEnumerable<byte>Hex_to_Byte(byte[] bytes)

并稍微修改代码

FileStream stream = new FileStream(save_log.FileName, FileMode.Create, FileAccess.ReadWrite);
foreach( byte b in Hex_to_Byte(hexString) )
    stream.WriteByte(b);
stream.Close();



    static internal IEnumerable<byte>Hex_to_Byte(string s)
    {
        bool haveFirstByte = false;
        int firstByteValue = 0;

        foreach( char c in s)
        {
            if( char.IsWhiteSpace(c))
                continue;

            if( !haveFirstByte)
            {
                haveFirstByte = true;
                firstByteValue = GetHexValue(c) << 4;
            }
            else
            {
                haveFirstByte = false;
                yield return unchecked((byte)(firstByteValue + GetHexValue(c)));
            }

        }

    }
    static string hexChars = "0123456789ABCDEF";
    static int GetHexValue(char c)
    {
        int v = hexChars.IndexOf(char.ToUpper(c));
        if (v < 0)
            throw new ArgumentOutOfRangeException("c", string.Format("not a hex char: {0}"));
        return v;
    }