C# 如何将int写入System.Span,即int.Parse(Span)的反向?
我需要编写和读取大型CSV(逗号分隔值)文件,这些文件基本上包含转换为字符串的整数值。为了高效地读取此类文件,.Net Core为类型C# 如何将int写入System.Span,即int.Parse(Span)的反向?,c#,.net-core,C#,.net Core,我需要编写和读取大型CSV(逗号分隔值)文件,这些文件基本上包含转换为字符串的整数值。为了高效地读取此类文件,.Net Core为类型int引入了一种新的Parse方法: public static int Parse (ReadOnlySpan<char> s, System.Globalization.NumberStyles style = System.Globalization.NumberStyles.Integer, IFormatProvider provi
int
引入了一种新的Parse
方法:
public static int Parse (ReadOnlySpan<char> s,
System.Globalization.NumberStyles style =
System.Globalization.NumberStyles.Integer, IFormatProvider provider = null);
同样,对于每一个int
都会创建一个string
,然后为每一行创建另一个string
。这将创建数百万个需要进行垃圾收集的字符串
我更喜欢这样的:
char[] charArray = getEmptyCharArray();
var span = new Span<char>(charArray);
int length1 = span.Write(int1);
charArray[length1] = ',';
span = span.Slice(length1 + 1);
int length2 = span.Write(int2);
streamWriter.Write(charArray, 0, length1 + 1 + length2);
char[]charArray=getEmptyCharArray();
var span=新span(charArray);
int length1=span.Write(int1);
charArray[长度1]=',';
span=span.切片(长度1+1);
int length2=span.Write(int2);
streamWriter.Write(字符,0,长度1+1+2);
getEmptyCharray()
提供了一个可重用的字符数组
不幸的是,Span
没有Write()
函数:-(
因此,问题是:如何在不生成任何垃圾收集对象(字符串)的情况下,将int
(或DateTime
或Decimal
或…)写入Span
请注意,2018年之前给出的任何答案可能都不是本文所需要的,因为
System.Span
仅在.NET Core 2.1中介绍。还要注意,这里的问题是关于System.Span
的,而不是HTML Span或任何其他Span。如何尝试将int
直接解析为char
数组通过传递所有数字,将其转换为char
-s,并将其直接存储到目标
public static ReadOnlySpan<char> ToSpan(int src)
{
int len = GetLength(src);
Span<char> chars = new char[len];
for (int i = 0; i < chars.Length; i++)
{
chars[i]= (char)((Math.Floor(src / Math.Pow(10, (chars.Length - i - 1))) % 10) + 48);
}
return chars;
static int GetLength(int src)
{
int len = 0;
while (src > 0)
{
src = src / 10;
len++;
}
return len;
}
}
static void Main(string[] args)
{
int original = 3334;
var data = ToSpan(original);
var copy= int.Parse(data);
Console.WriteLine(copy);
}
publicstaticreadonlyspan-ToSpan(int-src)
{
int len=GetLength(src);
Span字符=新字符[len];
for(int i=0;i0)
{
src=src/10;
len++;
}
回程透镜;
}
}
静态void Main(字符串[]参数)
{
int-original=3334;
var数据=ToSpan(原始);
var copy=int.Parse(数据);
控制台写入线(副本);
}
p.S
int
上迭代,以获得目标的长度多亏了伊恩·肯特的评论,我继续问,他们知道答案。答案非常简单:
var i = 1;
Span<char> span = new char[100];
var ok = i.TryFormat(span, out var charsWritten);
var i=1;
Span=新字符[100];
var ok=i.TryFormat(范围,写出var字符);
由于我有几天没有找到这个答案,并且我想继续编写代码,所以我编写了自己的方法,但使用char[]而不是Span。我使用BenchmarkRunner测量了不同方法编写50兆字节的CSV文件(包含7'000'000整数)的速度:
60毫秒:写入相同的常量字符串。这给出了DotNet只需写入文件所需的基线时间
public void WriteTo4() {
var PathFileName = directoryInfo.FullName + @"\Test1.csv";
using (var fileStream = new FileStream(PathFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, bufferSize, FileOptions.SequentialScan)) {
using (var streamWriter = new StreamWriter(fileStream)) {
var lineBuffer = new char[100];
Span<char> span = lineBuffer;
for (int i = 0; i < iterations; i++) {
var ok = i.TryFormat(span, out var charsWritten);
lineBuffer[charsWritten++] = ';';
var span1 = span[charsWritten..];
ok = (i+1).TryFormat(span1, out charsWritten);
span1[charsWritten++] = ';';
span1 = span1[charsWritten..];
ok = (i+2).TryFormat(span1, out charsWritten);
span1[charsWritten++] = ';';
span1 = span1[charsWritten..];
ok = (i+3).TryFormat(span1, out charsWritten);
span1[charsWritten++] = ';';
span1 = span1[charsWritten..];
ok = (i+4).TryFormat(span1, out charsWritten);
span1[charsWritten++] = ';';
span1 = span1[charsWritten..];
ok = (i+5).TryFormat(span1, out charsWritten);
span1[charsWritten++] = ';';
span1 = span1[charsWritten..];
ok = (i+6).TryFormat(span1, out charsWritten);
span1[charsWritten++] = ';';
var ca = lineBuffer[..(lineBuffer.Length - span1.Length + charsWritten)];
streamWriter.WriteLine(lineBuffer, 0, lineBuffer.Length - span1.Length + charsWritten);
}
}
}
}
对于(int i=0;ipublic void WriteTo3() {
var PathFileName = directoryInfo.FullName + @"\Test1.csv";
using (var fileStream = new FileStream(PathFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, bufferSize, FileOptions.SequentialScan)) {
using (var streamWriter = new StreamWriter(fileStream)) {
var lineBuffer = new char[100];
for (int i = 0; i < iterations; i++) {
var index = 0;
lineBuffer.Write3(i, ref index);
lineBuffer[index++] = ';';
lineBuffer.Write3(i+1, ref index);
lineBuffer[index++] = ';';
lineBuffer.Write3(i+2, ref index);
lineBuffer[index++] = ';';
lineBuffer.Write3(i+3, ref index);
lineBuffer[index++] = ';';
lineBuffer.Write3(i+4, ref index);
lineBuffer[index++] = ';';
lineBuffer.Write3(i+5, ref index);
lineBuffer[index++] = ';';
lineBuffer.Write3(i+6, ref index);
lineBuffer[index++] = ';';
streamWriter.WriteLine(lineBuffer, 0, index);
}
}
}
}
public static void Write3(this char[] charArray, int i, ref int index) {
if (i<0) {
charArray[index++] = '-';
i = -i;
}
int start = index;
while (i>9) {
charArray[index++] = (char)((i % 10) + '0');
i /= 10;
}
charArray[index++] = (char)(i + '0');
var end = index-1;
while (end>start) {
var temp = charArray[end];
charArray[end--] = charArray[start];
charArray[start++] = temp;
}
}
令人惊讶的是,字符串对话所花费的时间是实际文件编写时间的10倍。我原以为硬盘比任何软件都慢
我们被告知,Span将解决许多性能问题。不会太多。如果他们使用char[],似乎会更好
跨度测试代码
public void WriteTo4() {
var PathFileName = directoryInfo.FullName + @"\Test1.csv";
using (var fileStream = new FileStream(PathFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, bufferSize, FileOptions.SequentialScan)) {
using (var streamWriter = new StreamWriter(fileStream)) {
var lineBuffer = new char[100];
Span<char> span = lineBuffer;
for (int i = 0; i < iterations; i++) {
var ok = i.TryFormat(span, out var charsWritten);
lineBuffer[charsWritten++] = ';';
var span1 = span[charsWritten..];
ok = (i+1).TryFormat(span1, out charsWritten);
span1[charsWritten++] = ';';
span1 = span1[charsWritten..];
ok = (i+2).TryFormat(span1, out charsWritten);
span1[charsWritten++] = ';';
span1 = span1[charsWritten..];
ok = (i+3).TryFormat(span1, out charsWritten);
span1[charsWritten++] = ';';
span1 = span1[charsWritten..];
ok = (i+4).TryFormat(span1, out charsWritten);
span1[charsWritten++] = ';';
span1 = span1[charsWritten..];
ok = (i+5).TryFormat(span1, out charsWritten);
span1[charsWritten++] = ';';
span1 = span1[charsWritten..];
ok = (i+6).TryFormat(span1, out charsWritten);
span1[charsWritten++] = ';';
var ca = lineBuffer[..(lineBuffer.Length - span1.Length + charsWritten)];
streamWriter.WriteLine(lineBuffer, 0, lineBuffer.Length - span1.Length + charsWritten);
}
}
}
}
public void WriteTo4(){
var PathFileName=directoryInfo.FullName+@“\Test1.csv”;
使用(var fileStream=newfilestream(路径文件名、FileMode.OpenOrCreate、FileAccess.ReadWrite、FileShare.None、bufferSize、FileOptions.SequentialScan)){
使用(var streamWriter=newstreamwriter(fileStream)){
var lineBuffer=新字符[100];
Span=行缓冲区;
对于(int i=0;i
使用char[]测试代码
public void WriteTo3() {
var PathFileName = directoryInfo.FullName + @"\Test1.csv";
using (var fileStream = new FileStream(PathFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, bufferSize, FileOptions.SequentialScan)) {
using (var streamWriter = new StreamWriter(fileStream)) {
var lineBuffer = new char[100];
for (int i = 0; i < iterations; i++) {
var index = 0;
lineBuffer.Write3(i, ref index);
lineBuffer[index++] = ';';
lineBuffer.Write3(i+1, ref index);
lineBuffer[index++] = ';';
lineBuffer.Write3(i+2, ref index);
lineBuffer[index++] = ';';
lineBuffer.Write3(i+3, ref index);
lineBuffer[index++] = ';';
lineBuffer.Write3(i+4, ref index);
lineBuffer[index++] = ';';
lineBuffer.Write3(i+5, ref index);
lineBuffer[index++] = ';';
lineBuffer.Write3(i+6, ref index);
lineBuffer[index++] = ';';
streamWriter.WriteLine(lineBuffer, 0, index);
}
}
}
}
public static void Write3(this char[] charArray, int i, ref int index) {
if (i<0) {
charArray[index++] = '-';
i = -i;
}
int start = index;
while (i>9) {
charArray[index++] = (char)((i % 10) + '0');
i /= 10;
}
charArray[index++] = (char)(i + '0');
var end = index-1;
while (end>start) {
var temp = charArray[end];
charArray[end--] = charArray[start];
charArray[start++] = temp;
}
}
public void WriteTo3(){
var PathFileName=directoryInfo.FullName+@“\Test1.csv”;
使用(var fileStream=newfilestream(路径文件名,FileMode.OpenOrCreate,FileAccess.ReadWrite,FileShare.None,bufferSize,FileOptions.S