38 Soru: El ile bir kodlama belirtmeden, C # 'daki dizgelerin tutarlı bir bayt temsilini nasıl elde ederim?

tarafından oluşturulan soru Mon, Oct 1, 2018 12:00 AM

Belirli bir kodlamayı el ile belirtmeden string'u .NET'te (C #) byte[]'a nasıl dönüştürebilirim?

Dizgiyi şifreleyeceğim. Dönüştürmeden şifreleyebilirim, ancak kodlamanın neden burada oynatılmaya başladığını hala bilmek istiyorum.

Ayrıca kodlama neden dikkate alınmalı? Dize hangi baytların depolandığını basitçe öğrenemiyorum? Neden karakter kodlamalarına bağımlılık var?

    
2063
  1. Her dize bir bayt dizisi olarak depolanır mı? Neden bu baytlara basitçe sahip olamıyorum?
    2009-01-23 14: 05: 26Z
  2. kodlaması , karakterleri baytlarla eşleştiren şeydir. Örneğin, ASCII'de 'A' harfi 65 rakamıyla eşleşir. Farklı bir kodlamada, aynı olmayabilir. .NET çerçevesinde alınan dizgelere olan yüksek seviye yaklaşımı, bununla birlikte büyük ölçüde alakasız kılar (bu durumda hariç).
    2009-04-13 14: 13: 49Z
  3. Şeytanın savunucusunu oynamak için: Bellek içi bir dizenin baytlarını almak istiyorsanız (. HİÇ ASLA kodunu tekrar orijinal dizgiye dönüştürmek istemedi ... kodlamaları neden umursayacağınızı ya da hangisini kullanacağınızı seçeceğiniz açık değildir.
    2009-12-01 19: 47: 38Z
  4. Henüz hiç kimse bu bağlantıyı vermedi: joelonsoftware.com/articles/Unicode.html
    2010-06-29 02: 57: 28Z
  5. Bir karakter bir bayt değil ve bir bayt bir karakter değildir. Bir karakter hem yazı tipi tablosunun anahtarı hem de sözcük geleneğidir. Bir dize bir karakter dizisidir. (Bir sözcük, paragraf, cümle ve başlık aynı zamanda kendi tip tanımlarını haklı çıkaran kendi sözcük geleneklerine sahiptir - ama ben dalırım). Tam sayılar, kayan nokta sayıları ve diğer her şey gibi, karakterler de bayt olarak kodlanır. Kodlamanın bire bir basit olduğu bir zaman vardı: ASCII. Bununla birlikte, tüm insan sembolojisine uyum sağlamak için, bir baytın 256 permütasyonu yetersizdi ve kodlamalar, seçici olarak daha fazla bayt kullanmak için tasarlandı.
    2014-08-28 15: 43: 16Z
30 Yanıtlar                              30                         

Buradaki cevapların aksine, if kodlama konusunda endişelenmenize gerek yok, baytların yorumlanması gerekmez!

Bahsettiğiniz gibi, hedefiniz basitçe "dizenin hangi byte'ının depolandığını elde etmektir" .
(Ve tabii ki, dizgiyi baytlardan yeniden yapılandırabilmek için.)

Bu hedefler için dürüstçe yapmıyorum , insanların neden kodlamalara ihtiyacınız olduğunu söylemeye devam ettiğini anlamıyorum. Bunun için kodlamalar konusunda endişelenmenize kesinlikle gerek yok.

Bunun yerine sadece yapın:

 
static byte[] GetBytes(string str)
{
    byte[] bytes = new byte[str.Length * sizeof(char)];
    System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
    return bytes;
}

// Do NOT use on arbitrary bytes; only use on GetBytes's output on the SAME system
static string GetString(byte[] bytes)
{
    char[] chars = new char[bytes.Length / sizeof(char)];
    System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
    return new string(chars);
}

Programınız (veya diğer programlarınız), bir şekilde yapmak istediğinizden açıkça bahsetmediğiniz baytları yorumlamaya çalışmadığı sürece, hiçbir şey bu yaklaşımda yanlış! Kodlamalar konusunda endişelenmek, hayatınızı gerçek bir sebep olmadan daha karmaşık hale getirir.

Bu yaklaşımın ek faydası:

Dizginin geçersiz karakterler içerip içermediği önemli değil, çünkü verileri hala alabilir ve orijinal dizgiyi yine de yeniden oluşturabilirsiniz!

Aynı şekilde kodlanacak ve kodu çözülecektir, çünkü yalnızca baytlara bakıyorsunuz .

Belirli bir kodlama kullandıysanız, geçersiz karakterleri kodlama /kod çözme konusunda sorun çıkarırdı.

    
1798
2019-06-03 20: 34: 01Z
  1. NeBunun çirkin olması, GetString ve GetBytes'un çalışmak için aynı endianliğe sahip bir sistemde çalıştırılması gerektiğidir. Yani başka bir dizgeye dönüştürmek istediğiniz baytları almak için bunu kullanamazsınız. Bu yüzden, bunu kullanmak istediğim bir durumla karşılaşmak için çok zorlanıyorum.
    2012-05-13 11: 14: 52Z
  2. @ CodeInChaos: Söylediğim gibi, bunun asıl amacı, aynı işlevler dizisiyle aynı tür bir sistemde kullanmak istiyorsanız. Değilse, kullanmamalısınız.
    2012-05-13 18: 00: 27Z
  3. - 1 Birinin (baytları ve karakterleri anlamayan birisinin) dizesini bayt dizisine dönüştürmek isteyeceğini garanti ediyorum, google'ı okuyacak ve okuyacak bu cevabı yanlış bir şey yapacaklar, çünkü neredeyse her durumda, IS kodlaması uygun.
    2012-06-15 11: 07: 20Z
  4. @ artbristol: Cevapları okumaktan rahatsız olmazlarsa (veya diğer cevapları ...), üzgünüm, o zaman daha iyi bir yol yok benim onlarla iletişim kurmam için. Genelde cevabımla başkalarının ne yapabileceğini tahmin etmeye çalışmak yerine OP'yi yanıtlamayı tercih ediyorum - OP'nin bilmeye hakkı var ve sadece birinin bıçağı kötüye kullanabileceği için, dünyadaki tüm bıçakları gizlememiz gerektiği anlamına gelmiyor kendimiz için. Yine de aynı fikirde olmasanız da sorun değil.
    2012-06-15 14: 04: 28Z
  5. Bu cevap pek çok düzeyde yanlıştır ancak en başta "kodlama konusunda endişelenmenize gerek yok!" 2 yöntem, GetBytes ve GetString, Encoding.Unicode.GetBytes () ve Encoding.Unicode.GetString () 'in zaten yaptıklarının tamamen yeniden uygulanmaları kadar gereksizdir. "Programınız (veya diğer programlarınız) baytları yorumlamaya çalışmadığı sürece" ifadesi de temel olarak dolaylı olarak kusurludur, baytların Unicode olarak yorumlanması gerektiği anlamına gelir.
    2012-07-11 12: 36: 17Z

Dizininizin kodlamasına bağlıdır ( ASCII , UTF-8 , ...).

Örneğin:

 
byte[] b1 = System.Text.Encoding.UTF8.GetBytes (myString);
byte[] b2 = System.Text.Encoding.ASCII.GetBytes (myString);

Kodlamanın neden önemli olduğunu gösteren küçük bir örnek:

 
string pi = "\u03a0";
byte[] ascii = System.Text.Encoding.ASCII.GetBytes (pi);
byte[] utf8 = System.Text.Encoding.UTF8.GetBytes (pi);

Console.WriteLine (ascii.Length); //Will print 1
Console.WriteLine (utf8.Length); //Will print 2
Console.WriteLine (System.Text.Encoding.ASCII.GetString (ascii)); //Will print '?'

ASCII yalnızca özel karakterlerle başa çıkmak için donanımlı değildir.

Dahili olarak, .NET çerçevesi, dizeleri temsil etmek için UTF-16 kodlarını kullanır. NET'in kullandığı tam baytları almak istiyorsanız, System.Text.Encoding.Unicode.GetBytes (...)'u kullanın.

Bkz. .NET Framework'te Karakter Kodlaması (MSDN) daha fazla bilgi için.

    
1081
2015-04-24 09: 52: 05Z
  1. Ancak kodlama neden dikkate alınmalı? Hangi kodlamanın kullanıldığını görmek zorunda kalmadan neden sadece baytları alamıyorum? Zorunlu olsa bile, String nesnesinin kendisi hangi kodlamanın kullanıldığını bilmemeli ve sadece hafızada olanı boşaltmalı mıydı?
    2009-01-23 13: 48: 26Z
  2. Bir .NET dizeleri her zaman Unicode olarak kodlanır. Yani System.Text.Encoding.Unicode.GetBytes (); .NET'in karakterleri temsil etmek için kullanacağı bayt kümesini almak için. Ancak neden bunu istiyorsun? UTF-8'i özellikle çoğu karakter batı latin setindeyken öneririm.
    2009-01-23 14: 33: 29Z
  3. Ayrıca: onları alan sistem bu kodlamayı veya tutamağı işlemezse, dizesinde dahili olarak kullanılan tam baytlar önemli değildir yanlış kodlama olarak. Hepsi .Net'in içindeyse, neden bir bayt dizisine dönüştürebilirsiniz? Aksi takdirde, kodlamanızda açık olması daha iyidir
    2009-01-23 15: 42: 16Z
  4. @ Joel, Çalıştığı her makinede farklı olabileceği için System.Text.Encoding.Default ile dikkatli olun. Bu yüzden her zaman UTF-8 gibi bir kodlama belirtmeniz önerilir.
    2010-01-28 09: 01: 16Z
  5. Siz (veya başkası) verileri tedavi etmek yerine yorumla yapma niyetinde olmadığınız sürece, kodlamaya ihtiyacınız olmaz genel bir "bayt bloğu" olarak. Sıkıştırma, şifreleme, vb. Gibi şeyler için kodlama endişesi anlamsızdır. Kodlama konusunda endişelenmeden bunu yapmanın bir yolu için cevabım bölümüne bakın. (Yapmadığınızda kodlamalar konusunda endişelenmeniz gerektiğini söyleyen bir -1 vermiş olabilirim ama bugün özellikle kötü hissetmiyorum.: P)
    2012-04-30 07: 55: 05Z

Kabul edilen cevap çok, çok karmaşık. Bunun için dahil edilen .NET sınıflarını kullanın:

 
const string data = "A string with international characters: Norwegian: ÆØÅæøå, Chinese: 喂 谢谢";
var bytes = System.Text.Encoding.UTF8.GetBytes(data);
var decoded = System.Text.Encoding.UTF8.GetString(bytes);

Gerekmiyorsa tekerleği yeniden icat etme ...

    
269
2015-07-23 14: 32: 52Z
  1. Kabul edilen cevap sadece çok karmaşık değil, aynı zamanda felaket için bir reçetedir.
    2013-06-13 08: 40: 01Z
  2. Kabul edilen cevabın değişmesi durumunda, kayıt amaçlı olarak, bu geçerli saat ve tarihte Mehrdad'ın cevabıdır. Umarım OP bunu tekrar ziyaret eder ve daha iyi bir çözüm kabul eder.
    2013-09-27 18: 20: 56Z
  3. prensip olarak iyi ancak kodlamanın Mehrdad'ın cevabına eşdeğer olması için System.Text.Encoding.Unicode olması gerekir.
    2014-11-25 09: 08: 45Z
  4. @ AMissico, dizenizin sistem varsayılan kodlamanızla uyumlu olmadığından emin değilseniz (sistem varsayılan eski karakter dizisinde yalnızca ASCII karakterleri içeren dize). Ancak OP hiçbir yerde bunu belirtmiyor.
    2016-04-06 20: 53: 26Z
  5. @ AMissico Programın farklı sistemlerde farklı sonuçlar vermesine neden olabilir . Bu asla iyi bir şey değil. Bir karma veya başka bir şey yapmak için bile olsa (OP'nin 'şifrelemek' ile ne demek olduğunu varsayalım), aynı dize yine de her zaman aynı hastayı vermelidir.
    2016-04-22 10: 33: 15Z
 
BinaryFormatter bf = new BinaryFormatter();
byte[] bytes;
MemoryStream ms = new MemoryStream();

string orig = "喂 Hello 谢谢 Thank You";
bf.Serialize(ms, orig);
ms.Seek(0, 0);
bytes = ms.ToArray();

MessageBox.Show("Original bytes Length: " + bytes.Length.ToString());

MessageBox.Show("Original string Length: " + orig.Length.ToString());

for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo encrypt
for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo decrypt

BinaryFormatter bfx = new BinaryFormatter();
MemoryStream msx = new MemoryStream();            
msx.Write(bytes, 0, bytes.Length);
msx.Seek(0, 0);
string sx = (string)bfx.Deserialize(msx);

MessageBox.Show("Still intact :" + sx);

MessageBox.Show("Deserialize string Length(still intact): " 
    + sx.Length.ToString());

BinaryFormatter bfy = new BinaryFormatter();
MemoryStream msy = new MemoryStream();
bfy.Serialize(msy, sx);
msy.Seek(0, 0);
byte[] bytesy = msy.ToArray();

MessageBox.Show("Deserialize bytes Length(still intact): " 
   + bytesy.Length.ToString());
    
111
2009-01-26 06: 29: 52Z
  1. Tüm bu işlemler için aynı BinaryFormatter örneğini kullanabilirsiniz
    2009-01-23 17: 25: 59Z
  2. Çok İlgi Çekici. Görünüşe göre herhangi bir yüksek vekil Unicode karakteri düşecek. [BinaryFormatter ]
    2010-11-18 18: 51: 45Z
  3. @ ErikA.Brandstadmoen Buradaki testlerime bakın: stackoverflow.com/a/10384024
    2012-05-13 11: 12: 32Z

int kodlamasını almanız gerekiro hesap, çünkü 1 karakter 1 veya daha fazla byte ile temsil edilebilir (yaklaşık 6'ya kadar) ve farklı kodlamalar bu byte'leri farklı şekilde ele alır.

Joel'in bu konuda bir yazısı var:

  

Mutlak Minimum Her Yazılım Geliştiricisi Kesinlikle, Olumsuz, Unicode ve Karakter Kümeleri Hakkında Bilmeli )

    
91
2009-01-23 14: 03: 30Z
  1. "1 karakter 1 veya daha fazla bayt ile gösterilebilir" Kabul ediyorum. Dize hangi kodlamanın içinde olduğuna bakılmaksızın bu baytları istiyorum. Bir dizgenin bellekte saklanmasının tek yolu bayt cinsindendir. Karakterler bile 1 veya daha fazla bayt olarak saklanır. Sadece ellerimi baytlara sokmak istiyorum.
    2009-01-23 14: 07: 26Z
  2. Siz (veya başkası) verileri tedavi etmek yerine yorumla yapma niyetinde olmadığınız sürece, kodlamaya ihtiyacınız olmaz genel bir "bayt bloğu" olarak. Sıkıştırma, şifreleme, vb. Gibi şeyler için kodlama endişesi anlamsızdır. Kodlama konusunda endişelenmeden bunu yapmanın bir yolu için cevabım bölümüne bakın.
    2012-04-30 07: 54: 23Z
  3. @ Mehrdad - Tamamen, ancak ilk cevap verdiğimde asıl soru, dönüştürüldükten sonra bu baytlarda OP'nin ne olacağını ihmal etmedi onlar ve gelecekteki araştırmacılar için etrafındaki bilgiler geçerli - bu oldukça iyi bir şekilde Joel'in cevabı kapsamında - ve belirttiğiniz gibi Cevabınız içinde: .NET dünyasına sadık kalmanız ve dönüştürmek için yöntemlerinizi kullanmanız şartıyla, mutlusunuz. Bunun dışına çıkar çıkmaz kodlama önemlidir.
    2012-04-30 10: 48: 26Z
  4. Bir kod noktası , 4 bayta kadar gösterilebilir. (Bir UTF-32 kod birimi, bir UTF-16 vekil çifti veya 4 bayt UTF-8.) UTF-8'in 4 bayttan daha fazlasına ihtiyaç duyacağı değerler, 0x0.0.010FFFF Unicode aralığının dışında. ; -)
    2018-10-08 15: 05: 09Z

Bu popüler bir soru. Soru yazarının ne sorduğunu ve bunun en yaygın ihtiyaç olan şeyden farklı olduğunu anlamak önemlidir. Gerekmediği durumlarda kodun kötüye kullanılmasını önlemek için, ilk önce cevapladım.

Ortak İhtiyaç

Her dizgenin bir karakter seti ve kodlaması vardır. System.String nesnesini System.Byte dizisine dönüştürdüğünüzde hala bir karakter kümesi ve kodlaması vardır. Çoğu kullanımda, hangi karakter kümesine ve kodlamaya ihtiyacınız olduğunu bilirsiniz ve .NET, "dönüşümle kopyalamayı" kolaylaştırır. Uygun Encoding sınıfını seçin.

 
// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")

Dönüşümün, hedef karakter kümesinin veya kodlamanın kaynakta bulunan bir karakteri desteklemediği durumları ele alması gerekebilir. Bazı seçenekleriniz var: istisna, yerine koyma veya atlama. Varsayılan politika bir '?' Yerine koymaktır.

 
// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100")); 
                                                      // -> "You win ?100"

Açıkçası, dönüşümlerin mutlaka kayıpsız olması gerekmez!

Not: System.String için kaynak karakter kümesi Unicode'dur.

Kafa karıştırıcı olan tek şey, .NET'in, o karakter kümesinin belirli bir kodlamasının adı için bir karakter kümesinin adını kullanmasıdır. Encoding.Unicode, Encoding.UTF16 olarak adlandırılmalıdır.

Çoğu kullanım için budur. İhtiyacınız olan buysa, burada okumayı bırakın. Eğlenceye bakın Joel Spolsky makalesi bir kodlamanın ne olduğunu anlamadıysanız.

Özel İhtiyaç

Şimdi, soru yazarı şunu sorar: "Her dize bir bayt dizisi olarak depolanır, doğru mu? Neden bu baytlara sahip olamıyorum?"

Herhangi bir dönüşüm istemiyor.

C # spec 'dan:

  

C # 'daki karakter ve string işleme Unicode kodlamasını kullanır. Char   type, bir UTF-16 kod birimini, dize tipi ise   UTF-16 ko diziside birimler.

Öyleyse, null dönüşümünü istersek (yani, UTF-16'dan UTF-16'ya) sorarsak, istenen sonucu alacağımızı biliyoruz:  

Encoding.Unicode.GetBytes(".NET String to byte array")

Ancak kodlamalardan kaçınmak için başka bir yolla yapmalıyız. Bir ara veri türü kabul edilebilirse, bunun için kavramsal bir kısayol vardır:

 
".NET String to byte array".ToCharArray()

Bu bize istenen veri türünü sağlamaz ancak Mehrdad'ın cevabı bu Char dizisinin bir Byte dizisine nasıl dönüştürüleceğini gösterir BlockCopy 'i kullanarak. Ancak, bu dize iki kez kopyalar! Ayrıca, açıkça kodlamaya özgü bir kod kullanır: veri türü System.Char.

String'in depolandığı gerçek baytlara ulaşmanın tek yolu bir işaretçi kullanmaktır. fixed deyimi değerlerin adresinin alınmasına izin verir. C # spec’den:

  

[string] bir tür string ifadesi için, ... başlatıcı, hesaplar.   dizedeki ilk karakterin adresi.

Bunu yapmak için, derleyici yazar RuntimeHelpers.OffsetToStringData ile string nesnesinin diğer kısımlarına atlayarak kod yazar. Bu nedenle, ham baytları almak için dizgeye bir işaretçi oluşturun ve gereken bayt sayısını kopyalayın.

 
// using System.Runtime.InteropServices
unsafe byte[] GetRawBytes(String s)
{
    if (s == null) return null;
    var codeunitCount = s.Length;
    /* We know that String is a sequence of UTF-16 codeunits 
       and such codeunits are 2 bytes */
    var byteCount = codeunitCount * 2; 
    var bytes = new byte[byteCount];
    fixed(void* pRaw = s)
    {
        Marshal.Copy((IntPtr)pRaw, bytes, 0, byteCount);
    }
    return bytes;
}

@CodesInChaos'un işaret ettiği gibi, sonuç, makinenin türlüğüne bağlıdır. Ancak soru yazarı bununla ilgilenmiyor.

    
85
2017-05-23 10: 31: 37Z
  1. Genel olarak, byteCount'u dize uzunluğunun iki katı olarak ayarlamak doğru değildir. Temel Çok Dilli Düzlem dışındaki Unicode kod noktaları için, her karakter için iki adet 16 bit kod birimi olacaktır.
    2014-02-04 02: 33: 44Z
  2. @ Jan Bu doğru, ancak dize uzunluğu zaten kod birimlerinin sayısını veriyor (kod noktaları değil).
    2014-02-04 02: 35: 29Z
  3. Buna dikkat çektiğiniz için teşekkürler! MSDN'den: "Length özelliği [ String], bu örnekte, Unicode karakterlerinin sayısını değil, Char nesnesinin sayısını döndürür." Bu nedenle, örnek kodunuz yazıldığı şekilde doğrudur.
    2014-02-04 05: 42: 50Z
  4. @ TomBlodget: İlginç bir şekilde, Globalization.SortKey örnek alırsa, KeyData'u ayıklar ve sonuçtaki baytları her biri bir String'a paketler [karakter başına iki bayt, İlk olarak MSB ], ortaya çıkan dizgilerden String.CompareOrdinal'u çağırmak, SortKey.Compare'daki SortKey'u aramaktan ve hatta bu durumlarda memcmp'u aramaktan çok daha hızlı olacaktır. Buna göre, neden KeyData'un neden Byte[] yerine String'u döndürdüğünü merak ediyorum?
    2014-11-13 17: 56: 04Z
  5. @ TomBlodget: fixed veya unsafe koduna ihtiyacınız yok, ayrıca var gch = GCHandle.Alloc("foo", GCHandleType.Pinned); var arr = new byte[sizeof(char) * ((string)gch.Target).Length]; Marshal.Copy(gch.AddrOfPinnedObject(), arr, 0, arr.Length); gch.Free(); da yapabilirsiniz
    2018-01-28 04: 27: 51Z

Sadece Mehrdrad’ın sesinin yanıtladığını göstermek için yaklaşımı eşlenmemiş yedek karakterler (bunların çoğu Cevabımın seviyesine düştü, ancak bunlardan herkes eşit derecede suçluydu, örneğin System.Text.Encoding.UTF8.GetBytes, System.Text.Encoding.Unicode.GetBytes, bu kodlama yöntemleri mesela d800 gibi yüksek vekil karakterleri kaldıramazlar ve sadece yüksek vekil karakterleri fffd ile değiştirenler):

 
using System;

class Program
{     
    static void Main(string[] args)
    {
        string t = "爱虫";            
        string s = "Test\ud800Test"; 

        byte[] dumpToBytes = GetBytes(s);
        string getItBack = GetString(dumpToBytes);

        foreach (char item in getItBack)
        {
            Console.WriteLine("{0} {1}", item, ((ushort)item).ToString("x"));
        }    
    }

    static byte[] GetBytes(string str)
    {
        byte[] bytes = new byte[str.Length * sizeof(char)];
        System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
        return bytes;
    }

    static string GetString(byte[] bytes)
    {
        char[] chars = new char[bytes.Length / sizeof(char)];
        System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
        return new string(chars);
    }        
}

Çıktı:

 
T 54
e 65
s 73
t 74
? d800
T 54
e 65
s 73
t 74

System.Text.Encoding.UTF8.GetBytes veya System.Text.Encoding.Unicode.GetBytes ile deneyin, yalnızca yüksek vekil karakterlerin yerine geçecekler. strong> FFFD

Her ne zaman bu soruda bir hareket varsa, hala eşleştirilmemiş vekil karakterleri içeren karakterleri bile tutabilen bir seri hale getirici (Microsoft'tan veya 3. taraf bileşeninden) düşünüyorum; Bunu şimdi ve sonra google’a bırakıyorum: serileştirme eşlenmemiş vekil karakter .NET . Bu beni hiç uyutmamı sağlamaz ama bu kHer ne zaman ve ne zaman can sıkıcı olduğumdan sonra cevabımın kusurlu olduğunu söyleyen birileri var, ama cevapları eşleştirilmemiş yedek karakterler söz konusu olduğunda cevapları da eşit.

Kahretsin, Microsoft System.Buffer.BlockCopy’da BinaryFormatter’u kullanmalıydı ツ

谢谢!

    
43
2017-05-23 12: 18: 28Z
  1. Geçerli kod noktaları oluşturmak için vekillerin çiftler halinde görünmesi gerekmez mi? Durum buysa, verilerin neden yönetildiğini anlayabilirim.
    2012-06-14 14: 27: 32Z
  2. @ dtanders Evet, bu benim düşüncelerim de, çiftler halinde görünmek zorundalar, eşleştirilmemiş vekil karakterler yalnızca dizeye koyup eşleştirilmemeleri durumunda ortaya çıkar. Bilmediğim şey, diğer geliştiricilerin neden serileştirme yaklaşımını gördükleri için kodlamaya duyarlı yaklaşımı kullanmamız gerektiğine dair sürekli devam etmeleridir ( 3 yıldan uzun süredir kabul edilen bir cevap olan cevabım , eşleştirilmemiş vekil karakterini sağlam tutmuyor. Ancak kodlamaya duyarlı çözümlerinin, eşlenmemiş vekil karakterini, yani ironiyi koruyamadığını kontrol etmeyi unuttular.
    2012-06-14 23: 23: 30Z
  3. Dahili olarak System.Buffer.BlockCopy kullanan bir seri hale getirme kütüphanesi varsa, tüm kodlama-savunuculuk yapan kişilerin argümanları tartışılır
    2012-06-14 23: 23: 58Z
  4. @ MichaelBuen Bana göre asıl mesele, bir şey önemli değil, onların önemli değil. vaka. Sonuç olarak, cevabınıza bakan insanları, gelecekte başkalarının hayal kırıklığına uğramasına neden olacak temel programlama hataları yapmaya teşvik ediyorsunuz. Eşlenmemiş vekiller bir dizgede geçersiz. Bu bir char dizisi değildir, bu yüzden bir dizgiyi başka bir biçime dönüştürmenin bu karakterde FFFD hatasıyla sonuçlanması mantıklıdır. Elle dize işleme yapmak istiyorsanız, önerildiği gibi bir karakter [] kullanın.
    2014-11-11 20: 06: 47Z
  5. @ dtanders: Bir System.String, değişmez bir Char dizisidir; .NET, her zaman String'dan Char[] nesnesinin oluşturulmasına izin verdi ve orijinal Char[] eşleştirilmemiş vekiller içeriyorsa bile içeriğini aynı değerleri içeren Char[]'a aktardı.
    2014-11-12 21: 57: 26Z

Sorunuzun ilk kısmı (baytların nasıl alınacağı) başkaları tarafından zaten yanıtlandı: System.Text.Encoding ad alanına bakın.

İzleme sorunuzu ele alacağım: neden bir kodlama seçmeniz gerekiyor? Neden bunu string sınıfının kendisinden alamıyorsun?

Cevap iki bölümden oluşuyor.

Öncelikle, dizgi sınıfı tarafından dahili olarak kullanılan baytlar önemli değildir ve ne zaman varsayalım, muhtemelen bir hata ile karşılaşıyorsunuzdur.

Programınız tamamen .Net dünyasındaysa, bir ağ üzerinden veri gönderiyor olsanız bile, dizgeler için bayt dizileri alma konusunda endişelenmenize gerek yoktur. Bunun yerine, veri iletimi konusunda endişelenmek için .Net Seri hale getirme kullanın. Artık gerçek baytlar için endişelenmiyorsunuz: Seri hale getirme biçimlendiricisi sizin için yapıyor.

Diğer yandan, bu baytları bir .Net serileştirilmiş akıştan veri alacağını garanti edemeyeceğiniz bir yere gönderirseniz ne olur? Bu durumda kesinlikle kodlama konusunda endişelenmeniz gerekir, çünkü açıkçası bu harici sistem önemsiyor. Yine, dizge tarafından kullanılan dahili baytların önemi yoktur: bir kodlama seçmeniz gerekir, böylece alıcı tarafından bu kodlama hakkında açık olabilirsiniz, hatta dahili olarak .NET tarafından kullanılan aynı kodlama olsa bile.

Anladığım kadarıyla, bu durumda, mümkünse bellekte string değişkeni tarafından saklanan gerçek byte'ları kullanmayı tercih edebileceğinizi, bayt akışınızı yaratan bazı işleri kurtarabileceğini düşünerek biliyorum. Bununla birlikte, çıktınızın diğer ucunda anlaşıldığından emin olmak ve kodlamanızla açık bir şekilde olmanızı garanti etmek yerine, sizin için önemli değil. Ek olarak, bendahili byte'larınızı gerçekten eşleştirmek istiyorsanız, zaten Unicode kodlamasını seçebilir ve bu performans tasarrufunu elde edebilirsiniz.

Bu da beni ikinci bölüme getiriyor ... Unicode kodunu seçerek diyerek .Net'in altındaki baytları kullanmasını söylüyorum. Bu kodlamayı seçmeniz gerekir, çünkü bazı yeni çıkmış Unicode-Plus'lar çıktığında .Net çalışma zamanı, programınızı bozmadan daha yeni ve daha iyi kodlama modelini kullanmak için ücretsiz olmalıdır. Ancak, şu an için (ve yakın gelecekte), yalnızca Unicode kodlamasını seçmek size istediğiniz şeyi verir.

Dizginizin kabloya yeniden yazılması gerektiğini ve eşleşen bir kodlama kullansanız bile bit deseninin bazı çevirilerini içeren bir anlam ifade etmek de önemlidir. Bilgisayarın, Little vs Little Endian, ağ bayt sırası, paketleme, oturum bilgileri vb. Gibi şeyleri hesaba katması gerekir.

    
43
2017-09-25 21: 13: 44Z
  1. .NET'te dizeler için bayt dizileri almanız gereken alanlar var. .NET Cryptrography sınıflarının çoğu, byte dizisini veya akışını kabul eden ComputeHash () gibi yöntemler içerir. Bir dizgiyi önce bir bayt dizisine (bir Kodlama seçerek) dönüştürmek ve sonra isteğe bağlı olarak bir akışa sarmaktan başka seçeneğiniz yok. Ancak bir kodlama seçtiğiniz sürece (yani UTF8) onunla bir sopa bu konuda hiçbir sorun yoktur.
    2010-01-28 09: 33: 21Z

Bunu deneyin, çok daha az kod:

 
System.Text.Encoding.UTF8.GetBytes("TEST String");
    
39
2015-04-24 09: 58: 10Z
  1. Sonra System.Text.Encoding.UTF8.GetBytes("Árvíztűrő tükörfúrógép);'u deneyin ve ağlayın! Çalışacak, ancak System.Text.Encoding.UTF8.GetBytes("Árvíztűrő tükörfúrógép").Length != System.Text.Encoding.UTF8.GetBytes("Arvizturo tukorfurogep").Length ise "Árvíztűrő tükörfúrógép".Length == "Arvizturo tukorfurogep".Length
    2017-12-05 16: 30: 19Z
  2. @ mg30rg: Neden örneğinizin garip olduğunu düşünüyorsunuz? Elbette değişken genişlikli bir kodlamada tüm karakterler aynı bayt uzunluğuna sahip değildir. Bunda yanlış olan ne?
    2018-02-25 01: 18: 35Z

Pekala, tüm cevapları okudum ve kodlanmamış ya da eşlenmemiş vekilleri düşüren serileştirme hakkında bir tane kullanıyorlardı.

Örneğin, dize, oluşturulduğu yer olan SQL Server 'dan geldiğinde kötü bir bayt dizisi, örneğin bir şifre karması depolar. Ondan bir şey bırakırsak, geçersiz bir karma depolar ve XML'de saklamak istiyorsak bozulmadan bırakmak isteriz (çünkü XML yazıcısı bulduğu eşlenmemiş herhangi bir vekilde istisna bırakmaktadır).

Bu nedenle, bu gibi durumlarda bayt dizilerinin kodlamasını Base64 kullanıyorum, ancak İnternet’te hey C # 'a bunun için tek bir çözüm var ve içinde hata var ve sadece bir yolu var, bu yüzden hatayı düzelttim ve prosedürü geri yazdım. İşte, gelecekteki çalışanlar:

 
public static byte[] StringToBytes(string str)
{
    byte[] data = new byte[str.Length * 2];
    for (int i = 0; i < str.Length; ++i)
    {
        char ch = str[i];
        data[i * 2] = (byte)(ch & 0xFF);
        data[i * 2 + 1] = (byte)((ch & 0xFF00) >> 8);
    }

    return data;
}

public static string StringFromBytes(byte[] arr)
{
    char[] ch = new char[arr.Length / 2];
    for (int i = 0; i < ch.Length; ++i)
    {
        ch[i] = (char)((int)arr[i * 2] + (((int)arr[i * 2 + 1]) << 8));
    }
    return new String(ch);
}
    
25
2017-03-09 08: 55: 32Z
  1. Bir bayt dizisini base64'e dönüştürmek için özel yönteminizi kullanmak yerine, tek yapmanız gereken yerleşik dönüştürücüyü kullanmaktı: Convert.ToBase64String (arr);
    2012-02-10 15: 53: 36Z
  2. @ Makotosan teşekkür ederim, ancak temel 64 dönüşümler Convert.ToBase64String(arr); için byte[] (data) <-> string (serialized data to store in XML file) kullandım. Fakat ilk byte[] (data)’u elde etmek için, binary verilerini içeren String ile bir şeyler yapmam gerekiyordu (MSSQL'in bana döndürme şekli). SO yukarıdaki işlevler String (binary data) <-> byte[] (easy accessible binary data) içindir.
    2012-03-06 19: 15: 02Z
  

Ayrıca lütfen kodlamanın neden dikkate alınması gerektiğini de açıklayın.   Dize hangi baytların depolandığını basitçe öğrenemiyorum?   Neden bu kodlamaya bağımlılık? !!!

Çünkü "dizenin baytları" diye bir şey yoktur.

Bir dize (veya daha genel olarak bir metin) karakterlerden oluşur: harfler, rakamlar ve diğer semboller. Bu kadar. Ancak bilgisayarlar karakterler hakkında hiçbir şey bilmezler; sadece baytları kullanabilirler. Bu nedenle, bir bilgisayar kullanarak metin depolamak veya iletmek istiyorsanız, karakterleri baytlara dönüştürmeniz gerekir. Bunu nasıl yaptın? Kodlamaların gerçekleştiği yer burasıdır.

Bir kodlama, mantıksal karakterleri fiziksel baytlara çevirmek için yapılan bir kuraldan başka bir şey değildir. En basit ve en iyi bilinen kodlama ASCII'dir ve İngilizce yazıyorsanız ihtiyacınız olan tek şey budur. Diğer diller için, daha eksiksiz kodlamalara ihtiyacınız olacak, Unicode tatlarından herhangi biri olmak, bugünlerde en güvenli seçenek.

Yani, "kodlama kullanmadan bir dizginin baytlarını almaya" çalışmak "imkansız" herhangi bir dil kullanmadan bir metin yazmak "kadar mümkün değildir.

Bu arada, sizi (ve bu konuda kimsenin) bu küçük bilgeliği okumasını şiddetle tavsiye ediyorum: Mutlak Minimum Her Yazılım Geliştiricisi Kesinlikle, Unicode ve Karakter Kümelerini Mutlak Olarak Bilmeli (Mazeret Yok!)

    
22
2015-10-23 06: 19: 47Z
  1. Açıklamama izin ver: "Merhaba dünyayı" fiziksel baytlara çevirmek için bir kodlama kullanıldı. Dize bilgisayarımda depolandığından, bayt olarak depolanması gerektiğinden eminim. Sadece bu baytlara diskte veya başka bir nedenden dolayı kaydetmek için erişmek istiyorum. Bu baytları yorumlamak istemiyorum. Bu baytları yorumlamak istemediğim için, bu noktada bir kodlamaya duyulan ihtiyaç, printf'i çağırmak için bir telefon hattını gerektirmek kadar yanlış.
    2009-07-16 15: 30: 48Z
  2. Yine de, bir kodlama kullanmadığınız sürece metin-fiziksel-bayt-çeviri kavramı yoktur. Elbette, derleyici dizeleri bir şekilde bellekte saklar - fakat sadece sizin (ya da derleyici geliştiricisi dışındaki herhangi birinin) bilmediği bir dahili kodlama kullanıyordur. Bu nedenle, ne yaparsanız yapın, bir dizgiden fiziksel bayt almak için bir kodlamaya ihtiyacınız var.
    2009-07-22 08: 35: 39Z
  3. @ Agnel Kurian: Elbette, bir dizgenin içeriğini saklayan bir yerde bir demet bayt olduğu doğru (UTF-16 afair). Ancak, erişmenizi engellemek için iyi bir neden var: dizeler değişmez ve eğer iç byte [] dizisini elde edebiliyorsanız, onu da değiştirebilirsiniz. Bu, çok sayıda dizgenin aynı verileri paylaşabilmesi nedeniyle hayati önem taşıyan değişkenliği bozar. Dizeyi almak için UTF-16 kodlaması kullanmak büyük olasılıkla yalnızca verileri kopyalayacaktır.
    2011-05-14 00: 06: 56Z
  4. @ Gnafoo, Baytların bir kopyası olur.
    2011-05-14 05: 06: 15Z

string’dan byte dizisine dönüştürmek için C #:

 
public static byte[] StrToByteArray(string str)
{
   System.Text.UTF8Encoding  encoding=new System.Text.UTF8Encoding();
   return encoding.GetBytes(str);
}
    
21
2016-08-12 18: 39: 11Z

Dize ve bayt dizisi arasında dönüşüm yapmak için aşağıdaki kodu kullanabilirsiniz.

 
string s = "Hello World";

// String to Byte[]

byte[] byte1 = System.Text.Encoding.Default.GetBytes(s);

// OR

byte[] byte2 = System.Text.ASCIIEncoding.Default.GetBytes(s);

// Byte[] to string

string str = System.Text.Encoding.UTF8.GetString(byte1);
    
17
2014-09-09 11: 30: 51Z
  1. VUPBu sorunumu çözdü (bayt [] ff = ASCIIEncoding.ASCII.GetBytes (barcodetxt.Text);)
    2015-09-09 13: 19: 57Z
 
byte[] strToByteArray(string str)
{
    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    return enc.GetBytes(str);
}
    
16
2009-01-23 13: 43: 18Z
  1. Ancak kodlama neden dikkate alınmalı? Hangi kodlamanın kullanıldığını görmek zorunda kalmadan neden sadece baytları alamıyorum? Zorunlu olsa bile, String nesnesinin kendisi hangi kodlamanın kullanıldığını bilmemeli ve sadece hafızada olanı boşaltmalı mıydı?
    2009-01-23 13: 46: 40Z
  2. Bu her zaman işe yaramaz. Bazı özel karakterler zor yoldan bulduğum bir yöntemi kullanarak kaybolabilir.
    2009-01-23 17: 14: 16Z
  3. karakter kümesi utf olsaydı işe yaramazdı!
    2012-09-18 06: 27: 31Z

Emin değilim, ancak dize bilgilerini baytlarla etkin olmayan bir Chars dizisi olarak sakladığını düşünüyorum. Spesifik olarak, Char tanımı "Unicode karakterini temsil eder" şeklindedir.

bu örnek örneği alın:

 
String str = "asdf éß";
String str2 = "asdf gh";
EncodingInfo[] info =  Encoding.GetEncodings();
foreach (EncodingInfo enc in info)
{
    System.Console.WriteLine(enc.Name + " - " 
      + enc.GetEncoding().GetByteCount(str)
      + enc.GetEncoding().GetByteCount(str2));
}

Unicode cevabının her iki durumda da 14 bayt olduğuna dikkat edin, UTF-8 cevabı ise birinci için sadece 9 bayt, ikincisinde ise sadece 7'dir.

Yani dizginin kullandığı baytları istiyorsanız, Encoding.Unicode'u kullanın, ancak depolama alanı ile verimsiz olacaktır.

    
13
2016-08-12 18: 38: 55Z

C # ile yayınlanan Span<T> 'un gelişiyle 7.2, bir dizgenin altında yatan bellek gösterimini yönetilen bayt dizisine yakalamak için kullanılan kurallı teknik:

 
byte[] bytes = "rubbish_\u9999_string".AsSpan().AsBytes().ToArray();

Onu geri dönüştürmek bir başlangıç ​​olmamalıdır, çünkü bu aslında verileri bir şekilde yorumladığınız anlamına gelir, ancak tamamlanma adına:

 
string s;
unsafe
{
    fixed (char* f = &bytes.AsSpan().NonPortableCast<byte, char>().DangerousGetPinnableReference())
    {
        s = new string(f);
    }
}

NonPortableCast ve DangerousGetPinnableReference adları, muhtemelen bunu yapmamanız gerektiği argümanını ilerletmelidir.

Span<T> ile çalışmanın System.Memory NuGet paketini yüklemesi gerektiğini unutmayın .

Her şeye rağmen, gerçek orijinal soru ve takip yorumları, temel hafızanın “yorumlanmaması” anlamına gelir (ki, demek istediğim, değiştirmenin ya da yazma zorunluluğunun ötesinde okunmadığını farz ediyorum). is), Stream sınıfının bir kısmının uygulanmasının, veriler hakkında herhangi bir karakter dizisi olarak düşünülmesi yerine kullanılması gerektiğini belirtir.

    
12
2018-01-10 20: 21: 12Z

Temel sorun, bir dizedeki glifin 32 bit (karakter kodu için 16 bit) almasıdır, ancak bir baytın yalnızca 8 bit ayıracağı durumdur. Kendinizi yalnızca ASCII karakterleri içeren dizelerle kısıtlamadığınız sürece bire bir eşleme yapılmaz. System.Text.Encoding, bir dizgiyi bayt [] ile eşlemenin birçok yoluna sahiptir; bilgi kaybını önleyen ve bayt [] 'ı bir dizeye eşlemesi gerektiğinde müşteriniz tarafından kullanması kolay olanı seçmeniz gerekir. .

Utf8 popüler bir kodlamadır, küçüktür ve kayıplı değildir.

    
11
2009-01-23 14: 15: 26Z
  1. UTF-8 yalnızca karakterlerinizin çoğunluğu İngilizce (ASCII) karakter kümesindeyse küçüktür. Uzun bir Çince karakter dizisine sahipseniz, UTF-16 bu dize için UTF-8'den daha kompakt bir kodlama olur. Bunun nedeni UTF-8'in ASCII'yi kodlamak için bir bayt, aksi takdirde 3'ü (veya belki 4) kullanmasıdır.
    2009-01-23 20: 40: 59Z
  2. Doğru. Ancak, Çince metinleri nasıl kullanacağınızı biliyorsanız kodlamayı nasıl bilmezsiniz?
    2009-01-24 03: 40: 31Z

En hızlı yol

 
public static byte[] GetBytes(string text)
{
    return System.Text.ASCIIEncoding.UTF8.GetBytes(text);
}

DÜZENLEME Makotosan'ın yorumladığı gibi bu şimdi en iyi yol:

 
Encoding.UTF8.GetBytes(text)
    
8
2016-08-04 10: 31: 17Z
  1. ASCIIEncoding ..... gerekli değil. Sadece Encoding.UTF8.GetBytes (text) kullanarak tercih edilir.
    2012-02-17 20: 40: 25Z

Kullanım:

 
    string text = "string";
    byte[] array = System.Text.Encoding.UTF8.GetBytes(text);

Sonuç:

 
[0] = 115
[1] = 116
[2] = 114
[3] = 105
[4] = 110
[5] = 103
    
8
2017-01-09 01: 22: 07Z
  1. OP, belirli bir kodlamayı manuel olarak belirtmeden, özellikle bir kodlama belirtmemesini ister ... "
    2018-08-30 13: 40: 21Z
  

Belirli bir kodlamayı manuel olarak belirtmeden .NET'te (C #) bir dizgiyi bir bayta [] nasıl dönüştürebilirim?

Bir dize .NET, metni bir UTF-16 kod birimi dizisi olarak gösterir, bu nedenle baytlar zaten UTF-16'da bellekte kodlanmıştır.

Mehrdad'ın Cevabı

Mehrdad’ın cevabını kullanabilirsiniz, ancak karakter kodları UTF-16 olduğundan kodlama kullanıyor. kaynağını oluşturan ve bir char[] oluşturan kopyalayan ToCharArray'ı çağırır doğrudan buna bellek. Daha sonra verileri ayrıca tahsis edilen bir bayt dizisine kopyalar. Bu nedenle, başlık altında iki kez altındaki baytları kopyalıyor ve aramadan sonra kullanılmayan bir karakter dizisi ayırıyor.

Tom Blodget’ın Cevabı

Tom Blodget'in cevabı , karakter dizisi ayırmanın orta adımını atladığından beri Mehrdad'dan% 20-30 daha hızlıdır ve baytları kopyalamak, ancak /unsafe seçeneğiyle derlemenizi gerektirir. Eğer kesinlikle kodlama kullanmak istemiyorsanız, bence bu yoldur. Şifreleme giriş bilgilerinizi fixed bloğuna koyarsanız, ayrı bir bayt dizisi ayırmanıza ve baytları kopyalamanıza bile gerek kalmaz.

  

Ayrıca kodlama neden dikkate alınmalı? Dize hangi baytların depolandığını basitçe öğrenemiyorum? Neden karakter kodlamalarına bağımlılık var?

Çünkü bunu yapmanın doğru yolu budur. string bir soyutlamadır.

Geçersiz karakterler içeren 'dizeler' varsa kodlama kullanmak size sorun çıkarabilir, ancak bu olmamalıdır. Geçersiz karakterlerle dizginize veri alıyorsanız, yanlış yapıyorsunuz demektir. Muhtemelen, başlamak için bir bayt dizisi veya Base64 kodlaması kullanıyor olmalısınız.

System.Text.Encoding.Unicode kullanıyorsanız, kodunuz daha dayanıklı olacaktır. Kodunuzun çalışacağı sistemin endianness hakkında endişelenmenize gerek yok. CLR'nin bir sonraki sürümünün farklı bir dahili karakter kodlaması kullanması durumunda endişelenmenize gerek yok.

Sanırım soru neden kodlama konusunda endişelenmek istemediğinizi değil, neden ihmal etmek ve başka bir şey kullanmak istediğinizi düşünüyorum. Kodlamanın, bayt dizisindeki bir dizgenin soyutlamasını temsil etmesi amaçlanmıştır. System.Text.Encoding.Unicode size küçük bir endian bayt sırası kodlaması verecek ve şimdi ve gelecekte her sistemde aynı işlemi gerçekleştirecektir.

    
8
2018-07-02 20: 51: 49Z

string’u .NET'te byte array’a dönüştürmek için aşağıdaki kodu kullanabilirsiniz

 
string s_unicode = "abcéabc";
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s_unicode);
    
6
2014-05-02 07: 39: 30Z

OP’nin sorusuna en yakın yaklaşım Tom Obje’dir, aslında nesneye girer ve baytları çıkarır. Ben en yakın diyorum çünkü bu String Nesnesinin uygulanmasına bağlı.

 
"Can't I simply get what bytes the string has been stored in?"

Elbette, ancak sorudaki temel hatanın ortaya çıktığı yer burasıdır. Dize, ilginç bir veri yapısına sahip olabilecek bir nesnedir. Bunu zaten biliyoruz, çünkü eşleştirilmemiş taşıyıcıların saklanmasına izin veriyor. Uzunluğu saklayabilir. Hızlı sayma imkanı sağlayan 'eşleştirilmiş' vekillerin her birine işaret edebilir. Vb. Bu fazladan baytların tümü karakter verilerinin bir parçası değil.

İstediğiniz şey, bir dizideki her karakterin baytıdır. Ve 'kodlamanın' geldiği yer burasıdır. Varsayılan olarak UTF-16LE'yi alırsınız. Gidiş-dönüş hariç baytların kendileri umrunda değilse, 'varsayılan' da dahil olmak üzere herhangi bir kodlamayı seçebilir ve daha sonra geri dönüştürebilirsiniz (varsayılan kodlamanın ne olduğu gibi aynı parametreleri varsayarak, kod noktaları, hata düzeltmeleri) , eşlenmemiş taşıyıcılar vb. gibi şeylere izin verilir.

Ama neden 'kodlamayı' sihir için bıraktın? Neden kodlamayı belirtmiyorsunuz, böylece hangi baytları alacağınızı bilmek için?

 
"Why is there a dependency on character encodings?"

Kodlama (bu bağlamda) sadece dizenizi temsil eden bayt anlamına gelir. String nesnesinin baytları değil. Dizenin içinde bulunduğu baytları istediniz - bu, sorunun saf olarak sorulduğu yerdi. Bir dize nesnesinin içerebileceği diğer ikili verilerin tümünü değil, dizeyi temsil eden bitişik bir dizide dizenin bayt olmasını istediniz.

Bu, bir dizenin nasıl saklandığı anlamına gelmez. Bir bayt dizisindeki baytlara "Kodlanmış" bir dize istiyorum.

Tom Bloget’in cevabını beğendim çünkü sizi 'string nesnesinin baytları' yönüne götürdü. Yine de uygulamaya bağlı ve içeriden gözetleme yaptığı için dizenin bir kopyasını yeniden oluşturmak zor olabilir.

Mehrdad'ın cevabı yanlıştır çünkü kavramsal düzeyde yanıltıcıdır. Hala kodlanmış bir bayt listeniz var. Özel çözümü, eşleştirilmemiş taşıyıcıların korunmasını sağlar - bu uygulamaya bağlıdır. Özel çözümü, GetBytes dizeyi varsayılan olarak UTF-8'de döndürdüyse dizenin baytlarını doğru üretmez.


Bu konudaki fikrimi değiştirdim (Mehrdad'ın çözümü) - ipeğin baytını almıyor; bunun yerine, dizeden yaratılan karakter dizisinin baytlarını alıyor. Kodlamaya bakılmaksızın, c # içindeki char veri türü sabit bir boyuttur. Bu, tutarlı bir uzunluk bayt dizisinin üretilmesine izin verir ve karakter dizisinin bayt dizisinin boyutuna bağlı olarak çoğaltılmasını sağlar. Yani kodlama UTF-8 olsaydı, ancak her karakter en büyük utf8 değerine uyması için 6 bayt olsaydı, yine de çalışırdı. Gerçekten de - karakterin kodlanması önemli değil.

Ancak bir dönüşüm kullanıldı - her karakter sabit bir boyut kutusuna (c # karakter karakteri) yerleştirildi. Bununla birlikte, bu temsilin önemi yoktur, teknik olarak OP'nin cevabı budur. Öyleyse - yine de dönüştürecekseniz ... Neden 'kodlamıyorsunuz'?

    
6
2017-11-01 19: 44: 31Z
  1. Bu karakterler UTF-8 veya UTF-16, hatta UTF-32 tarafından desteklenmiyor : 񩱠 & (Char) 55906 & (Char) 55655. Bu nedenle hatalı olabilirsiniz ve Mehrdad'ın cevabı ne tür kodlamalar kullanıldığını düşünmeden güvenli bir dönüşümdür.
    2016-02-11 19: 48: 49Z
  2. Raymon, karakterler zaten bir unicode değeriyle temsil edilir - ve tüm unicode değerleri tüm utf'ler tarafından temsil edilebilir. Ne hakkında konuştuğunuz hakkında daha uzun bir açıklama var mı? Bu iki değer (veya 3 ..) hangi karakter kodlamasını içerir?
    2016-02-11 20: 47: 14Z
  3. Herhangi bir kodlama aralığı tarafından desteklenmeyen geçersiz karakterlerdir. th% 100 yararsız oldukları anlamına gelmez. Kodlamalardan bağımsız olarak herhangi bir dize türünü bayt dizisi eşdeğerine dönüştüren bir kod, yanlış bir çözüm değildir ve istenen durumlarda kendi kullanımlarına sahiptir.
    2016-02-11 21: 02: 37Z
  4. Tamam, o zaman sorunu anlamadığınızı düşünüyorum. Unicode uyumlu bir dizi olduğunu biliyoruz - aslında, çünkü .net, UTF-16 olduğunu biliyoruz. Yani bu karakterler orada olmayacak. Ayrıca, içsel temsillerin değiştirilmesiyle ilgili yorumumu tam olarak okumamışsınız. Dize, kodlanmış bir bayt dizisi değil, bir nesnedir. Bu yüzden son ifadene katılmayacağım. Kodun tüm unicode dizelerini herhangi bir UTF kodlamasına dönüştürmesini istiyorsunuz. Bu, istediğinizi doğru bir şekilde yapar.
    2016-02-11 22: 17: 24Z
  5. Nesneler, asıl durumundaki bir nesneyi tanımlayan başlangıçta bit dizisi veri dizisidir. Bu nedenle programlama dillerindeki her veri, herhangi bir nesnenin durumunu bellekte tutmanız gerekebileceğinden bayt dizisine dönüştürülebilir (her bayt 8 bit tanımlar). Bir bayt dizisini dosyaya veya hafızaya kaydedip tutabilir ve tamsayı, bigint, resim, Ascii string, UTF-8 string, şifreli string veya diskten okuduktan sonra kendi tanımlanmış veri tipiniz olarak yayınlayabilirsiniz. Dolayısıyla, nesnelerin bayt dizisinden farklı bir şey olduğunu söyleyemezsiniz.
    2016-02-11 23: 00: 41Z

İşte String - Byte[] arasındaki güvensiz uygulamam:

 
public static unsafe Byte[] GetBytes(String s)
{
    Int32 length = s.Length * sizeof(Char);
    Byte[] bytes = new Byte[length];

    fixed (Char* pInput = s)
    fixed (Byte* pBytes = bytes)
    {
        Byte* source = (Byte*)pInput;
        Byte* destination = pBytes;

        if (length >= 16)
        {
            do
            {
                *((Int64*)destination) = *((Int64*)source);
                *((Int64*)(destination + 8)) = *((Int64*)(source + 8));

                source += 16;
                destination += 16;
            }
            while ((length -= 16) >= 16);
        }

        if (length > 0)
        {
            if ((length & 8) != 0)
            {
                *((Int64*)destination) = *((Int64*)source);

                source += 8;
                destination += 8;
            }

            if ((length & 4) != 0)
            {
                *((Int32*)destination) = *((Int32*)source);

                source += 4;
                destination += 4;
            }

            if ((length & 2) != 0)
            {
                *((Int16*)destination) = *((Int16*)source);

                source += 2;
                destination += 2;
            }

            if ((length & 1) != 0)
            {
                ++source;
                ++destination;

                destination[0] = source[0];
            }
        }
    }

    return bytes;
}

Eskisi kadar zarif olmasa bile, kabul edilen ananınkinden çok daha hızlı. İşte 10000000'den fazla yineleme içeren Kronometre kriterlerim:

 
[Second String: Length 20]
Buffer.BlockCopy: 746ms
Unsafe: 557ms

[Second String: Length 50]
Buffer.BlockCopy: 861ms
Unsafe: 753ms

[Third String: Length 100]
Buffer.BlockCopy: 1250ms
Unsafe: 1063ms

Kullanmak için, proje oluşturma özelliklerinde "Güvensiz Kodlara İzin Ver" seçeneğini işaretlemelisiniz. .NET Framework 3.5'e göre, bu yöntem String uzantısı olarak da kullanılabilir:

 
public static unsafe class StringExtensions
{
    public static Byte[] ToByteArray(this String s)
    {
        // Method Code
    }
}
    
4
2016-08-12 18: 38: 24Z
  1. RuntimeHelpers.OffsetToStringData'un değeri .NET'in Itanium sürümlerinde 8'in katı mı? Çünkü aksi halde bu, hizalanmamış okumalar nedeniyle başarısız olur.
    2014-01-06 14: 09: 00Z
  2. memcpy'u çağırmak daha kolay olmaz mıydı? stackoverflow.com/a/27124232/659190
    2014-11-25 10: 33: 45Z

Bir dizgenin altındaki baytlarının gerçekten bir kopyasını istiyorsanız, izleyen gibi bir işlevi kullanabilirsiniz. Ancak, olmamalısınız lütfen nedenini öğrenmek için okumaya devam edin.

 
[DllImport(
        "msvcrt.dll",
        EntryPoint = "memcpy",
        CallingConvention = CallingConvention.Cdecl,
        SetLastError = false)]
private static extern unsafe void* UnsafeMemoryCopy(
    void* destination,
    void* source,
    uint count);

public static byte[] GetUnderlyingBytes(string source)
{
    var length = source.Length * sizeof(char);
    var result = new byte[length];
    unsafe
    {
        fixed (char* firstSourceChar = source)
        fixed (byte* firstDestination = result)
        {
            var firstSource = (byte*)firstSourceChar;
            UnsafeMemoryCopy(
                firstDestination,
                firstSource,
                (uint)length);
        }
    }

    return result;
}

Bu işlev, dizenizin altındaki baytların bir kopyasını oldukça hızlı bir şekilde alır. Bu baytları, sisteminizde hangi şekilde kodladıklarını alırsınız. Bu kodlama neredeyse kesinlikle UTF-16LE'dir ancak bu, dikkat etmeniz gerekmeyen bir uygulama detayıdır.

Yalnızca aramak için daha güvenli, daha basit ve daha güvenilir olur,

 
System.Text.Encoding.Unicode.GetBytes()

Herhalde, bu aynı sonucu verecektir, yazması daha kolaydır ve baytlar her zaman bir çağrı ile arayarak

 
System.Text.Encoding.Unicode.GetString()
    
3
2014-11-25 10: 29: 12Z

Basitçe şunu kullanın:

 
byte[] myByte= System.Text.ASCIIEncoding.Default.GetBytes(myString);
    
3
2015-07-01 01: 14: 44Z
  1. ... ve 127'den daha büyük bir atlama başlığına sahip olan tüm karakterleri kaybedersiniz. System.Text.ASCIIEncoding.Default.GetBytes("Árvíztűrő tükörfúrógép.").ToString();, alınamayan "Árvizturo tukörfurogép." kaybedilen bilgiyi geri verecektir. (Asya dillerinden henüz bahsetmedim.tüm karakterleri kaybedersin.)
    2018-01-11 15: 09: 12Z

İki yol:

 
public static byte[] StrToByteArray(this string s)
{
    List<byte> value = new List<byte>();
    foreach (char c in s.ToCharArray())
        value.Add(c.ToByte());
    return value.ToArray();
}

 
public static byte[] StrToByteArray(this string s)
{
    s = s.Replace(" ", string.Empty);
    byte[] buffer = new byte[s.Length / 2];
    for (int i = 0; i < s.Length; i += 2)
        buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
    return buffer;
}

En alttan bir tanesini daha sık kullanmaya meyilliyim, hız için kıyaslamadım.

    
2
2009-02-19 21: 03: 34Z
  1. Çok baytlı karakterler ne olacak?
    2009-02-23 09: 57: 52Z
  2. c.ToByte () özel: S
    2011-06-20 08: 41: 54Z
  3. @ AgnelKurian Msdn diyor "Bu yöntem, kendisine iletilen Char nesnesinin sayısal kodunu gösteren işaretsiz bir bayt değeri döndürür. .NET Framework'te bir Char nesnesi 16-bit Bu, yöntemin ASCII karakter aralığındaki veya Unicode C0 Kontrolleri ve Temel Latince ve C1 Kontrolleri ve Latin-1 Ek aralıkları içindeki U + 0000 ila U + 00FF arasındaki karakterlerin sayısal kodlarını döndürmek için uygun olduğu anlamına gelir. "
    2018-01-11 11: 30: 25Z
 
bytes[] buffer = UnicodeEncoding.UTF8.GetBytes(string something); //for converting to UTF then get its bytes

bytes[] buffer = ASCIIEncoding.ASCII.GetBytes(string something); //for converting to ascii then get its bytes
    
2
2012-01-02 11: 07: 00Z

LINQ içeren basit kod

 
string s = "abc"
byte[] b = s.Select(e => (byte)e).ToArray();

EDIT: aşağıda yorumlandığı gibi, iyi bir yol değil.

ancak LINQ’u daha uygun bir kodlamayla anlamak için yine de kullanabilirsiniz:

 
string s = "abc"
byte[] b = s.Cast<byte>().ToArray();
    
2
2013-12-18 10: 13: 26Z
  1. en hızlı olsa bile, neredeyse daha hızlı . Bu kesinlikle ilginç bir alternatif, ancak aslında çok daha hızlı olan Encoding.Default.GetBytes(s) ile aynı. Hızlı test, Encoding.Default.GetBytes(s)'un en az% 79 daha hızlı performans gösterdiğini gösteriyor. YMMV.
    2013-10-25 04: 36: 21Z
  2. ile deneyin. Bu kod kilitlenmeyecek, ancak yanlış bir sonuç (ki daha da kötü) döndürecek. Farkı görmek için short yerine byte’a yayın yapmayı deneyin.
    2013-12-18 08: 57: 07Z

Aşağıdaki gerçek nedeniyle dize, birkaç farklı yolla bayt dizisine dönüştürülebilir: .NET, Unicode'u destekler ve Unicode, UTF olarak adlandırılan birkaç fark kodlamasını standart hale getirir. Farklı uzunluklarda bayt temsilleri vardır ancak bu, bir dize kodlandığında, dizeye geri kodlanabileceği anlamına gelir, ancak dize bir UTF ile kodlanmışsa ve vidalanabiliyorsa, farklı UTF varsayımına göre kodlanmışsa yukarı.

Ayrıca, .NET, Unicode olmayan kodlamaları da destekler, ancak genel durumda geçerli değildir (yalnızca ASCII gibi gerçek bir dizede sınırlı bir Unicode kod noktası alt kümesi kullanıldığında geçerli olacaktır). Dahili olarak, .NET UTF-16'yı destekler, ancak akış gösterimi için UTF-8 genellikle kullanılır. Aynı zamanda İnternet için standart bir yöntemdir.

Şaşırtıcı olmayan bir şekilde, dizginin bir bayt dizisine seri hale getirilmesi ve seriyi kaldırma, soyut bir sınıf olan System.Text.Encoding sınıfı tarafından desteklenir; türetilmiş sınıfları somut kodlamaları destekler: ASCIIEncoding ve dört UTF (System.Text.UnicodeEncoding UTF-16'yı destekler)

Ref bu bağlantıyı tıklayın.

System.Text.Encoding.GetBytes kullanarak bir bayt dizisine serileştirme için. Fveya ters işlem System.Text.Encoding.GetChars'u kullanır. Bu işlev bir karakter dizisi döndürür, bu nedenle bir dize elde etmek için System.String(char[]) dize yapıcısını kullanın.
Bu sayfayı refere et.

Örnek:

 
string myString = //... some string

System.Text.Encoding encoding = System.Text.Encoding.UTF8; //or some other, but prefer some UTF is Unicode is used
byte[] bytes = encoding.GetBytes(myString);

//next lines are written in response to a follow-up questions:

myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);
myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);

//how many times shall I repeat it to show there is a round-trip? :-)
    
2
2017-08-17 07: 33: 04Z

Bu, baytların ne istediğine bağlıdır.

Bunun nedeni Tyler’ın çok uygun bir şekilde dediği gibi , "Dizeler saf veri değildir. ayrıca bilgilere sahip. " Bu durumda, bilgi dize oluşturulduğunda varsayılan bir kodlamadır.

Bir dizede depolanan ikili verilerinizin (metin yerine) olduğunu varsayarsak

Bu, OP'nin kendi sorusu hakkındaki yorumuna dayanır ve OP'nin kullanımdaki ipuçlarını anlarsam doğru sorudur.

İkili verileri dizelerde saklamak, yukarıda bahsedilen kodlamanın üstesinden gelmesi nedeniyle muhtemelen yanlış bir yaklaşımdır! Bu ikili verileri string'da depolayan herhangi bir program veya kütüphane (daha uygun olan byte[] dizisi yerine) çoktan başlamadan savaşı kaybetti bile. Baytları size bir REST isteğinde /yanıtında veya olması gereken herhangi bir dizede gönderiyorlarsa, Base64 doğru yaklaşım olacaktır.

Bilinmeyen kodlamaya sahip bir metin dizeniz varsa

Bu yanlış soruyu başka herkes yanlış cevapladı.

Dize olduğu gibi iyi görünüyorsa, yalnızca bir kodlama seçin (tercihen UTF ile başlayan), ilgili System.Text.Encoding.???.GetBytes() işlevini kullanın ve seçtiğiniz kodlamayı baytlara kime verdiğinizi söyleyin.

    
2
2017-11-08 19: 15: 47Z
kaynak yerleştirildi İşte