byte[]を に変換するにはどうすればよいstringですか? 私がそれを試みるたびに、私は得る
System.Byte[]
値の代わりに。
また、10 進数ではなく 16 進数で値を取得するにはどうすればよいですか?
これには組み込みのメソッドがあります。
byte[] data = { 1, 2, 4, 8, 16, 32 };
string hex = BitConverter.ToString(data);
結果:01-02-04-08-10-20
ダッシュなしで使用したい場合は、ダッシュを削除してください。
string hex = BitConverter.ToString(data).Replace("-", string.Empty);
結果:010204081020
よりコンパクトな表現が必要な場合は、Base64を使用できます。
string base64 = Convert.ToBase64String(data);
結果:AQIECBAg
ここにリストされている各方法の速度を比較しようと思いました. これに基づいて速度テストコードを作成しました。
その結果、BitConverter+String.Replace は、他のほとんどの単純な方法よりも高速に見えます。しかし、Nathan Moinvaziri の ByteArrayToHexStringや Kurt の ToHex などのアルゴリズムを使用すると、速度を向上させることができます。
また、string.Concat と string.Join は、長い文字列の場合は StringBuilder の実装よりもはるかに遅くなりますが、短い配列の場合は同様であることも興味深いと思いました。おそらく、より長い文字列で StringBuilder を拡張するため、初期サイズを設定すると、この違いが打ち消されます。
と:
LONG_STRING_LENGTH = 1000 * 1024;
- BitConvertRep 計算 経過時間27,202 ms (最速内蔵/シンプル)
- StringBuilder の計算時間経過 75,723 ミリ秒 (StringBuilder 再割り当てなし)
- LinqConcat 計算 経過時間 182,094 ミリ秒
- LinqJoin 計算 経過時間 181,142 ms
- LinqAgg 計算時間経過 93,087 ミリ秒 (再割り当てを伴う StringBuilder)
- ToHex 計算 経過時間19,167 ms (最速)
と:
LONG_STRING_LENGTH = 100 * 1024;, 同様の結果
- BitConvertReplace 計算 経過時間 3431 ms
- StringBuilder 計算 経過時間 8289 ミリ秒
- LinqConcat 計算 経過時間 21512 ms
- LinqJoin 計算 経過時間 19433 ms
- LinqAgg 計算 経過時間 9230 ms
- ToHex 計算 経過時間 1976 ms
あり:
int MANY_STRING_COUNT = 1000;int MANY_STRING_LENGTH = 1024;(最初のテストと同じバイト数ですが、配列が異なります)
- BitConvertReplace 計算 経過時間 25,680 ms
- StringBuilder 計算経過時間 78,411 ミリ秒
- LinqConcat 計算 経過時間 101,233 ミリ秒
- LinqJoin 計算経過時間 99,311 ms
- LinqAgg 計算 経過時間 84,660 ミリ秒
- ToHex 計算 経過時間 18,221 ms
と:
int MANY_STRING_COUNT = 2000;int MANY_STRING_LENGTH = 20;
- BitConvertReplace 計算 経過時間 1347 ms
- StringBuilder 計算 経過時間 3234 ms
- LinqConcat 計算 経過時間 5013 ms
- LinqJoin 計算 経過時間 4826 ms
- LinqAgg 計算 経過時間 3589 ms
- ToHex 計算 経過時間 772 ms
私が使用したテストコード:
void Main()
{
int LONG_STRING_LENGTH = 100 * 1024;
int MANY_STRING_COUNT = 1024;
int MANY_STRING_LENGTH = 100;
var source = GetRandomBytes(LONG_STRING_LENGTH);
List<byte[]> manyString = new List<byte[]>(MANY_STRING_COUNT);
for (int i = 0; i < MANY_STRING_COUNT; ++i)
{
manyString.Add(GetRandomBytes(MANY_STRING_LENGTH));
}
var algorithms = new Dictionary<string,Func<byte[], string>>();
algorithms["BitConvertReplace"] = BitConv;
algorithms["StringBuilder"] = StringBuilderTest;
algorithms["LinqConcat"] = LinqConcat;
algorithms["LinqJoin"] = LinqJoin;
algorithms["LinqAgg"] = LinqAgg;
algorithms["ToHex"] = ToHex;
algorithms["ByteArrayToHexString"] = ByteArrayToHexString;
Console.WriteLine(" === Long string test");
foreach (var pair in algorithms) {
TimeAction(pair.Key + " calculation", 500, () =>
{
pair.Value(source);
});
}
Console.WriteLine(" === Many string test");
foreach (var pair in algorithms) {
TimeAction(pair.Key + " calculation", 500, () =>
{
foreach (var str in manyString)
{
pair.Value(str);
}
});
}
}
// Define other methods and classes here
static void TimeAction(string description, int iterations, Action func) {
var watch = new Stopwatch();
watch.Start();
for (int i = 0; i < iterations; i++) {
func();
}
watch.Stop();
Console.Write(description);
Console.WriteLine(" Time Elapsed {0} ms", watch.ElapsedMilliseconds);
}
//static byte[] GetRandomBytes(int count) {
// var bytes = new byte[count];
// (new Random()).NextBytes(bytes);
// return bytes;
//}
static Random rand = new Random();
static byte[] GetRandomBytes(int count) {
var bytes = new byte[count];
rand.NextBytes(bytes);
return bytes;
}
static string BitConv(byte[] data)
{
return BitConverter.ToString(data).Replace("-", string.Empty);
}
static string StringBuilderTest(byte[] data)
{
StringBuilder sb = new StringBuilder(data.Length*2);
foreach (byte b in data)
sb.Append(b.ToString("X2"));
return sb.ToString();
}
static string LinqConcat(byte[] data)
{
return string.Concat(data.Select(b => b.ToString("X2")).ToArray());
}
static string LinqJoin(byte[] data)
{
return string.Join("",
data.Select(
bin => bin.ToString("X2")
).ToArray());
}
static string LinqAgg(byte[] data)
{
return data.Aggregate(new StringBuilder(),
(sb,v)=>sb.Append(v.ToString("X2"))
).ToString();
}
static string ToHex(byte[] bytes)
{
char[] c = new char[bytes.Length * 2];
byte b;
for(int bx = 0, cx = 0; bx < bytes.Length; ++bx, ++cx)
{
b = ((byte)(bytes[bx] >> 4));
c[cx] = (char)(b > 9 ? b - 10 + 'A' : b + '0');
b = ((byte)(bytes[bx] & 0x0F));
c[++cx] = (char)(b > 9 ? b - 10 + 'A' : b + '0');
}
return new string(c);
}
public static string ByteArrayToHexString(byte[] Bytes)
{
StringBuilder Result = new StringBuilder(Bytes.Length*2);
string HexAlphabet = "0123456789ABCDEF";
foreach (byte B in Bytes)
{
Result.Append(HexAlphabet[(int)(B >> 4)]);
Result.Append(HexAlphabet[(int)(B & 0xF)]);
}
return Result.ToString();
}
また、同様のプロセスで別の回答がありますが、まだ結果を比較していません。
Hex、Linq-fu:
string.Concat(ba.Select(b => b.ToString("X2")).ToArray())
時代に合わせてUPDATE
@RubenBartelink が指摘したようIEnumerable<string>に、配列への変換を持たないコード: ba.Select(b => b.ToString("X2"))4.0 より前では機能しません。同じコードが 4.0 で機能しています。
このコード...
byte[] ba = { 1, 2, 4, 8, 16, 32 };
string s = string.Concat(ba.Select(b => b.ToString("X2")));
string t = string.Concat(ba.Select(b => b.ToString("X2")).ToArray());
Console.WriteLine (s);
Console.WriteLine (t);
....NET 4.0 より前の場合、出力は次のようになります。
System.Linq.Enumerable+<CreateSelectIterator>c__Iterator10`2[System.Byte,System.String]
010204081020
.NET 4.0 以降では、string.Concat に IEnumerable を受け入れるオーバーロードがあります。したがって、4.0 では、上記のコードは変数 s と t の両方に対して同じ出力を持ちます。
010204081020
010204081020
4.0 より前でba.Select(b => b.ToString("X2"))は、 をオーバーロードに移動します。これは、 が適切なオーバーロードに移動する(object arg0)方法です。つまり、を文字列配列に変換する必要があります。4.0 より前では、string.Concat には 10 個のオーバーロード関数があり、4.0 では 12 個になりました。IEnumerable<string>(params string[] values)IEnumerable<string>
標準ライブラリ メソッドをラップするだけの場合でも、このような変換には拡張メソッドを使用するのが好きです。16 進数変換の場合、次の手作業で調整された (高速) アルゴリズムを使用します。
public static string ToHex(this byte[] bytes)
{
char[] c = new char[bytes.Length * 2];
byte b;
for(int bx = 0, cx = 0; bx < bytes.Length; ++bx, ++cx)
{
b = ((byte)(bytes[bx] >> 4));
c[cx] = (char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30);
b = ((byte)(bytes[bx] & 0x0F));
c[++cx]=(char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30);
}
return new string(c);
}
public static byte[] HexToBytes(this string str)
{
if (str.Length == 0 || str.Length % 2 != 0)
return new byte[0];
byte[] buffer = new byte[str.Length / 2];
char c;
for (int bx = 0, sx = 0; bx < buffer.Length; ++bx, ++sx)
{
// Convert first half of byte
c = str[sx];
buffer[bx] = (byte)((c > '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0')) << 4);
// Convert second half of byte
c = str[++sx];
buffer[bx] |= (byte)(c > '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0'));
}
return buffer;
}
答えを出すべきだと思いました。私のテストから、この方法は最速です
public static class Helper
{
public static string[] HexTbl = Enumerable.Range(0, 256).Select(v => v.ToString("X2")).ToArray();
public static string ToHex(this IEnumerable<byte> array)
{
StringBuilder s = new StringBuilder();
foreach (var v in array)
s.Append(HexTbl[v]);
return s.ToString();
}
public static string ToHex(this byte[] array)
{
StringBuilder s = new StringBuilder(array.Length*2);
foreach (var v in array)
s.Append(HexTbl[v]);
return s.ToString();
}
}
非常に高速な拡張方法 (反転あり):
public static class ExtensionMethods {
public static string ToHex(this byte[] data) {
return ToHex(data, "");
}
public static string ToHex(this byte[] data, string prefix) {
char[] lookup = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
int i = 0, p = prefix.Length, l = data.Length;
char[] c = new char[l * 2 + p];
byte d;
for(; i < p; ++i) c[i] = prefix[i];
i = -1;
--l;
--p;
while(i < l) {
d = data[++i];
c[++p] = lookup[d >> 4];
c[++p] = lookup[d & 0xF];
}
return new string(c, 0, c.Length);
}
public static byte[] FromHex(this string str) {
return FromHex(str, 0, 0, 0);
}
public static byte[] FromHex(this string str, int offset, int step) {
return FromHex(str, offset, step, 0);
}
public static byte[] FromHex(this string str, int offset, int step, int tail) {
byte[] b = new byte[(str.Length - offset - tail + step) / (2 + step)];
byte c1, c2;
int l = str.Length - tail;
int s = step + 1;
for(int y = 0, x = offset; x < l; ++y, x += s) {
c1 = (byte)str[x];
if(c1 > 0x60) c1 -= 0x57;
else if(c1 > 0x40) c1 -= 0x37;
else c1 -= 0x30;
c2 = (byte)str[++x];
if(c2 > 0x60) c2 -= 0x57;
else if(c2 > 0x40) c2 -= 0x37;
else c2 -= 0x30;
b[y] = (byte)((c1 << 4) + c2);
}
return b;
}
}
上記の速度テストで他のすべてを打ち負かします:
=== 長い文字列テスト
BitConvertReplace 計算 経過時間 2415 ミリ秒
StringBuilder 計算 経過時間 5668 ミリ秒
LinqConcat 計算 経過時間 11826 ミリ秒
LinqJoin 計算 経過時間 9323 ミリ秒
LinqAgg 計算 経過時間 7444 ミリ秒
ToHexTable 計算 経過時間 1028 ミリ秒
ToHexAcidzombie 計算 経過時間 1035 ミリ秒
ToHexPatrick 計算経過時間 814 ミリ秒
ToHexKurt 計算の経過時間 1604 ミリ秒
ByteArrayToHexString 計算の経過時間 1330 ミリ秒=== 多文字列テスト
BitConvertReplace 計算 経過時間 2238 ms
StringBuilder 計算 経過時間 5393 ms
LinqConcat 計算 経過時間 9043 ms
LinqJoin 計算 経過時間 9131 ms
LinqAgg 計算 経過時間 7324 ms
ToHexTable 計算 経過時間 968 ms
ToHexAcidzombie 計算 経過時間 969 ms
ToHexPatrick 計算経過時間 956 ミリ秒
ToHexKurt 計算の経過時間 1547 ミリ秒
ByteArrayToHexString 計算の経過時間 1277 ミリ秒
と:
byte[] data = new byte[] { 0x01, 0x02, 0x03, 0x0D, 0x0E, 0x0F };
string hex = string.Empty;
data.ToList().ForEach(b => hex += b.ToString("x2"));
// use "X2" for uppercase hex letters
Console.WriteLine(hex);
結果:0102030d0e0f
LINQ を文字列メソッドと組み合わせます。
string hex = string.Join("",
bin.Select(
bin => bin.ToString("X2")
).ToArray());
ここでは、値の代わりに「System.Byte[]」文字列を取得する理由について誰も言及していないので、そうします。
オブジェクトが文字列に暗黙的にキャストされると、プログラムは、public String ToString()から継承されたオブジェクトのメソッドにデフォルト設定されSystem.Objectます。
public virtual string ToString()
{
return this.GetType().ToString();
}
この変換を頻繁に行っている場合は、単純にラッパー クラスを作成し、このメソッドを次のようにオーバーライドできます。
public override string ToString()
{
// do the processing here
// return the nicely formatted string
}
このラッパー オブジェクトを印刷するたびに、 からの値ではなく、独自の値が取得されますthis.GetType().ToString()。
より高速なバイト配列から文字列へのコンバーターを作成したと思います。
public static class HexTable
{
private static readonly string[] table = BitConverter.ToString(Enumerable.Range(0, 256).Select(x => (byte)x).ToArray()).Split('-');
public static string ToHexTable(byte[] value)
{
StringBuilder sb = new StringBuilder(2 * value.Length);
for (int i = 0; i < value.Length; i++)
sb.Append(table[value[i]]);
return sb.ToString();
}
そして、テストのセットアップ:
static void Main(string[] args)
{
const int TEST_COUNT = 10000;
const int BUFFER_LENGTH = 100000;
Random random = new Random();
Stopwatch sw = new Stopwatch();
Stopwatch sw2 = new Stopwatch();
byte[] buffer = new byte[BUFFER_LENGTH];
random.NextBytes(buffer);
sw.Start();
for (int j = 0; j < TEST_COUNT; j++)
HexTable.ToHexTable(buffer);
sw.Stop();
sw2.Start();
for (int j = 0; j < TEST_COUNT; j++)
ToHexChar.ToHex(buffer);
sw2.Stop();
Console.WriteLine("Hex Table Elapsed Milliseconds: {0}", sw.ElapsedMilliseconds);
Console.WriteLine("ToHex Elapsed Milliseconds: {0}", sw2.ElapsedMilliseconds);
}
ToHexChar.ToHEx() メソッドは、前に示した ToHex() メソッドです。
結果は次のとおりです。
HexTable = 11808 ミリ秒 ToHEx = 12168 ミリ秒
それほど違いはないように見えるかもしれませんが、それでも高速です:)
これを行うためにパフォーマンスが必要かどうかはわかりませんが、バイト[]を16進文字列に変換する最速の方法は次のとおりです。
static readonly char[] hexchar = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
public static string HexStr(byte[] data, int offset, int len, bool space = false)
{
int i = 0, k = 2;
if (space) k++;
var c = new char[len * k];
while (i < len)
{
byte d = data[offset + i];
c[i * k] = hexchar[d / 0x10];
c[i * k + 1] = hexchar[d % 0x10];
if (space && i < len - 1) c[i * k + 2] = ' ';
i++;
}
return new string(c, 0, c.Length);
}
private static string GuidToRaw(Guid guid)
{
byte[] bytes = guid.ToByteArray();
int сharCount = bytes.Length * 2;
char[] chars = new char[сharCount];
int index = 0;
for (int i = 0; i < сharCount; i += 2)
{
byte b = bytes[index++];
chars[i] = GetHexValue((int)(b / 16));
chars[i + 1] = GetHexValue((int)(b % 16));
}
return new string(chars, 0, chars.Length);
}
private static char GetHexValue(int i)
{
return (char)(i < 10 ? i + 48 : i + 55);
}
LINQでこれを行う良い方法...
var data = new byte[] { 1, 2, 4, 8, 16, 32 };
var hexString = data.Aggregate(new StringBuilder(),
(sb,v)=>sb.Append(v.ToString("X2"))
).ToString();