C#で文字列をバイト配列に変換する


670

VBからC#に変換しています。このステートメントの構文に問題があります:

if ((searchResult.Properties["user"].Count > 0))
{
    profile.User = System.Text.Encoding.UTF8.GetString(searchResult.Properties["user"][0]);
}

次に、次のエラーが表示されます。

引数1: 'object'から 'byte []'に変換できません

'System.Text.Encoding.GetString(byte [])'に最適なオーバーロードメソッドの一致には、無効な引数がいくつかあります

この投稿に基づいてコードを修正しようとしましたが、まだ成功しません

string User = Encoding.UTF8.GetString("user", 0);

助言がありますか?


1
タイプはsearchResult.Properties["user"][0]何ですか?byte[]最初にキャストしてみてください
mshsayem 2013

mshsayemは私が行くところに行きました。(byte[])searchResultのa へのキャストがありませんか?
ハリソン

2
あなたProperties["user"][0]はタイプが何であるかを知る必要があります。それがバイト配列であると確信している場合は、次のようにキャストできますprofile.User = System.Text.Encoding.UTF8.GetString((byte[])searchResult.Properties["user"][0]);
keyboardP

1
そんなに大騒ぎする必要はないことがわかりました。結局のところ、ユーザー名はエンコードせずにフェッチできます。
nouptime

3
なぜあなたは本当の答えを選択しないのですか?
Ali

回答:


1189

すでにバイト配列がある場合は、そのバイト配列にするために使用されたエンコーディングのタイプを知る必要があります。

たとえば、バイト配列が次のように作成された場合:

byte[] bytes = Encoding.ASCII.GetBytes(someString);

次のような文字列に戻す必要があります。

string someString = Encoding.ASCII.GetString(bytes);

継承したコード、バイト配列の作成に使用されたエンコーディングが見つかれば、設定する必要があります。


3
ティモシー、VBコードを調べましたが、あなたが言ったようにバイト配列を見つけることができません。
nouptime

検索結果で、Propertiesプロパティのタイプは何ですか?
ティモシーランドール

プロパティに文字列としてアタッチされているアイテムがいくつかあることだけがわかります。それがあなたが私に尋ねていたのかどうかはわかりません。
nouptime 2013

16
@AndiARはEncoding.UTF8.GetBytes(somestring)を試します
OzBob

1
私の状況では、Encoding.Unicode.GetBytesが機能することがわかりました(ただし、ASCIIは機能しませんでした)
Jeff

106

まず、System.Text名前空間を追加します

using System.Text;

次に、このコードを使用します

string input = "some text"; 
byte[] array = Encoding.ASCII.GetBytes(input);

修正したいです!


42

また、拡張メソッドを使用して、string次のようにメソッドをタイプに追加できます。

static class Helper
{
   public static byte[] ToByteArray(this string str)
   {
      return System.Text.Encoding.ASCII.GetBytes(str);
   }
}

そして、以下のように使用してください:

string foo = "bla bla";
byte[] result = foo.ToByteArray();

12
このメソッドの名前を変更して、ASCIIエンコーディングを使用しているという事実を含めます。のようなものToASCIIByteArray。私が使用しているライブラリがASCIIを使用していることがわかり、UTF-8またはそれよりも新しいものを使用していると想定しています。
Tブランク

30
var result = System.Text.Encoding.Unicode.GetBytes(text);

3
他の回答がASCIIを示唆しているため、これは受け入れられる回答であるはずですが、エンコーディングはUnicode(UTF16)またはUTF8のいずれかです。
アベル

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

これは、サロゲートペアの範囲に含まれる文字の場合は失敗します。GetBytesには、サロゲートペアごとに1つの通常の文字が最後から欠落しているバイト配列があります。GetStringの最後には空の文字があります。これが機能する唯一の方法は、MicrosoftのデフォルトがUTF32である場合、またはサロゲートペアの範囲内の文字が許可されていない場合です。それとも私が見ないものはありますか?適切な方法は、文字列をバイトに「エンコード」することです。
Gerard ONeill 2017

