आप एक बाइट सरणी को हेक्साडेसिमल स्ट्रिंग में कैसे बदल सकते हैं, और इसके विपरीत?
आप एक बाइट सरणी को हेक्साडेसिमल स्ट्रिंग में कैसे बदल सकते हैं, और इसके विपरीत?
जवाबों:
कोई एक:
public static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString();
}
या:
public static string ByteArrayToString(byte[] ba)
{
return BitConverter.ToString(ba).Replace("-","");
}
उदाहरण के लिए, इसे करने के और भी कई प्रकार हैं ।
रिवर्स रूपांतरण इस तरह होगा:
public static byte[] StringToByteArray(String hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
का उपयोग करना Substring
संयोजन के साथ सबसे अच्छा विकल्प है Convert.ToByte
। अधिक जानकारी के लिए यह उत्तर देखें । यदि आपको बेहतर प्रदर्शन की आवश्यकता है, तो Convert.ToByte
आपको ड्रॉप करने से पहले बचना चाहिए SubString
।
नोट: 2015-08-20 के रूप में नए नेता
मैंने कुछ क्रूड Stopwatch
प्रदर्शन परीक्षण, एक यादृच्छिक वाक्य (n = 61, 1000 पुनरावृत्तियों) के साथ एक रन और प्रोजेक्ट गुटेनबर्ग पाठ (n = 1,238,957, 150 पुनरावृत्तियों) के साथ एक रन के माध्यम से विभिन्न रूपांतरण विधियों में से प्रत्येक को चलाया। यहाँ परिणाम हैं, मोटे तौर पर सबसे तेजी से सबसे धीमी गति से। सभी माप टिक्स में हैं ( 10,000 टिक्स = 1 एमएस ) और सभी रिश्तेदार नोटों की तुलना [सबसे धीमी] StringBuilder
कार्यान्वयन से की जाती है। उपयोग किए गए कोड के लिए, नीचे देखें या परीक्षण ढांचा रेपो जहां मैं अब इसे चलाने के लिए कोड बनाए रखता हूं।
चेतावनी: किसी भी चीज़ के लिए इन आँकड़ों पर भरोसा न करें; वे बस नमूना डेटा का एक नमूना रन हैं। यदि आपको वास्तव में शीर्ष प्रदर्शन की आवश्यकता है, तो कृपया अपने उत्पादन जरूरतों के पर्यावरण प्रतिनिधि में इन विधियों का परीक्षण करें जो आप उपयोग करेंगे के डेटा प्रतिनिधि के साथ।
unsafe
(कोड्स इनचैचोस के माध्यम से) ( एयरब्रीथर द्वारा रेपो का परीक्षण करने के लिए जोड़ा गया )
BitConverter
(तोमलक के माध्यम से)
{SoapHexBinary}.ToString
(मायक्रॉफ्ट के माध्यम से)
{byte}.ToString("X2")
(उपयोग foreach
) (विल डीन के उत्तर से प्राप्त)
{byte}.ToString("X2")
(उपयोग करते हुए {IEnumerable}.Aggregate
, System.Linq की आवश्यकता होती है) (मार्क के माध्यम से)
Array.ConvertAll
(का उपयोग करते हुए string.Join
) (विल डीन के माध्यम से)
Array.ConvertAll
(उपयोग करना string.Concat
, .NET 4.0 की आवश्यकता है) (विल डीन के माध्यम से)
{StringBuilder}.AppendFormat
(का उपयोग कर foreach
) (Tomalak के माध्यम से)
{StringBuilder}.AppendFormat
(का उपयोग करते हुए {IEnumerable}.Aggregate
, System.Linq की आवश्यकता होती है) (तोमलक के उत्तर से प्राप्त)
लुकअप टेबल ने बाइट हेरफेर पर बढ़त बना ली है। मूल रूप से, वहाँ किसी भी दिए गए कुतरना या बाइट हेक्स में होगा precomputing के कुछ रूप है। फिर, जैसा कि आप डेटा के माध्यम से चीरते हैं, आप बस अगले हिस्से को देखते हैं कि हेक्स स्ट्रिंग क्या है। उस मूल्य को फिर कुछ फैशन में परिणामी स्ट्रिंग आउटपुट में जोड़ा जाता है। लंबे समय तक बाइट हेरफेर के लिए, कुछ डेवलपर्स द्वारा पढ़ने के लिए संभवतः कठिन, शीर्ष-प्रदर्शन दृष्टिकोण था।
आपका सबसे अच्छा दांव अभी भी कुछ प्रतिनिधि डेटा खोजने और इसे उत्पादन जैसे वातावरण में आज़माने जा रहा है। यदि आपके पास अलग-अलग मेमोरी बाधाएं हैं, तो आप कम आवंटन वाले एक विधि को पसंद कर सकते हैं जो कि तेज होगी लेकिन अधिक मेमोरी का उपभोग करेगी।
मेरे द्वारा उपयोग किए गए परीक्षण कोड के साथ खेलने के लिए स्वतंत्र महसूस करें। एक संस्करण यहां शामिल है लेकिन रेपो क्लोन करने और अपने स्वयं के तरीकों को जोड़ने के लिए स्वतंत्र महसूस करें । कृपया एक पुल अनुरोध प्रस्तुत करें यदि आप कुछ भी दिलचस्प पाते हैं या परीक्षण ढांचे का उपयोग करने में मदद करना चाहते हैं।
Func<byte[], string>
) /Tests/ConvertByteArrayToHexString/Test.cs में जोड़ें।TestCandidates
उसी वर्ग में वापसी मान में जोड़ें ।GenerateTestInput
।static string ByteArrayToHexStringViaStringJoinArrayConvertAll(byte[] bytes) {
return string.Join(string.Empty, Array.ConvertAll(bytes, b => b.ToString("X2")));
}
static string ByteArrayToHexStringViaStringConcatArrayConvertAll(byte[] bytes) {
return string.Concat(Array.ConvertAll(bytes, b => b.ToString("X2")));
}
static string ByteArrayToHexStringViaBitConverter(byte[] bytes) {
string hex = BitConverter.ToString(bytes);
return hex.Replace("-", "");
}
static string ByteArrayToHexStringViaStringBuilderAggregateByteToString(byte[] bytes) {
return bytes.Aggregate(new StringBuilder(bytes.Length * 2), (sb, b) => sb.Append(b.ToString("X2"))).ToString();
}
static string ByteArrayToHexStringViaStringBuilderForEachByteToString(byte[] bytes) {
StringBuilder hex = new StringBuilder(bytes.Length * 2);
foreach (byte b in bytes)
hex.Append(b.ToString("X2"));
return hex.ToString();
}
static string ByteArrayToHexStringViaStringBuilderAggregateAppendFormat(byte[] bytes) {
return bytes.Aggregate(new StringBuilder(bytes.Length * 2), (sb, b) => sb.AppendFormat("{0:X2}", b)).ToString();
}
static string ByteArrayToHexStringViaStringBuilderForEachAppendFormat(byte[] bytes) {
StringBuilder hex = new StringBuilder(bytes.Length * 2);
foreach (byte b in bytes)
hex.AppendFormat("{0:X2}", b);
return hex.ToString();
}
static string ByteArrayToHexViaByteManipulation(byte[] bytes) {
char[] c = new char[bytes.Length * 2];
byte b;
for (int i = 0; i < bytes.Length; i++) {
b = ((byte)(bytes[i] >> 4));
c[i * 2] = (char)(b > 9 ? b + 0x37 : b + 0x30);
b = ((byte)(bytes[i] & 0xF));
c[i * 2 + 1] = (char)(b > 9 ? b + 0x37 : b + 0x30);
}
return new string(c);
}
static string ByteArrayToHexViaByteManipulation2(byte[] bytes) {
char[] c = new char[bytes.Length * 2];
int b;
for (int i = 0; i < bytes.Length; i++) {
b = bytes[i] >> 4;
c[i * 2] = (char)(55 + b + (((b - 10) >> 31) & -7));
b = bytes[i] & 0xF;
c[i * 2 + 1] = (char)(55 + b + (((b - 10) >> 31) & -7));
}
return new string(c);
}
static string ByteArrayToHexViaSoapHexBinary(byte[] bytes) {
SoapHexBinary soapHexBinary = new SoapHexBinary(bytes);
return soapHexBinary.ToString();
}
static string ByteArrayToHexViaLookupAndShift(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();
}
static readonly uint* _lookup32UnsafeP = (uint*)GCHandle.Alloc(_Lookup32, GCHandleType.Pinned).AddrOfPinnedObject();
static string ByteArrayToHexViaLookup32UnsafeDirect(byte[] bytes) {
var lookupP = _lookup32UnsafeP;
var result = new string((char)0, bytes.Length * 2);
fixed (byte* bytesP = bytes)
fixed (char* resultP = result) {
uint* resultP2 = (uint*)resultP;
for (int i = 0; i < bytes.Length; i++) {
resultP2[i] = lookupP[bytesP[i]];
}
}
return result;
}
static uint[] _Lookup32 = Enumerable.Range(0, 255).Select(i => {
string s = i.ToString("X2");
return ((uint)s[0]) + ((uint)s[1] << 16);
}).ToArray();
static string ByteArrayToHexViaLookupPerByte(byte[] bytes) {
var result = new char[bytes.Length * 2];
for (int i = 0; i < bytes.Length; i++)
{
var val = _Lookup32[bytes[i]];
result[2*i] = (char)val;
result[2*i + 1] = (char) (val >> 16);
}
return new string(result);
}
static string ByteArrayToHexViaLookup(byte[] bytes) {
string[] hexStringTable = new string[] {
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
"E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF",
};
StringBuilder result = new StringBuilder(bytes.Length * 2);
foreach (byte b in bytes) {
result.Append(hexStringTable[b]);
}
return result.ToString();
}
विश्लेषण के लिए Waleed का उत्तर जोड़ा गया। जल्दी।
string.Concat
Array.ConvertAll
पूर्णता के लिए जोड़ा गया संस्करण (.NET 4.0 की आवश्यकता है)। string.Join
संस्करण के साथ सममूल्य पर ।
टेस्ट रेपो में अधिक वेरिएंट शामिल हैं जैसे कि StringBuilder.Append(b.ToString("X2"))
। कोई भी परिणाम किसी को परेशान नहीं करता है। उदाहरण के लिए, foreach
तेजी से है {IEnumerable}.Aggregate
, लेकिन BitConverter
अभी भी जीतता है।
SoapHexBinary
विश्लेषण में माईक्रोफ्ट का उत्तर जोड़ा गया , जिसने तीसरा स्थान हासिल किया।
जोड़े गए कोडइनचैट्स के बाइट हेरफेर का उत्तर, जिसने पहले स्थान पर ले लिया (पाठ के बड़े ब्लॉकों पर एक बड़े मार्जिन द्वारा)।
नाथन मोइनवाज़िरी के लुकअप उत्तर और ब्रायन लैम्बर्ट के ब्लॉग के संस्करण को जोड़ा गया। दोनों तेजी से, लेकिन मैंने परीक्षण मशीन (एएमडी फेनोम 9750) का इस्तेमाल नहीं किया।
जोड़ा गया @ CodesInChaos का नया बाइट-आधारित लुकअप उत्तर। ऐसा प्रतीत होता है कि दोनों वाक्य परीक्षणों और पूर्ण-पाठ परीक्षणों पर बढ़त ले ली है।
इस उत्तर के रेपो में एयरब्रेथ के अनुकूलन और unsafe
संस्करण जोड़े गए । यदि आप असुरक्षित गेम में खेलना चाहते हैं, तो आप शॉर्ट स्ट्रिंग्स और बड़े टेक्स्ट दोनों पर किसी भी पूर्व शीर्ष विजेता पर कुछ बड़ा प्रदर्शन हासिल कर सकते हैं।
bytes.ToHexStringAtLudicrousSpeed()
)।
SoapHexBinary नामक एक वर्ग है जो वास्तव में वही करता है जो आप चाहते हैं।
using System.Runtime.Remoting.Metadata.W3cXsd2001;
public static byte[] GetStringToBytes(string value)
{
SoapHexBinary shb = SoapHexBinary.Parse(value);
return shb.Value;
}
public static string GetBytesToString(byte[] value)
{
SoapHexBinary shb = new SoapHexBinary(value);
return shb.ToString();
}
क्रिप्टो कोड लिखते समय डेटा निर्भर शाखाओं और टेबल लुकअप से बचने के लिए यह सामान्य है कि रनटाइम डेटा पर निर्भर न हो, क्योंकि डेटा निर्भर समय के कारण साइड-चैनल हमले हो सकते हैं।
यह भी बहुत तेज है।
static string ByteToHexBitFiddle(byte[] bytes)
{
char[] c = new char[bytes.Length * 2];
int b;
for (int i = 0; i < bytes.Length; i++) {
b = bytes[i] >> 4;
c[i * 2] = (char)(55 + b + (((b-10)>>31)&-7));
b = bytes[i] & 0xF;
c[i * 2 + 1] = (char)(55 + b + (((b-10)>>31)&-7));
}
return new string(c);
}
Ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn
यहाँ आने वाले अपनी सभी आशाओं को छोड़ दें
एक अजीब सा अजीब बात है:
bytes[i] >> 4
एक बाइट के उच्च निबल को bytes[i] & 0xF
निकालता है, एक बाइट के कम निबल को निकालता हैb - 10
< 0
मूल्यों के लिए b < 10
है, जो हो जाएगा एक दशमलव अंकों >= 0
मूल्यों के लिए b > 10
, जिसमें से एक पत्र बन जाएगा A
करने के लिए F
।i >> 31
हस्ताक्षर किए गए 32 बिट पूर्णांक का उपयोग करके साइन को निकाला जाता है, साइन एक्सटेंशन के लिए धन्यवाद। यह उन सभी लोगों -1
के लिए i < 0
और 0
के लिए i >= 0
।(b-10)>>31
हो जाएगा 0
पत्र के लिए और -1
अंक के लिए।0
, और b
10 से 15. की सीमा में है। हम इसे A
(65) से F
(70) तक मैप करना चाहते हैं , जिसका अर्थ है 55 ( 'A'-10
) जोड़ना ।b
0 से 9 की सीमा तक 0
(48) से लेकर 9
(57) तक के नक्शे को दर्शाता है । इसका मतलब है कि यह -7 ( '0' - 55
) बनना चाहिए । & -7
बाद से (0 & -7) == 0
और का उपयोग कर सकते हैं (-1 & -7) == -7
।कुछ और विचार:
c
, क्योंकि माप से पता चलता है कि इससे गणना करना i
सस्ता है।i < bytes.Length
के रूप में ऊपरी लूप के लिए बाध्य घबराना पर सीमा चेकों को खत्म करने की अनुमति देता है bytes[i]
, इसलिए मुझे लगता है कि संस्करण चुना है।b
एक इंट बनाने से अनावश्यक रूपांतरणों को बाइट करने की अनुमति मिलती है।hex string
करने के लिए byte[] array
?
87 + b + (((b-10)>>31)&-39)
byte[] array
", जिसका शाब्दिक अर्थ है बाइट सरणियों की एक सरणी, या byte[][]
। मैं बस मज़े से चुदवा रही थी।
यदि आप तुलना में अधिक लचीलापन चाहते हैं BitConverter
, लेकिन उन क्लंकी 1990 के दशक की शैली के स्पष्ट छोरों को नहीं चाहते हैं, तो आप कर सकते हैं:
String.Join(String.Empty, Array.ConvertAll(bytes, x => x.ToString("X2")));
या, यदि आप .NET 4.0 का उपयोग कर रहे हैं:
String.Concat(Array.ConvertAll(bytes, x => x.ToString("X2")));
(मूल पोस्ट पर एक टिप्पणी से उत्तरार्द्ध।)
एक और लुकअप टेबल आधारित दृष्टिकोण। यह प्रत्येक बाइट के लिए केवल एक लुकअप तालिका का उपयोग करता है, बजाय प्रति देखने योग्य तालिका के बजाय।
private static readonly uint[] _lookup32 = CreateLookup32();
private static uint[] CreateLookup32()
{
var result = new uint[256];
for (int i = 0; i < 256; i++)
{
string s=i.ToString("X2");
result[i] = ((uint)s[0]) + ((uint)s[1] << 16);
}
return result;
}
private static string ByteArrayToHexViaLookup32(byte[] bytes)
{
var lookup32 = _lookup32;
var result = new char[bytes.Length * 2];
for (int i = 0; i < bytes.Length; i++)
{
var val = lookup32[bytes[i]];
result[2*i] = (char)val;
result[2*i + 1] = (char) (val >> 16);
}
return new string(result);
}
मैं भी उपयोग करते हुए इस के वेरिएंट परीक्षण किया ushort
, struct{char X1, X2}
, struct{byte X1, X2}
लुकअप तालिका में।
संकलन लक्ष्य (x86, X64) के आधार पर, जिनका या तो लगभग एक ही प्रदर्शन था या इस संस्करण की तुलना में थोड़ा धीमा था।
और उच्च प्रदर्शन के लिए, इसके unsafe
भाई:
private static readonly uint[] _lookup32Unsafe = CreateLookup32Unsafe();
private static readonly uint* _lookup32UnsafeP = (uint*)GCHandle.Alloc(_lookup32Unsafe,GCHandleType.Pinned).AddrOfPinnedObject();
private static uint[] CreateLookup32Unsafe()
{
var result = new uint[256];
for (int i = 0; i < 256; i++)
{
string s=i.ToString("X2");
if(BitConverter.IsLittleEndian)
result[i] = ((uint)s[0]) + ((uint)s[1] << 16);
else
result[i] = ((uint)s[1]) + ((uint)s[0] << 16);
}
return result;
}
public static string ByteArrayToHexViaLookup32Unsafe(byte[] bytes)
{
var lookupP = _lookup32UnsafeP;
var result = new char[bytes.Length * 2];
fixed(byte* bytesP = bytes)
fixed (char* resultP = result)
{
uint* resultP2 = (uint*)resultP;
for (int i = 0; i < bytes.Length; i++)
{
resultP2[i] = lookupP[bytesP[i]];
}
}
return new string(result);
}
या यदि आप इसे सीधे स्ट्रिंग में लिखने के लिए स्वीकार्य मानते हैं:
public static string ByteArrayToHexViaLookup32UnsafeDirect(byte[] bytes)
{
var lookupP = _lookup32UnsafeP;
var result = new string((char)0, bytes.Length * 2);
fixed (byte* bytesP = bytes)
fixed (char* resultP = result)
{
uint* resultP2 = (uint*)resultP;
for (int i = 0; i < bytes.Length; i++)
{
resultP2[i] = lookupP[bytesP[i]];
}
}
return result;
}
Span
अब के बजाय इस्तेमाल किया जा सकता है unsafe
??
आप BitConverter.ToString विधि का उपयोग कर सकते हैं:
byte[] bytes = {0, 1, 2, 4, 8, 16, 32, 64, 128, 256}
Console.WriteLine( BitConverter.ToString(bytes));
आउटपुट:
00-01-02-04-08-10-20-40-80-एफएफ
अधिक जानकारी: BitConverter.ToString विधि (बाइट [])
मुझे आज बस एक ही समस्या का सामना करना पड़ा, और मैं इस कोड में आया:
private static string ByteArrayToHex(byte[] barray)
{
char[] c = new char[barray.Length * 2];
byte b;
for (int i = 0; i < barray.Length; ++i)
{
b = ((byte)(barray[i] >> 4));
c[i * 2] = (char)(b > 9 ? b + 0x37 : b + 0x30);
b = ((byte)(barray[i] & 0xF));
c[i * 2 + 1] = (char)(b > 9 ? b + 0x37 : b + 0x30);
}
return new string(c);
}
स्रोत: फोरम पोस्ट बाइट [] हेक्स स्ट्रिंग के लिए ऐरे (PZahra द्वारा पोस्ट देखें)। मैंने 0x उपसर्ग को हटाने के लिए कोड को थोड़ा संशोधित किया।
मैंने कोड के लिए कुछ प्रदर्शन परीक्षण किया था और यह बिटकॉइन्ट्रेटर.टॉस्ट्रिंग () (पैट्रिज की पोस्ट के अनुसार सबसे तेज़) का उपयोग करने की तुलना में लगभग आठ गुना तेज था।
यह टॉमालक के अत्यधिक लोकप्रिय उत्तर (और बाद के संपादन) के संशोधन 4 का उत्तर है ।
मैं यह बताता हूं कि यह संपादन गलत है, और समझाएं कि इसे वापस क्यों लाया जा सकता है। रास्ते के साथ, आप कुछ इंटर्नल के बारे में एक या दो सीख सकते हैं, और अभी तक एक और उदाहरण देख सकते हैं कि समय से पहले अनुकूलन वास्तव में क्या है और यह आपको कैसे काट सकता है।
tl; dr: बस उपयोग करें Convert.ToByte
और String.Substring
यदि आप जल्दी में हैं ("मूल कोड नीचे"), यह सबसे अच्छा संयोजन है यदि आप फिर से लागू नहीं करना चाहते हैं Convert.ToByte
। कुछ का उपयोग करें और अधिक उन्नत (अन्य उत्तर देखें) कि उपयोग नहीं करता है Convert.ToByte
अगर आप की जरूरत है प्रदर्शन। करो नहीं कुछ और अन्य का उपयोग की तुलना में String.Substring
के साथ संयोजन में Convert.ToByte
, जब तक कि कोई कुछ दिलचस्प यह उत्तर की टिप्पणियों में इस बारे में क्या कहना है।
चेतावनी: यदिConvert.ToByte(char[], Int32)
फ्रेम में एक अधिभार लागू किया जाता है तो यह उत्तर अप्रचलित हो सकता है। यह जल्द होने की संभावना नहीं है।
एक सामान्य नियम के रूप में, मुझे यह कहना पसंद नहीं है कि "समय से पहले अनुकूलन न करें", क्योंकि कोई नहीं जानता कि "समय से पहले" कब होता है। अनुकूलन करने या न करने का निर्णय लेते समय आपको केवल एक चीज पर विचार करना चाहिए: "क्या मेरे पास अनुकूलन दृष्टिकोणों की ठीक से जांच करने के लिए समय और संसाधन हैं?"। यदि आप नहीं करते हैं, तो यह बहुत जल्द है, तब तक प्रतीक्षा करें जब तक कि आपकी परियोजना अधिक परिपक्व न हो या जब तक आपको प्रदर्शन की आवश्यकता न हो (यदि कोई वास्तविक आवश्यकता है, तो आप समय बनाएंगे )। इस बीच, सबसे सरल काम करें जो संभवतः इसके बजाय काम कर सकता है।
मूल कोड:
public static byte[] HexadecimalStringToByteArray_Original(string input)
{
var outputLength = input.Length / 2;
var output = new byte[outputLength];
for (var i = 0; i < outputLength; i++)
output[i] = Convert.ToByte(input.Substring(i * 2, 2), 16);
return output;
}
संशोधन 4:
public static byte[] HexadecimalStringToByteArray_Rev4(string input)
{
var outputLength = input.Length / 2;
var output = new byte[outputLength];
using (var sr = new StringReader(input))
{
for (var i = 0; i < outputLength; i++)
output[i] = Convert.ToByte(new string(new char[2] { (char)sr.Read(), (char)sr.Read() }), 16);
}
return output;
}
संशोधन से बचता है String.Substring
और StringReader
इसके बजाय उपयोग करता है । दिए गए कारण है:
संपादित करें: आप किसी एकल पास पार्सर का उपयोग करके लंबे समय के लिए प्रदर्शन में सुधार कर सकते हैं, जैसे:
खैर, के लिए संदर्भ कोड को देखते हुएString.Substring
, यह पहले से ही स्पष्ट रूप से "एकल-पास" है; और यह क्यों नहीं होना चाहिए? यह बाइट-स्तर पर संचालित होता है, सरोगेट जोड़े पर नहीं।
हालांकि यह एक नया स्ट्रिंग आवंटित करता है, लेकिन फिर आपको Convert.ToByte
वैसे भी पास करने के लिए एक आवंटित करने की आवश्यकता होती है। इसके अलावा, संशोधन में प्रदान किया गया समाधान हर पुनरावृत्ति (दो-चार सरणी) पर एक और वस्तु को आवंटित करता है; आप सुरक्षित रूप से उस आवंटन को लूप के बाहर रख सकते हैं और उस से बचने के लिए सरणी का पुन: उपयोग कर सकते हैं।
public static byte[] HexadecimalStringToByteArray(string input)
{
var outputLength = input.Length / 2;
var output = new byte[outputLength];
var numeral = new char[2];
using (var sr = new StringReader(input))
{
for (var i = 0; i < outputLength; i++)
{
numeral[0] = (char)sr.Read();
numeral[1] = (char)sr.Read();
output[i] = Convert.ToByte(new string(numeral), 16);
}
}
return output;
}
प्रत्येक हेक्साडेसिमल numeral
दो अंकों (प्रतीकों) का उपयोग करके एक एकल ओकटेट का प्रतिनिधित्व करता है।
लेकिन फिर, StringReader.Read
दो बार फोन क्यों ? बस इसके दूसरे अधिभार को बुलाओ और इसे दो वर्णों को एक बार में दो वर्णों में पढ़ने के लिए कहें; और कॉल की मात्रा को दो से कम करें।
public static byte[] HexadecimalStringToByteArray(string input)
{
var outputLength = input.Length / 2;
var output = new byte[outputLength];
var numeral = new char[2];
using (var sr = new StringReader(input))
{
for (var i = 0; i < outputLength; i++)
{
var read = sr.Read(numeral, 0, 2);
Debug.Assert(read == 2);
output[i] = Convert.ToByte(new string(numeral), 16);
}
}
return output;
}
आपके पास जो कुछ बचा है, वह एक स्ट्रिंग रीडर है जिसका केवल जोड़ा गया "मान" एक समानांतर इंडेक्स (आंतरिक _pos
) है जिसे आप स्वयं घोषित कर सकते हैं ( j
उदाहरण के लिए), एक निरर्थक लंबाई चर (आंतरिक _length
), और इनपुट के लिए एक निरर्थक संदर्भ। स्ट्रिंग (आंतरिक _s
)। दूसरे शब्दों में, यह बेकार है।
यदि आप आश्चर्य करते हैं कि Read
" कैसे पढ़ता है", तो बस कोड को देखें , यह सब String.CopyTo
कुछ इनपुट स्ट्रिंग पर कॉल करता है । बाकी उन मूल्यों को बनाए रखने के लिए सिर्फ पुस्तक-उपरि उपरिगामी है जिनकी हमें आवश्यकता नहीं है।
तो, पहले से ही स्ट्रिंग रीडर को हटा दें, और CopyTo
खुद को कॉल करें; यह सरल, स्पष्ट और अधिक कुशल है।
public static byte[] HexadecimalStringToByteArray(string input)
{
var outputLength = input.Length / 2;
var output = new byte[outputLength];
var numeral = new char[2];
for (int i = 0, j = 0; i < outputLength; i++, j += 2)
{
input.CopyTo(j, numeral, 0, 2);
output[i] = Convert.ToByte(new string(numeral), 16);
}
return output;
}
क्या आपको वास्तव में एक j
सूचकांक की आवश्यकता है जो दो समानांतर के चरणों में वृद्धि करता है i
? बेशक, बस i
दो से गुणा करें (जो कंपाइलर को एक अतिरिक्त अनुकूलन करने में सक्षम होना चाहिए)।
public static byte[] HexadecimalStringToByteArray_BestEffort(string input)
{
var outputLength = input.Length / 2;
var output = new byte[outputLength];
var numeral = new char[2];
for (int i = 0; i < outputLength; i++)
{
input.CopyTo(i * 2, numeral, 0, 2);
output[i] = Convert.ToByte(new string(numeral), 16);
}
return output;
}
समाधान अब कैसा दिखता है? बिल्कुल वैसे ही जैसे यह शुरुआत में था, केवल String.Substring
स्ट्रिंग को आवंटित करने और उस पर डेटा कॉपी करने के लिए उपयोग करने के बजाय , आप एक मध्यस्थ सरणी का उपयोग कर रहे हैं, जिसके लिए आप हेक्साडेसिमल अंकों की प्रतिलिपि बनाते हैं, फिर स्ट्रिंग को स्वयं आवंटित करें और डेटा को फिर से कॉपी करें सरणी और स्ट्रिंग में (जब आप इसे स्ट्रिंग कंस्ट्रक्टर में पास करते हैं)। दूसरी प्रतिलिपि को अनुकूलित किया जा सकता है यदि स्ट्रिंग पहले से ही आंतरिक पूल में है, लेकिन फिर String.Substring
इन मामलों में भी इससे बचने में सक्षम होगी।
वास्तव में, यदि आप String.Substring
फिर से देखते हैं, तो आप देखते हैं कि यह कुछ निम्न-स्तर के आंतरिक ज्ञान का उपयोग करता है कि स्ट्रिंग को आवंटित करने के लिए स्ट्रिंग्स का निर्माण कैसे किया जाता है जितना कि आप सामान्य रूप से कर सकते हैं, और यह उसी कोड को इनलाइन करता है CopyTo
जिससे बचने के लिए सीधे उपयोग किया जाता है। कॉल ओवरहेड।
String.Substring
मैनुअल विधि
निष्कर्ष? यदि आप उपयोग करना चाहते हैंConvert.ToByte(String, Int32)
(क्योंकि आप स्वयं उस कार्यक्षमता को फिर से लागू नहीं करना चाहते हैं), वहाँ एक तरीका नहीं है हरा करने का String.Substring
; आप जो कुछ भी करते हैं वह हलकों में चलाया जाता है, पहिया को फिर से आविष्कार करना (केवल उप-इष्टतम सामग्री के साथ)।
ध्यान दें कि का उपयोग करते हुए Convert.ToByte
और String.Substring
एक पूरी तरह से वैध विकल्प है यदि आप चरम प्रदर्शन की आवश्यकता नहीं है। याद रखें: केवल एक विकल्प का चयन करें यदि आपके पास यह जांचने के लिए समय और संसाधन हैं कि यह कैसे ठीक से काम करता है।
यदि वहाँ था Convert.ToByte(char[], Int32)
, तो चीजें बिल्कुल अलग होंगी (ऐसा करना संभव होगा जो मैंने ऊपर वर्णित किया है और पूरी तरह से बचें String
)।
मुझे संदेह है कि "टालने" से बेहतर प्रदर्शन की रिपोर्ट करने वाले लोग String.Substring
भी बचते हैं Convert.ToByte(String, Int32)
, जो आपको वैसे भी प्रदर्शन की आवश्यकता होने पर वास्तव में करना चाहिए। ऐसा करने के लिए सभी विभिन्न दृष्टिकोणों की खोज करने के लिए अनगिनत अन्य उत्तरों को देखें।
अस्वीकरण: मैंने यह पुष्टि करने के लिए फ्रेमवर्क के नवीनतम संस्करण को विघटित नहीं किया है कि संदर्भ स्रोत अद्यतित है, मुझे लगता है कि यह है।
अब, यह सब अच्छा और तार्किक लगता है, उम्मीद है कि स्पष्ट रूप से अगर आप अभी तक प्राप्त करने में कामयाब रहे हैं। लेकिन क्या यह सच है?
Intel(R) Core(TM) i7-3720QM CPU @ 2.60GHz
Cores: 8
Current Clock Speed: 2600
Max Clock Speed: 2600
--------------------
Parsing hexadecimal string into an array of bytes
--------------------
HexadecimalStringToByteArray_Original: 7,777.09 average ticks (over 10000 runs), 1.2X
HexadecimalStringToByteArray_BestEffort: 8,550.82 average ticks (over 10000 runs), 1.1X
HexadecimalStringToByteArray_Rev4: 9,218.03 average ticks (over 10000 runs), 1.0X
हाँ!
बेंच फ्रेमवर्क के लिए पार्ट्रिप्स पर जाता है, इसे हैक करना आसान है। उपयोग किया गया इनपुट एक 100,000 बाइट्स लंबी स्ट्रिंग बनाने के लिए निम्नलिखित SHA-1 हैश को 5000 बार दोहराया गया है।
209113288F93A9AB8E474EA78D899AFDBB874355
मज़े करो! (लेकिन मॉडरेशन के साथ अनुकूलन करें।)
@CodesInChaos (उलट विधि) द्वारा जवाब देने के लिए पूरक
public static byte[] HexToByteUsingByteManipulation(string s)
{
byte[] bytes = new byte[s.Length / 2];
for (int i = 0; i < bytes.Length; i++)
{
int hi = s[i*2] - 65;
hi = hi + 10 + ((hi >> 31) & 7);
int lo = s[i*2 + 1] - 65;
lo = lo + 10 + ((lo >> 31) & 7) & 0x0f;
bytes[i] = (byte) (lo | hi << 4);
}
return bytes;
}
स्पष्टीकरण:
& 0x0f
निचले मामलों के पत्रों का भी समर्थन करना है
hi = hi + 10 + ((hi >> 31) & 7);
के समान है:
hi = ch-65 + 10 + (((ch-65) >> 31) & 7);
'0' .. '9' के लिए यह वही है hi = ch - 65 + 10 + 7;
जो ऐसा है hi = ch - 48
(इस कारण है 0xffffffff & 7
)।
'ए' के लिए .. 'एफ' यह है hi = ch - 65 + 10;
(यह इस वजह से है 0x00000000 & 7
)।
'A' .. 'f' के लिए हमें बड़ी संख्याएँ हैं इसलिए हमें 32 बिट्स 0
का उपयोग करके डिफ़ॉल्ट संस्करण से घटाना होगा & 0x0f
।
65 के लिए कोड है 'A'
48 के लिए कोड है '0'
7 ASCII तालिका ( ) के बीच '9'
और अक्षरों की संख्या है ।'A'
...456789:;<=>?@ABCD...
लुक-अप तालिका का उपयोग करके भी इस समस्या को हल किया जा सकता है। इसके लिए एनकोडर और डिकोडर दोनों के लिए थोड़ी मात्रा में स्थिर मेमोरी की आवश्यकता होगी। यह विधि हालांकि तेज होगी:
मेरा समाधान एन्कोडिंग टेबल के लिए 1024 बाइट्स और डिकोडिंग के लिए 256 बाइट्स का उपयोग करता है।
private static readonly byte[] LookupTable = new byte[] {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
private static byte Lookup(char c)
{
var b = LookupTable[c];
if (b == 255)
throw new IOException("Expected a hex character, got " + c);
return b;
}
public static byte ToByte(char[] chars, int offset)
{
return (byte)(Lookup(chars[offset]) << 4 | Lookup(chars[offset + 1]));
}
private static readonly char[][] LookupTableUpper;
private static readonly char[][] LookupTableLower;
static Hex()
{
LookupTableLower = new char[256][];
LookupTableUpper = new char[256][];
for (var i = 0; i < 256; i++)
{
LookupTableLower[i] = i.ToString("x2").ToCharArray();
LookupTableUpper[i] = i.ToString("X2").ToCharArray();
}
}
public static char[] ToCharLower(byte[] b, int bOffset)
{
return LookupTableLower[b[bOffset]];
}
public static char[] ToCharUpper(byte[] b, int bOffset)
{
return LookupTableUpper[b[bOffset]];
}
StringBuilderToStringFromBytes: 106148
BitConverterToStringFromBytes: 15783
ArrayConvertAllToStringFromBytes: 54290
ByteManipulationToCharArray: 8444
TableBasedToCharArray: 5651 *
* यह समाधान
डिकोडिंग के दौरान IOException और IndexOutOfRangeException हो सकती है (यदि किसी वर्ण का मान बहुत अधिक है> 256)। डी / एन्कोडिंग धाराओं या सरणियों के लिए तरीकों को लागू किया जाना चाहिए, यह सिर्फ अवधारणा का प्रमाण है।
यह एक महान पोस्ट है। मुझे वलीद का हल पसंद है। मैंने इसे पेट्रिज टेस्ट के माध्यम से नहीं चलाया है, लेकिन यह काफी तेज है। मुझे रिवर्स प्रक्रिया की भी आवश्यकता थी, एक हेक्स स्ट्रिंग को बाइट सरणी में परिवर्तित करना, इसलिए मैंने इसे वेलेड के समाधान के उलट के रूप में लिखा। सुनिश्चित नहीं है कि यह टॉमालक के मूल समाधान की तुलना में कोई तेज़ है। फिर, मैंने पितृसत्ता के परीक्षण के माध्यम से रिवर्स प्रक्रिया को नहीं चलाया।
private byte[] HexStringToByteArray(string hexString)
{
int hexStringLength = hexString.Length;
byte[] b = new byte[hexStringLength / 2];
for (int i = 0; i < hexStringLength; i += 2)
{
int topChar = (hexString[i] > 0x40 ? hexString[i] - 0x37 : hexString[i] - 0x30) << 4;
int bottomChar = hexString[i + 1] > 0x40 ? hexString[i + 1] - 0x37 : hexString[i + 1] - 0x30;
b[i / 2] = Convert.ToByte(topChar + bottomChar);
}
return b;
}
hexString[i] &= ~0x20;
इसे जटिल क्यों बनाते हैं? यह दृश्य स्टूडियो 2008 में सरल है:
सी#:
string hex = BitConverter.ToString(YourByteArray).Replace("-", "");
वीबी:
Dim hex As String = BitConverter.ToString(YourByteArray).Replace("-", "")
यहाँ कई उत्तरों पर ढेर करने के लिए नहीं, लेकिन मुझे एक काफी इष्टतम मिला (~ 4.5x बेहतर स्वीकार किए जाते हैं), सीधे हेक्स स्ट्रिंग पार्सर का कार्यान्वयन। पहले, मेरे परीक्षणों से उत्पादन (पहला बैच मेरा कार्यान्वयन है):
Give me that string:
04c63f7842740c77e545bb0b2ade90b384f119f6ab57b680b7aa575a2f40939f
Time to parse 100,000 times: 50.4192 ms
Result as base64: BMY/eEJ0DHflRbsLKt6Qs4TxGfarV7aAt6pXWi9Ak58=
BitConverter'd: 04-C6-3F-78-42-74-0C-77-E5-45-BB-0B-2A-DE-90-B3-84-F1-19-F6-AB-5
7-B6-80-B7-AA-57-5A-2F-40-93-9F
Accepted answer: (StringToByteArray)
Time to parse 100000 times: 233.1264ms
Result as base64: BMY/eEJ0DHflRbsLKt6Qs4TxGfarV7aAt6pXWi9Ak58=
BitConverter'd: 04-C6-3F-78-42-74-0C-77-E5-45-BB-0B-2A-DE-90-B3-84-F1-19-F6-AB-5
7-B6-80-B7-AA-57-5A-2F-40-93-9F
With Mono's implementation:
Time to parse 100000 times: 777.2544ms
Result as base64: BMY/eEJ0DHflRbsLKt6Qs4TxGfarV7aAt6pXWi9Ak58=
BitConverter'd: 04-C6-3F-78-42-74-0C-77-E5-45-BB-0B-2A-DE-90-B3-84-F1-19-F6-AB-5
7-B6-80-B7-AA-57-5A-2F-40-93-9F
With SoapHexBinary:
Time to parse 100000 times: 845.1456ms
Result as base64: BMY/eEJ0DHflRbsLKt6Qs4TxGfarV7aAt6pXWi9Ak58=
BitConverter'd: 04-C6-3F-78-42-74-0C-77-E5-45-BB-0B-2A-DE-90-B3-84-F1-19-F6-AB-5
7-B6-80-B7-AA-57-5A-2F-40-93-9F
Base64 और 'BitConverter'd' लाइनें शुद्धता के लिए परीक्षण करने के लिए हैं। ध्यान दें कि वे समान हैं।
कार्यान्वयन:
public static byte[] ToByteArrayFromHex(string hexString)
{
if (hexString.Length % 2 != 0) throw new ArgumentException("String must have an even length");
var array = new byte[hexString.Length / 2];
for (int i = 0; i < hexString.Length; i += 2)
{
array[i/2] = ByteFromTwoChars(hexString[i], hexString[i + 1]);
}
return array;
}
private static byte ByteFromTwoChars(char p, char p_2)
{
byte ret;
if (p <= '9' && p >= '0')
{
ret = (byte) ((p - '0') << 4);
}
else if (p <= 'f' && p >= 'a')
{
ret = (byte) ((p - 'a' + 10) << 4);
}
else if (p <= 'F' && p >= 'A')
{
ret = (byte) ((p - 'A' + 10) << 4);
} else throw new ArgumentException("Char is not a hex digit: " + p,"p");
if (p_2 <= '9' && p_2 >= '0')
{
ret |= (byte) ((p_2 - '0'));
}
else if (p_2 <= 'f' && p_2 >= 'a')
{
ret |= (byte) ((p_2 - 'a' + 10));
}
else if (p_2 <= 'F' && p_2 >= 'A')
{
ret |= (byte) ((p_2 - 'A' + 10));
} else throw new ArgumentException("Char is not a hex digit: " + p_2, "p_2");
return ret;
}
मैंने unsafe
(स्पष्ट रूप से निरर्थक) चरित्र-से-नीच if
अनुक्रम को दूसरी विधि से स्थानांतरित करने के लिए कुछ सामान की कोशिश की , लेकिन यह सबसे तेज़ था।
(मैंने माना कि यह आधे सवाल का जवाब देता है। मुझे लगा कि स्ट्रिंग-> बाइट [] रूपांतरण को कम करके आंका गया था, जबकि बाइट [] -> स्ट्रिंग कोण अच्छी तरह से ढंका हुआ लगता है। इस प्रकार, यह उत्तर।)
सुरक्षित संस्करण:
public static class HexHelper
{
[System.Diagnostics.Contracts.Pure]
public static string ToHex(this byte[] value)
{
if (value == null)
throw new ArgumentNullException("value");
const string hexAlphabet = @"0123456789ABCDEF";
var chars = new char[checked(value.Length * 2)];
unchecked
{
for (int i = 0; i < value.Length; i++)
{
chars[i * 2] = hexAlphabet[value[i] >> 4];
chars[i * 2 + 1] = hexAlphabet[value[i] & 0xF];
}
}
return new string(chars);
}
[System.Diagnostics.Contracts.Pure]
public static byte[] FromHex(this string value)
{
if (value == null)
throw new ArgumentNullException("value");
if (value.Length % 2 != 0)
throw new ArgumentException("Hexadecimal value length must be even.", "value");
unchecked
{
byte[] result = new byte[value.Length / 2];
for (int i = 0; i < result.Length; i++)
{
// 0(48) - 9(57) -> 0 - 9
// A(65) - F(70) -> 10 - 15
int b = value[i * 2]; // High 4 bits.
int val = ((b - '0') + ((('9' - b) >> 31) & -7)) << 4;
b = value[i * 2 + 1]; // Low 4 bits.
val += (b - '0') + ((('9' - b) >> 31) & -7);
result[i] = checked((byte)val);
}
return result;
}
}
}
असुरक्षित संस्करण उन लोगों के लिए जो प्रदर्शन पसंद करते हैं और अनिश्चितता से डरते नहीं हैं। लगभग 35% तेज़ ToHex और 10% तेज़ी से FromHex।
public static class HexUnsafeHelper
{
[System.Diagnostics.Contracts.Pure]
public static unsafe string ToHex(this byte[] value)
{
if (value == null)
throw new ArgumentNullException("value");
const string alphabet = @"0123456789ABCDEF";
string result = new string(' ', checked(value.Length * 2));
fixed (char* alphabetPtr = alphabet)
fixed (char* resultPtr = result)
{
char* ptr = resultPtr;
unchecked
{
for (int i = 0; i < value.Length; i++)
{
*ptr++ = *(alphabetPtr + (value[i] >> 4));
*ptr++ = *(alphabetPtr + (value[i] & 0xF));
}
}
}
return result;
}
[System.Diagnostics.Contracts.Pure]
public static unsafe byte[] FromHex(this string value)
{
if (value == null)
throw new ArgumentNullException("value");
if (value.Length % 2 != 0)
throw new ArgumentException("Hexadecimal value length must be even.", "value");
unchecked
{
byte[] result = new byte[value.Length / 2];
fixed (char* valuePtr = value)
{
char* valPtr = valuePtr;
for (int i = 0; i < result.Length; i++)
{
// 0(48) - 9(57) -> 0 - 9
// A(65) - F(70) -> 10 - 15
int b = *valPtr++; // High 4 bits.
int val = ((b - '0') + ((('9' - b) >> 31) & -7)) << 4;
b = *valPtr++; // Low 4 bits.
val += (b - '0') + ((('9' - b) >> 31) & -7);
result[i] = checked((byte)val);
}
}
return result;
}
}
}
BTW बेंचमार्क परीक्षण के लिए वर्णमाला को हर बार बदलने के लिए कहा जाता है कि फ़ंक्शन गलत है, वर्णमाला तार (या स्ट्रिंग के लिए) स्थैतिक (चार [] के लिए) होनी चाहिए। फिर बाइट [] को वर्णमाला-आधारित रूपांतरण बाइट हेरफेर संस्करणों के रूप में तेजी से हो जाता है।
और निश्चित रूप से परीक्षण को रिलीज़ (अनुकूलन के साथ) और डिबग विकल्प "सप्रेस जेआईटी ऑप्टिमाइज़ेशन" के साथ बंद किया जाना चाहिए (यदि कोड डीबग करना होगा तो "केवल मेरे कोड सक्षम करें" के लिए)।
Waleed Eissa कोड (हेक्स स्ट्रिंग टू बाइट ऐरे) के लिए उलटा कार्य:
public static byte[] HexToBytes(this string hexString)
{
byte[] b = new byte[hexString.Length / 2];
char c;
for (int i = 0; i < hexString.Length / 2; i++)
{
c = hexString[i * 2];
b[i] = (byte)((c < 0x40 ? c - 0x30 : (c < 0x47 ? c - 0x37 : c - 0x57)) << 4);
c = hexString[i * 2 + 1];
b[i] += (byte)(c < 0x40 ? c - 0x30 : (c < 0x47 ? c - 0x37 : c - 0x57));
}
return b;
}
निचले मामले के समर्थन के साथ Waleed Eissa फ़ंक्शन:
public static string BytesToHex(this byte[] barray, bool toLowerCase = true)
{
byte addByte = 0x37;
if (toLowerCase) addByte = 0x57;
char[] c = new char[barray.Length * 2];
byte b;
for (int i = 0; i < barray.Length; ++i)
{
b = ((byte)(barray[i] >> 4));
c[i * 2] = (char)(b > 9 ? b + addByte : b + 0x30);
b = ((byte)(barray[i] & 0xF));
c[i * 2 + 1] = (char)(b > 9 ? b + addByte : b + 0x30);
}
return new string(c);
}
विस्तार के तरीके (अस्वीकरण: पूरी तरह से बिना कोड वाला कोड, BTW ...):
public static class ByteExtensions
{
public static string ToHexString(this byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
{
hex.AppendFormat("{0:x2}", b);
}
return hex.ToString();
}
}
आदि .. टॉमालक के तीन समाधानों में से किसी एक का उपयोग करें (पिछले एक स्ट्रिंग पर एक विस्तार विधि होने के साथ)।
Microsoft के डेवलपर्स से, एक अच्छा, सरल रूपांतरण:
public static string ByteArrayToString(byte[] ba)
{
// Concatenate the bytes into one long string
return ba.Aggregate(new StringBuilder(32),
(sb, b) => sb.Append(b.ToString("X2"))
).ToString();
}
जबकि ऊपर साफ और कॉम्पैक्ट है, प्रदर्शन नशेड़ियों enumerators का उपयोग करके इसके बारे में चिल्लाएंगे। आप टॉमालक के मूल उत्तर के एक बेहतर संस्करण के साथ शिखर प्रदर्शन प्राप्त कर सकते हैं :
public static string ByteArrayToString(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
for(int i=0; i < ba.Length; i++) // <-- Use for loop is faster than foreach
hex.Append(ba[i].ToString("X2")); // <-- ToString is faster than AppendFormat
return hex.ToString();
}
यह उन सभी रूटीनों में से सबसे तेज़ है जो मैंने अब तक यहाँ पोस्ट किए हैं। बस इसके लिए मेरा शब्द न लें ... प्रदर्शन प्रत्येक दिनचर्या का परीक्षण करता है और अपने लिए अपने CIL कोड का निरीक्षण करता है।
b.ToSting("X2")
।
और SQL स्ट्रिंग में डालने के लिए (यदि आप कमांड मापदंडों का उपयोग नहीं कर रहे हैं):
public static String ByteArrayToSQLHexString(byte[] Source)
{
return = "0x" + BitConverter.ToString(Source).Replace("-", "");
}
Source == null
या Source.Length == 0
हमें कोई समस्या है सर!
गति के मामले में, यह यहां की किसी भी चीज़ से बेहतर है:
public static string ToHexString(byte[] data) {
byte b;
int i, j, k;
int l = data.Length;
char[] r = new char[l * 2];
for (i = 0, j = 0; i < l; ++i) {
b = data[i];
k = b >> 4;
r[j++] = (char)(k > 9 ? k + 0x37 : k + 0x30);
k = b & 15;
r[j++] = (char)(k > 9 ? k + 0x37 : k + 0x30);
}
return new string(r);
}
मुझे वह कोड नहीं मिला, जिसमें आपने काम करने का सुझाव दिया था, ओलिप्रो। hex[i] + hex[i+1]
जाहिरा तौर पर लौट आए int
।
हालाँकि, मुझे कुछ सफलता मिली है, जो वॉलेड्स कोड से कुछ संकेत ले रही है और इसे एक साथ अंकित कर रही है। यह बदसूरत नरक के रूप में है, लेकिन यह मेरे परीक्षणों के अनुसार दूसरों की तुलना में 1/3 समय पर काम करता है और प्रदर्शन करता है (पैट्रियड्स परीक्षण तंत्र का उपयोग करके)। इनपुट आकार पर निर्भर करता है। चारों ओर स्विचिंग ?: 0-9 को अलग करने के लिए सबसे पहले शायद थोड़ा तेज परिणाम होगा क्योंकि पत्रों की तुलना में अधिक संख्याएं हैं।
public static byte[] StringToByteArray2(string hex)
{
byte[] bytes = new byte[hex.Length/2];
int bl = bytes.Length;
for (int i = 0; i < bl; ++i)
{
bytes[i] = (byte)((hex[2 * i] > 'F' ? hex[2 * i] - 0x57 : hex[2 * i] > '9' ? hex[2 * i] - 0x37 : hex[2 * i] - 0x30) << 4);
bytes[i] |= (byte)(hex[2 * i + 1] > 'F' ? hex[2 * i + 1] - 0x57 : hex[2 * i + 1] > '9' ? hex[2 * i + 1] - 0x37 : hex[2 * i + 1] - 0x30);
}
return bytes;
}
ByteArrayToHexViaByteManipulation का यह संस्करण और तेज़ हो सकता है।
मेरी रिपोर्ट से:
...
static private readonly char[] hexAlphabet = new char[]
{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
static string ByteArrayToHexViaByteManipulation3(byte[] bytes)
{
char[] c = new char[bytes.Length * 2];
byte b;
for (int i = 0; i < bytes.Length; i++)
{
b = ((byte)(bytes[i] >> 4));
c[i * 2] = hexAlphabet[b];
b = ((byte)(bytes[i] & 0xF));
c[i * 2 + 1] = hexAlphabet[b];
}
return new string(c);
}
और मुझे लगता है कि यह एक अनुकूलन है:
static private readonly char[] hexAlphabet = new char[]
{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
static string ByteArrayToHexViaByteManipulation4(byte[] bytes)
{
char[] c = new char[bytes.Length * 2];
for (int i = 0, ptr = 0; i < bytes.Length; i++, ptr += 2)
{
byte b = bytes[i];
c[ptr] = hexAlphabet[b >> 4];
c[ptr + 1] = hexAlphabet[b & 0xF];
}
return new string(c);
}
मैं इस बिट फ़िडलिंग प्रतियोगिता में प्रवेश करूँगा क्योंकि मेरे पास एक जवाब है जो हेक्साडेसिमल को डीकोड करने के लिए बिट-फ़िडलिंग का उपयोग करता है । ध्यान दें कि वर्ण सरणियों का उपयोग करना और भी तेज़ हो सकता है क्योंकि कॉलिंग StringBuilder
विधियों में समय लगेगा।
public static String ToHex (byte[] data)
{
int dataLength = data.Length;
// pre-create the stringbuilder using the length of the data * 2, precisely enough
StringBuilder sb = new StringBuilder (dataLength * 2);
for (int i = 0; i < dataLength; i++) {
int b = data [i];
// check using calculation over bits to see if first tuple is a letter
// isLetter is zero if it is a digit, 1 if it is a letter
int isLetter = (b >> 7) & ((b >> 6) | (b >> 5)) & 1;
// calculate the code using a multiplication to make up the difference between
// a digit character and an alphanumerical character
int code = '0' + ((b >> 4) & 0xF) + isLetter * ('A' - '9' - 1);
// now append the result, after casting the code point to a character
sb.Append ((Char)code);
// do the same with the lower (less significant) tuple
isLetter = (b >> 3) & ((b >> 2) | (b >> 1)) & 1;
code = '0' + (b & 0xF) + isLetter * ('A' - '9' - 1);
sb.Append ((Char)code);
}
return sb.ToString ();
}
public static byte[] FromHex (String hex)
{
// pre-create the array
int resultLength = hex.Length / 2;
byte[] result = new byte[resultLength];
// set validity = 0 (0 = valid, anything else is not valid)
int validity = 0;
int c, isLetter, value, validDigitStruct, validDigit, validLetterStruct, validLetter;
for (int i = 0, hexOffset = 0; i < resultLength; i++, hexOffset += 2) {
c = hex [hexOffset];
// check using calculation over bits to see if first char is a letter
// isLetter is zero if it is a digit, 1 if it is a letter (upper & lowercase)
isLetter = (c >> 6) & 1;
// calculate the tuple value using a multiplication to make up the difference between
// a digit character and an alphanumerical character
// minus 1 for the fact that the letters are not zero based
value = ((c & 0xF) + isLetter * (-1 + 10)) << 4;
// check validity of all the other bits
validity |= c >> 7; // changed to >>, maybe not OK, use UInt?
validDigitStruct = (c & 0x30) ^ 0x30;
validDigit = ((c & 0x8) >> 3) * (c & 0x6);
validity |= (isLetter ^ 1) * (validDigitStruct | validDigit);
validLetterStruct = c & 0x18;
validLetter = (((c - 1) & 0x4) >> 2) * ((c - 1) & 0x2);
validity |= isLetter * (validLetterStruct | validLetter);
// do the same with the lower (less significant) tuple
c = hex [hexOffset + 1];
isLetter = (c >> 6) & 1;
value ^= (c & 0xF) + isLetter * (-1 + 10);
result [i] = (byte)value;
// check validity of all the other bits
validity |= c >> 7; // changed to >>, maybe not OK, use UInt?
validDigitStruct = (c & 0x30) ^ 0x30;
validDigit = ((c & 0x8) >> 3) * (c & 0x6);
validity |= (isLetter ^ 1) * (validDigitStruct | validDigit);
validLetterStruct = c & 0x18;
validLetter = (((c - 1) & 0x4) >> 2) * ((c - 1) & 0x2);
validity |= isLetter * (validLetterStruct | validLetter);
}
if (validity != 0) {
throw new ArgumentException ("Hexadecimal encoding incorrect for input " + hex);
}
return result;
}
जावा कोड से परिवर्तित।
Char[]
और Char
आंतरिक रूप से
प्रदर्शन के लिए मैं ड्रॉफोरेंस समाधान के साथ जाऊंगा। डिकोडर के लिए एक छोटा अनुकूलन "<< 4" से छुटकारा पाने के लिए या तो चार के लिए एक तालिका का उपयोग किया जा सकता है।
स्पष्ट रूप से दो विधि कॉल महंगे हैं। यदि किसी प्रकार का चेक इनपुट या आउटपुट डेटा (सीआरसी, चेकसम या जो भी हो) पर किया जाता हैif (b == 255)...
हो सकता है उसे छोड़ दिया जा सकता है और इस तरह विधि पूरी तरह से कॉल हो जाती है।
का उपयोग करते हुए offset++
और offset
के बजाय offset
और offset + 1
कुछ सैद्धांतिक लाभ दे सकता है, लेकिन मैं मुझे से बेहतर संकलक हैंडल संदेह है।
private static readonly byte[] LookupTableLow = new byte[] {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
private static readonly byte[] LookupTableHigh = new byte[] {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
private static byte LookupLow(char c)
{
var b = LookupTableLow[c];
if (b == 255)
throw new IOException("Expected a hex character, got " + c);
return b;
}
private static byte LookupHigh(char c)
{
var b = LookupTableHigh[c];
if (b == 255)
throw new IOException("Expected a hex character, got " + c);
return b;
}
public static byte ToByte(char[] chars, int offset)
{
return (byte)(LookupHigh(chars[offset++]) | LookupLow(chars[offset]));
}
यह मेरे सिर के ठीक ऊपर है और इसका परीक्षण या बेंचमार्क नहीं किया गया है।
विविधता के लिए एक और बदलाव:
public static byte[] FromHexString(string src)
{
if (String.IsNullOrEmpty(src))
return null;
int index = src.Length;
int sz = index / 2;
if (sz <= 0)
return null;
byte[] rc = new byte[sz];
while (--sz >= 0)
{
char lo = src[--index];
char hi = src[--index];
rc[sz] = (byte)(
(
(hi >= '0' && hi <= '9') ? hi - '0' :
(hi >= 'a' && hi <= 'f') ? hi - 'a' + 10 :
(hi >= 'A' && hi <= 'F') ? hi - 'A' + 10 :
0
)
<< 4 |
(
(lo >= '0' && lo <= '9') ? lo - '0' :
(lo >= 'a' && lo <= 'f') ? lo - 'a' + 10 :
(lo >= 'A' && lo <= 'F') ? lo - 'A' + 10 :
0
)
);
}
return rc;
}
गति के लिए अनुकूलित नहीं है, लेकिन अधिकांश उत्तर (.NET 4.0) की तुलना में अधिक LINQy:
<Extension()>
Public Function FromHexToByteArray(hex As String) As Byte()
hex = If(hex, String.Empty)
If hex.Length Mod 2 = 1 Then hex = "0" & hex
Return Enumerable.Range(0, hex.Length \ 2).Select(Function(i) Convert.ToByte(hex.Substring(i * 2, 2), 16)).ToArray
End Function
<Extension()>
Public Function ToHexString(bytes As IEnumerable(Of Byte)) As String
Return String.Concat(bytes.Select(Function(b) b.ToString("X2")))
End Function
दो मैशअप जो एक में दो निबल संचालन को मोड़ते हैं।
शायद बहुत कुशल संस्करण:
public static string ByteArrayToString2(byte[] ba)
{
char[] c = new char[ba.Length * 2];
for( int i = 0; i < ba.Length * 2; ++i)
{
byte b = (byte)((ba[i>>1] >> 4*((i&1)^1)) & 0xF);
c[i] = (char)(55 + b + (((b-10)>>31)&-7));
}
return new string( c );
}
Decadent linq-bit-hacking version:
public static string ByteArrayToString(byte[] ba)
{
return string.Concat( ba.SelectMany( b => new int[] { b >> 4, b & 0xF }).Select( b => (char)(55 + b + (((b-10)>>31)&-7))) );
}
और रिवर्स:
public static byte[] HexStringToByteArray( string s )
{
byte[] ab = new byte[s.Length>>1];
for( int i = 0; i < s.Length; i++ )
{
int b = s[i];
b = (b - '0') + ((('9' - b)>>31)&-7);
ab[i>>1] |= (byte)(b << 4*((i&1)^1));
}
return ab;
}
stackalloc
जीसी मेमोरी प्रेशर को कम करने के लिए एक और तरीका है :
static string ByteToHexBitFiddle(byte[] bytes)
{
var c = stackalloc char[bytes.Length * 2 + 1];
int b;
for (int i = 0; i < bytes.Length; ++i)
{
b = bytes[i] >> 4;
c[i * 2] = (char)(55 + b + (((b - 10) >> 31) & -7));
b = bytes[i] & 0xF;
c[i * 2 + 1] = (char)(55 + b + (((b - 10) >> 31) & -7));
}
c[bytes.Length * 2 ] = '\0';
return new string(c);
}
यहाँ पर मेरा शॉट है। मैंने स्ट्रिंग और बाइट का विस्तार करने के लिए विस्तार वर्गों की एक जोड़ी बनाई है। बड़े फ़ाइल परीक्षण पर, प्रदर्शन बाइट मैनिपुलेशन 2 के बराबर है।
ToHexString के लिए नीचे दिया गया कोड लुकअप और शिफ्ट एल्गोरिदम का एक अनुकूलित कार्यान्वयन है। यह Behrooz द्वारा लगभग एक समान है, लेकिन यह एक foreach
पुनरावृति का उपयोग करके निकलता है और एक काउंटर स्पष्ट रूप से देखने की तुलना में तेज़ होता हैfor
।
यह मेरी मशीन पर बाइट मैनिपुलेशन 2 के पीछे 2 वें स्थान पर आता है और बहुत पठनीय कोड है। निम्नलिखित परीक्षा परिणाम भी रुचि के हैं:
ToHexStringCharArrayWithCharCrArrayLookup: 41,589.69 औसत टिक (1000 से अधिक रन), 1.5X ToHexStringCharArrayWithStringLookup: 506464.06 औसत टिक (1000 से अधिक रन), 1.2X ToHexStringStringBuक्चरकारथ्रूकेहर।
उपरोक्त परिणामों के आधार पर यह निष्कर्ष निकालना सुरक्षित है:
यहाँ कोड है:
using System;
namespace ConversionExtensions
{
public static class ByteArrayExtensions
{
private readonly static char[] digits = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
public static string ToHexString(this byte[] bytes)
{
char[] hex = new char[bytes.Length * 2];
int index = 0;
foreach (byte b in bytes)
{
hex[index++] = digits[b >> 4];
hex[index++] = digits[b & 0x0F];
}
return new string(hex);
}
}
}
using System;
using System.IO;
namespace ConversionExtensions
{
public static class StringExtensions
{
public static byte[] ToBytes(this string hexString)
{
if (!string.IsNullOrEmpty(hexString) && hexString.Length % 2 != 0)
{
throw new FormatException("Hexadecimal string must not be empty and must contain an even number of digits to be valid.");
}
hexString = hexString.ToUpperInvariant();
byte[] data = new byte[hexString.Length / 2];
for (int index = 0; index < hexString.Length; index += 2)
{
int highDigitValue = hexString[index] <= '9' ? hexString[index] - '0' : hexString[index] - 'A' + 10;
int lowDigitValue = hexString[index + 1] <= '9' ? hexString[index + 1] - '0' : hexString[index + 1] - 'A' + 10;
if (highDigitValue < 0 || lowDigitValue < 0 || highDigitValue > 15 || lowDigitValue > 15)
{
throw new FormatException("An invalid digit was encountered. Valid hexadecimal digits are 0-9 and A-F.");
}
else
{
byte value = (byte)((highDigitValue << 4) | (lowDigitValue & 0x0F));
data[index / 2] = value;
}
}
return data;
}
}
}
नीचे दिए गए परीक्षण के परिणाम हैं जो मैंने अपने मशीन पर @ patridge के परीक्षण परियोजना में अपना कोड डालते समय प्राप्त किए। मैंने हेक्साडेसिमल से बाइट सरणी में बदलने के लिए एक परीक्षण भी जोड़ा। परीक्षण चलता है कि मेरे कोड का प्रयोग किया गया है बाइटएयरट्रेक्सहेक्सवीआप्टिमाइज्ड लुकअपएंडशिफ्ट और हेक्सटॉबएयरएयर्रेविआबाइटमैनिपुलेशन। HexToByteArrayViaConvertToByte XXXX से लिया गया था। HexToByteArrayViaSoapHexBinary @ Mykroft के उत्तर में से एक है।
इंटेल पेंटियम III Xeon प्रोसेसर
Cores: 4 <br/> Current Clock Speed: 1576 <br/> Max Clock Speed: 3092 <br/>
हेक्साडेसिमल स्ट्रिंग प्रतिनिधित्व में बाइट्स की सरणी बदलना
ByteArrayToHexViaByteManipulation2: 39,366.64 औसत टिक (1000 से अधिक रन), 22.4X
ByteArrayToHexViaOptimizedLookupAndShift: 41,588.64 औसत टिक (1000 से अधिक रन), 21.2X
ByteArrayToHexViaLookup: 55,509.56 औसत टिक (1000 से अधिक रन), 15,X
बाइटअरेत्रोटेक्सेक्सियाबाइटमैनिपुलेशन: 65,349.12 औसत टिक (1000 से अधिक रन), 13.5X
ByteArrayToHexViaLookupAndShift: 86,926.87 औसत टिक (1000 से अधिक रन), 10.2X
ByteArrayToHexStringViaBitConverter: 139,353.73 औसत टिक (1000 से अधिक रन), 6.3X
बाइटअरेत्रोटेक्सेक्सियासैपहैक्सबिनरी: 314,598.77 औसत टिक (1000 से अधिक रन), 2.8X
ByteArrayToHexStringViaStringBuilderForEachByteToString: 344,264.63 औसत टिक (1000 से अधिक रन), 2.6X
ByteArrayToHexStringViaStringBuilderAggregateByteToString: 382,623.44 औसत टिक (1000 से अधिक रन), 2.3X
ByteArrayToHexStringViaStringBuilderForEachAppendFormat: 818,111.95 औसत टिक (1000 से अधिक रन), 1.1X
ByteArrayToHexStringViaStringConcatArrayConvertAll: 839,244.84 औसत टिक (1000 से अधिक रन), 1.1X
ByteArrayToHexStringViaStringBuilderAggregateAppendFormat: 867,303.98 औसत टिक (1000 से अधिक रन), 1.0X
ByteArrayToHexStringViaStringJoinArrayConvertAll: 882,710.28 औसत टिक (1000 से अधिक रन), 1.0X
एक और तेजी से कार्य ...
private static readonly byte[] HexNibble = new byte[] {
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x8, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF
};
public static byte[] HexStringToByteArray( string str )
{
int byteCount = str.Length >> 1;
byte[] result = new byte[byteCount + (str.Length & 1)];
for( int i = 0; i < byteCount; i++ )
result[i] = (byte) (HexNibble[str[i << 1] - 48] << 4 | HexNibble[str[(i << 1) + 1] - 48]);
if( (str.Length & 1) != 0 )
result[byteCount] = (byte) HexNibble[str[str.Length - 1] - 48];
return result;
}