将字符串列表转换为字节数组

本文关键字:字节 字节数 数组 转换 字符串 列表 | 更新日期: 2023-09-27 18:07:33

我试图写一个方法,它接受一个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();
}

但是我得到:

参数类型'byte[]'不能赋值给参数类型'byte'byteList.Add (Encoding.UTF8.GetBytes (i));

我哪里错了?我如何正确地把这个列表变成一个字节数组?

将字符串列表转换为字节数组

更有效的方法是先将字符串连接在一起,然后将其转换为字节数组,如下所示:

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

嗯,像这样的东西(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));
}

你可以这样做:

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

我通过预先计算所需的总大小(在totalSize中)创建了一个大的buffer,然后我将其填充到foreach循环中。注意,使用ix变量将当前位置保存在buffer中。

与其他方法相比,该方法的优点是不需要复制字符串或字节数组。UTF8编码的字符串只在buffer缓冲区中写入一次,不会到处复制。

List.Add()只允许添加单个元素。您需要将GetBytes()结果放入数组中,遍历数组并将每个数组元素添加到列表中。
也许你找到一种方法将GetBytes数组转换为列表,并使用AddRange()

或者省略函数中的所有List,只处理数组。您可以使用Array.Resize,但这在性能方面不是最好的,因为这将包括大量的值复制。您最好使用字节数组的数组,计算所需的最终字节数组大小,然后将每个内部数组的数据复制到您的最终数组。