537

我需要阅读[100]byte以传输一堆string数据。

因为不是所有的strings 都正好是 100 个字符长,所以剩下的部分byte array0s 填充。

如果我转换[100]bytestringby: string(byteArray[:]),尾随0s 显示为^@^@s。

在 C 中,string将终止于0,那么在 Go 中将其转换byte array为的最佳方法是什么?string

4

11 回答 11

546

将数据读入字节片的方法返回读取的字节数。您应该保存该号码,然后使用它来创建您的字符串。如果n是读取的字节数,您的代码将如下所示:

s := string(byteArray[:n])

要转换完整的字符串,可以使用:

s := string(byteArray[:len(byteArray)])

这相当于:

s := string(byteArray[:])

如果由于某种原因你不知道n,你可以使用bytes包来找到它,假设你的输入没有嵌入空字符。

n := bytes.Index(byteArray[:], []byte{0})

或者正如 icza 指出的那样,您可以使用以下代码:

n := bytes.IndexByte(byteArray[:], 0)
于 2013-01-09T07:24:38.720 回答
375

采用:

s := string(byteArray[:])
于 2013-09-04T13:52:33.707 回答
67

简单的解决方案:

str := fmt.Sprintf("%s", byteArray)

不过,我不确定它的性能如何。

于 2016-11-02T08:57:14.133 回答
16

例如,

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
于 2013-01-09T15:30:00.473 回答
7

以下代码正在寻找'\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))
}

天真地扫描字节数组以查找零字节可能会更快,尤其是在您的大多数字符串都很短的情况下。

于 2013-01-09T22:56:42.463 回答
2

当您不知道数组中非零字节的确切长度时,您可以先对其进行修剪:

字符串(字节。修剪(arr,“\x00”))

于 2018-03-21T07:02:23.147 回答
0

仅用于性能调整。

package main

import (
    "fmt"
    "reflect"
    "unsafe"
)

func BytesToString(b []byte) string {
    return *(*string)(unsafe.Pointer(&b))
}

func StringToBytes(s string) []byte {
    return *(*[]byte)(unsafe.Pointer(&s))
}

func main() {
    b := []byte{'b', 'y', 't', 'e'}
    s := BytesToString(b)
    fmt.Println(s)
    b = StringToBytes(s)
    fmt.Println(string(b))
}
于 2014-12-23T05:46:40.893 回答
0

用这个:

bytes.NewBuffer(byteArray).String()
于 2015-06-26T17:47:23.453 回答
0

虽然不是非常高效,但唯一可读的解决方案是:

  // Split by separator and pick the first one.
  // This has all the characters till null, excluding null itself.
  retByteArray := bytes.Split(byteArray[:], []byte{0}) [0]

  // OR

  // If you want a true C-like string, including the null character
  retByteArray := bytes.SplitAfter(byteArray[:], []byte{0}) [0]

具有 C 样式字节数组的完整示例:

package main

import (
    "bytes"
    "fmt"
)

func main() {
    var byteArray = [6]byte{97,98,0,100,0,99}

    cStyleString := bytes.SplitAfter(byteArray[:], []byte{0}) [0]
    fmt.Println(cStyleString)
}

具有不包括空值的 Go 样式字符串的完整示例:

package main

import (
    "bytes"
    "fmt"
)

func main() {
    var byteArray = [6]byte{97, 98, 0, 100, 0, 99}

    goStyleString := string(bytes.Split(byteArray[:], []byte{0}) [0])
    fmt.Println(goStyleString)
}

这分配了一片字节片。因此,如果大量或重复使用它,请注意性能。

于 2019-11-30T16:31:03.750 回答
-1
  • 使用切片而不是数组进行读取。例如,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 an exact (not padded) slice of read data
于 2013-01-09T07:33:15.360 回答
-1

这是一个删除空字节的选项:

package main
import "golang.org/x/sys/windows"

func main() {
   b := []byte{'M', 'a', 'r', 'c', 'h', 0}
   s := windows.ByteSliceToString(b)
   println(s == "March")
}
于 2021-03-12T21:12:52.967 回答