正解です。より広い範囲では、#Timothy Randallのソリューションに似たものを使用できます。System.Textを使用します。名前空間の例{public class Program {public static void Main(string [] args){string s1 = "Hello World"; 文字列s2 = "שלוםעולם"; string s3 = "你好、世界!"; Console.WriteLine(Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(s1))); Console.WriteLine(Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(s2))); Console.WriteLine(Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(s3))); }}}
エランヨゲフ2017

17

Encoding.Defaultを使用すべきでない理由...

@Randallの答えはを使用していEncoding.Defaultますが Microsoftはそれに対する警告を出します

異なるコンピュータはデフォルトとして異なるエンコーディングを使用でき、デフォルトのエンコーディングは単一のコンピュータで変更できます。既定のエンコードを使用して、コンピューター間でストリーミングされたデータ、または同じコンピューターで異なる時間に取得されたデータをエンコードおよびデコードすると、そのデータが正しく変換されない場合があります。さらに、Defaultプロパティによって返されるエンコーディングは、最適なフォールバックを使用して、サポートされていない文字をコードページでサポートされている文字にマップします。これらの理由により、デフォルトのエンコーディングを使用することは推奨されません。エンコードされたバイトが適切にデコードされるようにするには、UTF8EncodingやUnicodeEncodingなどのUnicodeエンコーディングを使用する必要があります。より高いレベルのプロトコルを使用して、同じ形式がエンコードとデコードに使用されるようにすることもできます。

