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

时间:2021-08-30 18:25:42

I wrote one app using C# to read data from a serial port and show the data on a textbox in hex string format. Finally, I saved all data to a binary file. If data is big (maybe > 20mb) it throws an out of memory error. How can I solve this? Here is my code:

我使用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 个解决方案

#1


2  

You're creating the byte array twice. Also, the .Replace over such a long string doesn't help. You can avoid all this:

你正在创建两次字节数组。此外,.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();
        }
    }
}

Also, take a look at Encoding and/or BinaryFormatter which might do all of this for you.

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

Update:

更新:

First of all, please note that your whole idea of storing megabytes of data in a string is a nonsense, and you shouldn't do that. You should process your data in smaller parts. Because of this nonsense I'm unable to provide you with a working demo (on IDEONE for example), because of resource limitations of online compilers. I've tested the code on my machine, and as you can see I can even process 50 MB strings - but it all depends on the amount of memory you have available. If you do such things, then on every machine it will be easy to reach the limit of available memory. And the methods you ask about in this particular question are irrelevant - the problem is because you fill your memory with tons of data in your Content.Text string. When memory is almost full, the OutOfMemoryException can occur at almost any place in your code.

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

You can view the whole picture in your browser to see all the details.

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

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

#2


1  

Use IEnumerable. That will avoid the large byte array.

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

I don't know what is in Content.Text. If it's a byte array, maybe you can change

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

static internal IEnumerable<byte>Hex_to_Byte(string s)

into

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

and modify the code a bit

并稍微修改一下代码

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;
    }

#1


2  

You're creating the byte array twice. Also, the .Replace over such a long string doesn't help. You can avoid all this:

你正在创建两次字节数组。此外,.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();
        }
    }
}

Also, take a look at Encoding and/or BinaryFormatter which might do all of this for you.

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

Update:

更新:

First of all, please note that your whole idea of storing megabytes of data in a string is a nonsense, and you shouldn't do that. You should process your data in smaller parts. Because of this nonsense I'm unable to provide you with a working demo (on IDEONE for example), because of resource limitations of online compilers. I've tested the code on my machine, and as you can see I can even process 50 MB strings - but it all depends on the amount of memory you have available. If you do such things, then on every machine it will be easy to reach the limit of available memory. And the methods you ask about in this particular question are irrelevant - the problem is because you fill your memory with tons of data in your Content.Text string. When memory is almost full, the OutOfMemoryException can occur at almost any place in your code.

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

You can view the whole picture in your browser to see all the details.

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

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

#2


1  

Use IEnumerable. That will avoid the large byte array.

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

I don't know what is in Content.Text. If it's a byte array, maybe you can change

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

static internal IEnumerable<byte>Hex_to_Byte(string s)

into

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

and modify the code a bit

并稍微修改一下代码

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;
    }