c#double to character array或alternative

我有一个程序存储一堆结构实例,其中包含许多double类型的成员。 我经常将这些转储到一个文件,我正在使用字符串构建器,例如:

StringBuilder builder = new StringBuilder(256); builder.AppendFormat("{0};{1};{2};", xAToString(), xBToString(), xCToString()); 

其中’x’是我的类型的实例,A,B,C是double类型的X的成员。 我在每个上面调用ToString()以避免装箱。 但是,这些对ToString的调用仍然在我的应用程序的上下文中分配了大量内存,我想减少这一点。 我的想法是拥有一个字符数组,并将每个成员直接写入该数组,然后从该字符数组创建一个字符串并将其转储到该文件中。 几个问题:

1)我想做的事情听起来合理吗? 有没有人知道会有类似的东西?

2)是否已经内置了将double转换为字符数组(我想这将达到一些参数化精度?)。 理想情况下想要传入我的数组和一些索引并让它开始写入那里。

我试图这样做的原因是当我的应用程序运行时减少内存中的大量峰值,因为我运行了很多实例并经常发现自己受内存限制。

干杯A.

该文件是否需要某种文本格式?

如果没有,到目前为止,最有效的方法是使用BinaryWriter(和BinaryReader读取它们)。

有关更多信息,请参阅http://msdn.microsoft.com/en-us/library/system.io.binarywriter.aspx 。

如果可以直接写入文本文件,则可以使用steamwriter编写强类型结构。 我没有测试内存使用情况,但我认为它们应该是高效的

  using (var tw = new System.IO.StreamWriter("filename", true)) //(true to append to file) { tw.Write(xA); tw.Write(';'); } 

如果需要stringbuilder,也可以使用以下方法调用强类型重载:

  builder.Append(xA) //strongly typed as long as the field is a system type .Append(';') .Append(xB) .Append(';'); 

当然,这两种方法在实现某种循环或委托方面看起来会更好,但这与装箱逻辑不同。

编辑自定义双写在其他答案中张贴: c#double to character array或alternative

您应该直接写入文件流以减少内存利用率。

 using(var writer = new StreamWriter(...)) { writer.Write(xA); writer.Write(";"); writer.Write(xB); writer.Write(";"); writer.Write(xC); } 

你确定它是可能的许多Double.ToString调用导致你的内存问题吗? 应该在下一代0集合上收集每个字符串,并且.NET垃圾收集器在执行此操作时非常有效。

如果你创建的字符串超过85K,它们将在大对象堆上创建,这可能会增加应用程序所需的总内存,即使大字符串只是暂时存在(大对象堆碎片)。

您可以使用性能监视器来了解有关应用程序如何使用托管堆的更多信息。 你已经使用了CLRProfiler这是一个更高级的工具,所以也许你不会学到任何新东西。

StringBuilder是用于在内存中构建字符串的正确类,但如果您只在内存中构建字符串以便稍后将其写入文件,则应使用StreamWriter直接写入文件。

StringBuilder必须扩展用于存储字符串的缓冲区,并且您可以通过提前设置StringBuilder的容量来避免这种额外开销(您已在示例代码中执行此操作)。

无论你调用什么重载将Double格式化为StringBuilder ,调用最终都会导致调用Double.ToStringStringBuilder.AppendFormat直接格式化到缓冲区而不分配额外的格式化字符串,因此在内存使用方面, StringBuilder.AppendFormatStringBuilder.Append一样好,并且两个重载都将分配带格式化Double的字符串作为格式化过程的一部分。 但是, StringBuilder.AppendFormat将为Double StringBuilder.AppendFormat ,因为它接受params Object[]数组。 使用接受DoubleStringBuilder.Append重载不会遇到此问题。

如果您确定知道Double.ToString是您的内存问题的根源,我相信您最好的选择是编写自己的浮点格式代码,该代码可以将浮点数直接写入StringBuilder 。 这项任务非常重要,但您可以从开源C库中获取灵感。

出于对如何去做的纯粹好奇,我无法抗拒试图创造一个直接写双打的场景。 结果如下。 我没有对它进行基准测试,但它确实在我运行的(有限)测试中按预期工作。

  double[] test = { 8.99999999, -4, 34.567, -234.2354, 2.34, 500.8 }; using (var sw = new FileStream(@"c:\temp\test.txt", FileMode.Create)) { using (var bw = new BinaryWriter(sw)) { const byte semicol = 59, minus = 45, dec = 46, b0 = 48; Action write = d => { if (d == 0) bw.Write(b0); else { if (d < 0) { bw.Write(minus); d = -d; } double m = Math.Pow(10d, Math.Truncate(Math.Log10(d))); while(true) { var r = ((decimal)(d / m) % 10); //decimal because of floating point errors if (r == 0) break; if (m == 0.1) bw.Write(dec); //decimal point bw.Write((byte)(48 + r)); m /= 10d; } } bw.Write(semicol); }; foreach (var d in test) write(d); } }