デフォルトのエンコーディングが何であるかを確認するには、Encoding.Default.WindowsCodePage(私の場合は1250-悲しいことに、CP1250エンコーディングの事前定義されたクラスはありませんが、オブジェクトは次のように取得できます。Encoding.GetEncoding(1250)

Encoding.ASCII 7ビットなので、私の場合も機能しません:

byte[] pass = Encoding.ASCII.GetBytes("šarže");
Console.WriteLine(Encoding.ASCII.GetString(pass)); // ?ar?e

...そして代わりにUTF-8エンコーディングを使用する理由...

デフォルトのエンコーディングは誤解を招く:.NETは実際のデフォルトとしてあらゆる場所でUTF-8を使用します(8ビットエンコーディングは20世紀の終わりまでに廃止されました。 Console.OutputEncoding.EncodingName *を)コードで定義するすべての定数はデフォルトでUTF-8でエンコードされています。データソースが異なるエンコーディングでない限り、これを使用する必要があります。

*これは私の場合、UTF-8であり、これは直接の嘘です。 chcpコンソール(cmd)から852が返されます。ローカライズされたシステムコマンド(pingなど)でこのコードページがハードコーディングされているため、これは変更しないでください

Microsoftの推奨に従います。

var utf8 = new UTF8Encoding();
byte[] pass = utf8.GetBytes("šarže");
Console.WriteLine(utf8.GetString(pass)); // šarže

Encoding.UTF8 他の人が推奨するのは、インスタンスuf UTF-8エンコーディングであり、直接使用することも、

var utf8 = Encoding.UTF8 as UTF8Encoding;

...しかし、常に使用されるわけではありません

バイト配列のエンコーディングは、西欧諸国のUnicodeで「正常に機能する」はずですが、プログラムをサポートされていない地域(ここでは東ヨーロッパのような)に移動するとすぐに、混乱を招きます。チェコ共和国では、Windowsのデフォルトが使用されます(2020年に!)コンソールのMS非標準852(別名Latin-2)、1250のWindows OEM、UTF-8(65001)の.NET(およびその他)の新しいデフォルト、および一部の西欧8ビットデータは1252のままですが、東ヨーロッパの古い8ビット西部標準はISO-8859-2(別名Latin-2ですが、852と同じLatin-2ではありません)でした。ASCIIを使用すると、豆腐と「?」でいっぱいのテキストを意味します ここに。21世紀の半ばまでは、明示的に UTF-8を設定してください。


12

オフの構築アリの答え、私はあなたが、必要に応じて使用したい符号化する際に通過することを可能にする拡張メソッドをお勧めします:

using System.Text;
public static class StringExtensions
{
    /// <summary>
    /// Creates a byte array from the string, using the 
    /// System.Text.Encoding.Default encoding unless another is specified.
    /// </summary>
    public static byte[] ToByteArray(this string str, Encoding encoding = Encoding.Default)
    {
        return encoding.GetBytes(str);
    }
}

そして、以下のように使用してください:

string foo = "bla bla";

// default encoding
byte[] default = foo.ToByteArray();

// custom encoding
byte[] unicode = foo.ToByteArray(Encoding.Unicode);

2
なお、使用してEncoding encoding = Encoding.Defaultコンパイル時のエラーで結果を:CS1736 Default parameter value for 'encoding' must be a compile-time constant
ダグラスガスケル

11

次のアプローチは、文字が1バイトの場合にのみ機能します。(デフォルトのユニコードは2バイトなので機能しません)

public static byte[] ToByteArray(string value)
{            
    char[] charArr = value.ToCharArray();
    byte[] bytes = new byte[charArr.Length];
    for (int i = 0; i < charArr.Length; i++)
    {
        byte current = Convert.ToByte(charArr[i]);
        bytes[i] = current;
    }

    return bytes;
}

シンプルに保つ


charそして、string定義によるUTF-16です。
Tom Blodget 2016年

はい、デフォルトはUTF-16です。入力文字列のエンコーディングについては何も想定していません。
Mandar Sudame 2016年

テキストはありませんが、エンコードされたテキストです。入力はタイプstringであるため、UTF-16です。UTF-16はデフォルトではありません。それについての選択肢はありません。次にchar[]、UTF-16コード単位に分割します。次にConvert.ToByte(Char)を呼び出します。これは、たまたまU + 0000をU + 00FFからISO-8859-1変換し、他のコードポイント
Tom Blodget 2016年

理にかなっています。説明をありがとう。回答を更新しています。
Mandar Sudame 16年

1
まだいくつかの重要な点が欠けていると思います。char16ビットであることとConvert.ToByte()、それらの半分を捨てることに焦点を当てます。
トムブロジェット


6

JustinStolleの編集の改良(Eran YogevによるBlockCopyの使用)。

提案されたソリューションは、実際にエンコーディングを使用するよりも高速です。問題は、長さが不均一なバイト配列のエンコードでは機能しないことです。与えられたように、それは範囲外の例外を発生させます。文字列からデコードするとき、長さを1増やすと、後続のバイトが残ります。

私にとって、からにエンコードしたいときに必要になりましDataTableJSON。バイナリフィールドを文字列にエンコードし、文字列からにデコードする方法を探していましたbyte[]

したがって、2つのクラスを作成しました。1つは上記のソリューションをラップするクラス(文字列からエンコードする場合は長さが常に均一であるため問題ありません)ともう1つはbyte[]エンコードを処理するクラスです。

バイナリ配列の元の長さが奇数( '1')であるか偶数( '0')であるかを通知する単一の文字を追加することにより、不均一な長さの問題を解決しました

次のように:

public static class StringEncoder
{
    static byte[] EncodeToBytes(string str)
    {
        byte[] bytes = new byte[str.Length * sizeof(char)];
        System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
        return bytes;
    }
    static string DecodeToString(byte[] bytes)
    {
        char[] chars = new char[bytes.Length / sizeof(char)];
        System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
        return new string(chars);
    }
}

public static class BytesEncoder
{
    public static string EncodeToString(byte[] bytes)
    {
        bool even = (bytes.Length % 2 == 0);
        char[] chars = new char[1 + bytes.Length / sizeof(char) + (even ? 0 : 1)];
        chars[0] = (even ? '0' : '1');
        System.Buffer.BlockCopy(bytes, 0, chars, 2, bytes.Length);

        return new string(chars);
    }
    public static byte[] DecodeToBytes(string str)
    {
        bool even = str[0] == '0';
        byte[] bytes = new byte[(str.Length - 1) * sizeof(char) + (even ? 0 : -1)];
        char[] chars = str.ToCharArray();
        System.Buffer.BlockCopy(chars, 2, bytes, 0, bytes.Length);

        return bytes;
    }
}

4

この質問は何度も十分に回答されていますが、C#7.2とSpan型の導入により、安全でないコードでこれを行うためのより速い方法があります。

public static class StringSupport
{
    private static readonly int _charSize = sizeof(char);

    public static unsafe byte[] GetBytes(string str)
    {
        if (str == null) throw new ArgumentNullException(nameof(str));
        if (str.Length == 0) return new byte[0];

        fixed (char* p = str)
        {
            return new Span<byte>(p, str.Length * _charSize).ToArray();
        }
    }

    public static unsafe string GetString(byte[] bytes)
    {
        if (bytes == null) throw new ArgumentNullException(nameof(bytes));
        if (bytes.Length % _charSize != 0) throw new ArgumentException($"Invalid {nameof(bytes)} length");
        if (bytes.Length == 0) return string.Empty;

        fixed (byte* p = bytes)
        {
            return new string(new Span<char>(p, bytes.Length / _charSize));
        }
    }
}

バイトはUTF-16でエンコードされた文字列(C#ランドでは「Unicode」と呼ばれます)を表すことに注意してください。

いくつかのクイックベンチマークは、上記のメソッドが中サイズの文字列(30-50文字)のEncoding.Unicode.GetBytes(...)/ GetString(...)実装よりも約5倍高速であり、大きな文字列の場合はさらに高速であることを示しています。これらのメソッドは、Marshal.Copy(..)またはBuffer.MemoryCopy(...)でポインターを使用するよりも高速であるように見えます。


4

'searchResult.Properties ["user"] [0]'の結果が文字列の場合:

if ( ( searchResult.Properties [ "user" ].Count > 0 ) ) {

   profile.User = System.Text.Encoding.UTF8.GetString ( searchResult.Properties [ "user" ] [ 0 ].ToCharArray ().Select ( character => ( byte ) character ).ToArray () );

}

文字列をバイト[]に変換するには、LINQを使用して実行できるという重要なポイントがあります。

.ToCharArray ().Select ( character => ( byte ) character ).ToArray () )

そしてその逆:

.Select ( character => ( char ) character ).ToArray () )

