dongyao2022
dongyao2022
2013-01-09 07:19
浏览 82
已采纳

如何将零终止的字节数组转换为字符串?

I need to read [100]byte to transfer a bunch of string data.

Because not all of the strings are precisely 100 characters long, the remaining part of the byte array are padded with 0s.

If I tansfer [100]byte to string by: string(byteArray[:]), the tailing 0s are displayed as ^@^@s.

In C the string will terminate upon 0, so I wonder what's the best way of smartly transfer a byte array to string in Golang.

图片转代码服务由CSDN问答提供 功能建议

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

因为并非所有 string 的长度都恰好是100个字符,所以 byte数组的其余部分 0 s填充。

如果我通过以下方式将 [100] byte 转换为 string string(byteArray [:]),结尾的 0 s显示为 ^ @ ^ @ s。

在C中, string 将在 0 处终止,所以我想知道什么是将 byte数组聪明地传输到的最佳方法是什么 Golang中的字符串

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

12条回答 默认 最新

  • dongzhouhao4316
    dongzhouhao4316 2013-01-09 07:24
    已采纳

    methods that read data into byte slices return the number of bytes read. You should save that number and then use it to create your string. n being the number of bytes read, your code would look like this:

    s := string(byteArray[:n])
    

    If for some reason you don't have n, you could use the bytes package to find it, assuming your input doesn't have a null character in it.

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

    Or as icza pointed out, you can use the code below:

    n := bytes.IndexByte(byteArray, 0)
    
    点赞 评论
  • dongxixia6399
    dongxixia6399 2013-01-09 07:33
    • Use slices instead of arrays for reading. e.g. io.Reader accepts a slice, not an array.

    • Use slicing instead of zero padding.

    Example:

    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
    
    点赞 评论
  • dtrphb5597
    dtrphb5597 2013-01-09 15:30

    For example,

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

    Output:

    C:  100 [97 98 99 0]
    Go: 3 abc
    
    点赞 评论
  • douyan6958
    douyan6958 2013-01-09 22:56

    The following code is looking for '\0', and under the assumptions of the question the array can be considered sorted since all non-'\0' precede all '\0'. This assumption won't hold if the array can contain '\0' within the data.

    Find the location of the first zero-byte using a binary search, then slice.

    You can find the zero-byte like this:

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

    It may be faster just to naively scan the byte array looking for the zero-byte, especially if most of your strings are short.

    点赞 评论
  • drwo32555
    drwo32555 2013-06-06 02:03

    I when with a recursive solution.

    func CToGoString(c []byte, acc string) string {
    
        if len(c) == 0 {
            return acc
        } else {
            head := c[0]
            tail := c[1:]
            return CToGoString(tail, acc + fmt.Sprintf("%c", head))
        }
    }
    
    func main() {
        b := []byte{some char bytes}
        fmt.Println(CToGoString(b, ""))
    }
    
    点赞 评论
  • dsfo22654
    dsfo22654 2013-09-04 13:52

    What about?

    s := string(byteArray[:])
    
    点赞 评论
  • doufei8250
    doufei8250 2014-12-23 05:46

    Only use for performance tuning.

    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))
    }
    
    点赞 评论
  • douke3442
    douke3442 2015-06-26 17:47

    Why not this?

    bytes.NewBuffer(byteArray).String()
    
    点赞 评论
  • dsbm49845
    dsbm49845 2016-11-02 08:57

    Simplistic solution:

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

    I'm not sure how performant this is though.

    点赞 评论
  • douzhuo3233
    douzhuo3233 2018-03-21 07:02

    When you do not know the exact length of non-nil bytes in the array, you can trim it first:

    string(bytes.Trim(arr, "\x00"))

    点赞 评论
  • dongshike7171
    dongshike7171 2018-05-03 13:02

    I tried few methods few times I got panic:

    runtime error: slice bounds out of range.

    But this finally worked.

    string(Data[:])

    点赞 评论
  • dongtun1683
    dongtun1683 2018-10-28 23:19

    Here is the faster way:

    resp, _ := http.Get("https://www.something.com/something.xml")
    bytes, _ := ioutil.ReadAll(resp.Body)
    resp.Body.Close()
    fmt.Println(string(bytes)) //just convert with string() function
    
    点赞 评论

相关推荐