我尝试编写一个接受List<string>
的方法,然后将整个列表转换为一个大的字节数组。像这样:
private byte[] ConvertStringsToBytes(List<string> list)
{
List<byte> byteList = new List<byte>();
foreach (var i in list)
{
byteList.Add(Encoding.UTF8.GetBytes(i));
}
return byteList.ToArray();
}
但是我得到了:
参数类型&#39; byte []&#39;不能分配给参数类型&#39;字节&#39;上 byteList.Add(Encoding.UTF8.GetBytes(i));
我哪里错了?如何正确将此列表转换为一个字节数组?
答案 0 :(得分:6)
更有效的方法是首先将字符串连接在一起,然后将其转换为字节数组,如下所示:
List<string> input = new List<string> { "first", "second" };
string fullString = String.Join(String.Empty, list.ToArray());
byte[] byteArray = Encoding.UTF8.GetBytes(fullString);
如果性能很重要并且您在该列表中有很多字符串,那么您会喜欢这样: 编辑:在进行基准测试后,此方法确实比上述方法慢。
List<string> input = new List<string> { "first", "second" };
StringBuilder sb = new StringBuilder();
foreach (string s in input )
sb.Append(s);
byte[] byteArray = Encoding.UTF8.GetBytes(sb.ToString());
修改强> 对本文中提到的一些方法进行了一些基准测试。以下是发布版本的输出:
ConvertWithString 896ms
ConvertWithStringBuilder 858ms
ConvertWithConcat 1529ms
ConvertWithSelectMany 2234ms
ConvertWithBuffer 904ms
ConvertWithString 501ms
ConvertWithStringBuilder 919ms
ConvertWithConcat 1435ms
ConvertWithSelectMany 2044ms
ConvertWithBuffer 636ms
如果您没有很多的字符串,那么效果似乎并不重要。
这是代码:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
internal class Program
{
static byte[] ConvertWithBuffer(List<string> list)
{
int totalSize = list.Sum(x => Encoding.UTF8.GetByteCount(x));
byte[] buffer = new byte[totalSize];
int ix = 0;
foreach (string str in list)
ix += Encoding.UTF8.GetBytes(str, 0, str.Length, buffer, ix);
return buffer;
}
static byte[] ConvertWithConcat(List<string> list) { return Encoding.UTF8.GetBytes(String.Concat(list)); }
static byte[] ConvertWithSelectMany(List<string> list)
{
return list
.SelectMany(line => Encoding.UTF8.GetBytes(line))
.ToArray();
}
static byte[] ConvertWithString(List<string> input)
{
string fullString = String.Join(String.Empty, input.ToArray());
return Encoding.UTF8.GetBytes(fullString);
}
static byte[] ConvertWithStringBuilder(List<string> input)
{
StringBuilder sb = new StringBuilder();
foreach (string s in input)
sb.Append(s);
return Encoding.UTF8.GetBytes(sb.ToString());
}
static IEnumerable<string> CreateList()
{
for (int i = 0; i < 10000000; i++)
yield return i.ToString();
}
static void Main(string[] args)
{
List<string> strings = CreateList().ToList();
Stopwatch stopWatch = Stopwatch.StartNew();
// warm up
ConvertWithString(strings);
ConvertWithStringBuilder(strings);
ConvertWithConcat(strings);
ConvertWithSelectMany(strings);
ConvertWithBuffer(strings);
// testing
stopWatch.Restart();
ConvertWithString(strings);
Console.WriteLine("ConvertWithString {0}ms", stopWatch.ElapsedMilliseconds);
stopWatch.Restart();
ConvertWithStringBuilder(strings);
Console.WriteLine("ConvertWithStringBuilder {0}ms", stopWatch.ElapsedMilliseconds);
stopWatch.Restart();
ConvertWithConcat(strings);
Console.WriteLine("ConvertWithConcat {0}ms", stopWatch.ElapsedMilliseconds);
stopWatch.Restart();
ConvertWithSelectMany(strings);
Console.WriteLine("ConvertWithSelectMany {0}ms", stopWatch.ElapsedMilliseconds);
stopWatch.Restart();
ConvertWithBuffer(strings);
Console.WriteLine("ConvertWithBuffer {0}ms", stopWatch.ElapsedMilliseconds);
Console.WriteLine("press any key...");
Console.ReadKey();
}
}
}
答案 1 :(得分:3)
呃,这样的事情( Linq )?
private byte[] ConvertStringsToBytes(List<string> list) {
return list
.SelectMany(line => Encoding.UTF8.GetBytes(line))
.ToArray();
}
另一种可能性是
private byte[] ConvertStringsToBytes(List<string> list) {
return Encoding.UTF8.GetBytes(String.Concat(list));
}
答案 2 :(得分:1)
你可以这样做:
private static byte[] ConvertStringsToBytes(List<string> list)
{
int totalSize = list.Sum(x => Encoding.UTF8.GetByteCount(x));
byte[] buffer = new byte[totalSize];
int ix = 0;
foreach (string str in list)
{
ix += Encoding.UTF8.GetBytes(str, 0, str.Length, buffer, ix);
}
return buffer;
}
我通过预先计算所需的总大小(buffer
)来创建一个大的totalSize
,然后在foreach
周期中填充它。请注意使用ix
变量来保存buffer
中的当前位置。
此方法优于其他方法的优点是不会复制字符串或字节数组。 UTF8编码的字符串只在buffer
缓冲区中写入一次,不会被复制。
答案 3 :(得分:0)
List.Add()
可让您只添加一个元素。您需要将GetBytes()
结果放入数组中,遍历数组并将每个数组元素添加到列表中。
也许您找到了将GetBytes数组转换为列表并使用AddRange()
...
或者,您省略函数中的所有List
并仅使用数组。你可以使用Array.Resize
,但这在性能方面是最好的,因为这将包括大量的价值复制。你最好使用一个byte数组数组,计算所需的最终字节数组大小,然后将每个内部数组的数据复制到你的最终数组。