3

これを行わない理由が誰かにわかりますか?

mystring.Select(Convert.ToByte).ToArray()

10
Convert.ToByte(char)思ったように動作しません。文字'2'2、文字を表すバイトではなく、バイトに変換されます'2'mystring.Select(x => (byte)x).ToArray()代わりに使用してください。
ジャック


2

MemoryMarshal APIを使用して、非常に高速で効率的な変換を実行できます。String暗黙的にキャストされるReadOnlySpan<byte>ように、MemoryMarshal.Castどちらか受け入れるSpan<byte>か、ReadOnlySpan<byte>入力パラメータとして。

public static class StringExtensions
{
    public static byte[] ToByteArray(this string s) => s.ToByteSpan().ToArray(); //  heap allocation, use only when you cannot operate on spans
    public static ReadOnlySpan<byte> ToByteSpan(this string s) => MemoryMarshal.Cast<char, byte>(s);
}

次のベンチマークは違いを示しています:

Input: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,"

|                       Method |       Mean |     Error |    StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|----------------------------- |-----------:|----------:|----------:|-------:|------:|------:|----------:|
| UsingEncodingUnicodeGetBytes | 160.042 ns | 3.2864 ns | 6.4099 ns | 0.0780 |     - |     - |     328 B |
| UsingMemoryMarshalAndToArray |  31.977 ns | 0.7177 ns | 1.5753 ns | 0.0781 |     - |     - |     328 B |
|           UsingMemoryMarshal |   1.027 ns | 0.0565 ns | 0.1630 ns |      - |     - |     - |         - |

0

この作業は私にとっては、変換後、自分の写真をデータベースのbyteaフィールドに入れることができました。

using (MemoryStream s = new MemoryStream(DirEntry.Properties["thumbnailphoto"].Value as byte[]))
{
    return s.ToArray();
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.