我使用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;
}
答案 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
几乎可以在代码中的任何位置出现。
您可以在浏览器中查看整个图片以查看所有详细信息。
答案 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;
}