大量のstring
データを転送するには、[100]byte
を読む必要があります。
すべてのstring
の長さが正確に100文字ではないため、byte array
の残りの部分には0
が埋め込まれます。
[100]byte
をstring(byteArray[:])
でstring
に変換すると、末尾の0
は^@^@
sとして表示されます。
Cではstring
は0
で終わるので、Golangでbyte array
をstring
にスマートに転送するための最善の方法は何でしょうか。
データをバイトスライスに読み込むメソッドは、読み込んだバイト数を返します。その番号を保存してから、それを使って文字列を作成してください。 n
は読み込んだバイト数なので、コードは次のようになります。
s := string(byteArray[:n])
何らかの理由でn
がない場合は、入力にnull文字が含まれていないと想定して、bytesパッケージを使用してそれを見つけることができます。
n := bytes.Index(byteArray, []byte{0})
またはiczaが指摘したように、あなたは以下のコードを使うことができます:
n := bytes.IndexByte(byteArray, 0)
どうですか?
s := string(byteArray[:])
単純な解決策:
str := fmt.Sprintf("%s", byteArray)
私はこれがどれほどパフォーマンスがよいかわからない。
例えば、
package main
import "fmt"
func CToGoString(c []byte) string {
n := -1
for i, b := range c {
if b == 0 {
break
}
n = i
}
return string(c[:n+1])
}
func main() {
c := [100]byte{'a', 'b', 'c'}
fmt.Println("C: ", len(c), c[:4])
g := CToGoString(c[:])
fmt.Println("Go:", len(g), g)
}
出力:
C: 100 [97 98 99 0]
Go: 3 abc
次のコードは '\ 0'を探していて、質問の仮定の下では、すべての '\ 0'がすべての '\ 0'に先行するため、配列はソート済みと見なすことができます。配列がデータ内に '\ 0'を含むことができる場合、この仮定は成り立ちません。
二分探索を使用して最初のゼロバイトの位置を見つけ、次にスライスします。
あなたはこのようなゼロバイトを見つけることができます:
package main
import "fmt"
func FirstZero(b []byte) int {
min, max := 0, len(b)
for {
if min + 1 == max { return max }
mid := (min + max) / 2
if b[mid] == '\000' {
max = mid
} else {
min = mid
}
}
return len(b)
}
func main() {
b := []byte{1, 2, 3, 0, 0, 0}
fmt.Println(FirstZero(b))
}
特にほとんどの文字列が短い場合は、単純にバイト配列をスキャンしてゼロバイトを探す方が速い場合があります。
配列内のnil以外のバイトの正確な長さがわからない場合は、まずそれをトリミングできます。
文字列(bytes.Trim(arr、 "\ x00"))
パフォーマンスチューニングにのみ使用します。
package main
import (
"fmt"
"reflect"
"unsafe"
)
func BytesToString(b []byte) string {
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
sh := reflect.StringHeader{bh.Data, bh.Len}
return *(*string)(unsafe.Pointer(&sh))
}
func StringToBytes(s string) []byte {
sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
bh := reflect.SliceHeader{sh.Data, sh.Len, 0}
return *(*[]byte)(unsafe.Pointer(&bh))
}
func main() {
b := []byte{'b', 'y', 't', 'e'}
s := BytesToString(b)
fmt.Println(s)
b = StringToBytes(s)
fmt.Println(string(b))
}
どうしてこれじゃないの?
bytes.NewBuffer(byteArray).String()
私はパニックになったいくつかの方法を数回試しました:
実行時エラー:スライスは範囲外です。
しかし、これはついにうまくいきました。
string(Data[:])
読み取りには配列の代わりにスライスを使用してください。例えば io.Reader
は配列ではなくスライスを受け入れます。
ゼロパディングの代わりにスライスを使用してください。
例:
buf := make([]byte, 100)
n, err := myReader.Read(buf)
if n == 0 && err != nil {
log.Fatal(err)
}
consume(buf[:n]) // consume will see exact (not padded) slice of read data