Answers:
将数据读取到字节片中的方法返回读取的字节数。您应该保存该数字,然后使用它创建字符串。如果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)
关于什么?
s := string(byteArray[:])
string(byteArray[:])
包含^@
字符
string(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))
}
仅天真地扫描字节数组以查找零字节可能会更快,尤其是在大多数字符串较短的情况下。
[]byte{0}
。在这种情况下,FirstZero()
应返回,0
这样切片结果将是""
,但相反,它将返回1
并在中切片结果"\x00"
。
为什么不呢?
bytes.NewBuffer(byteArray).String()
byteArray[:]
,因为bytes.NewBuffer
需要[]byte
; b)这个问题说数组有尾随的零,您不会处理;c)如果您的变量是[]byte
(行的唯一编译方式),那么您的行只是一种缓慢的方式string(v)
。
仅用于性能调整。
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))
}
string
可能会对以后的字节片产生严重影响。string
Go中的值被定义为不可变的,整个Go运行时和库都基于此值。如果您走这条路,您将自己传送到最神秘的错误和运行时错误的中间。
使用切片而不是数组进行读取。例如,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
s := a[:n]
或s := string(a[:n])
如果需要字符串来对字节数组进行切片。如果n
不能直接获得,则必须对其进行计算,例如,按照丹尼尔的建议,在缓冲区(数组)中查找特定/零字节。
我几次尝试过几次惊慌失措的方法:
运行时错误:切片范围超出范围。
但这终于奏效了。
string(Data[:])
尽管性能不是很好,但是唯一可读的解决方案是
//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)
}
具有不包含null的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)
}
这将分配一个字节的片。因此,如果频繁使用或反复使用,请留意性能。
这是将字节数组压缩为字符串的代码
package main
import (
"fmt"
)
func main() {
byteArr := [100]byte{'b', 'y', 't', 'e', 's'}
firstHalf := ToString(byteArr)
fmt.Println("Bytes to str", string(firstHalf))
}
func ToString(byteArr [100]byte) []byte {
arrLen := len(byteArr)
firstHalf := byteArr[:arrLen/2]
secHalf := byteArr[arrLen/2:]
for {
// if the first element is 0 in secondHalf discard second half
if len(secHalf) != 0 && secHalf[0] == 0 {
arrLen = len(firstHalf)
secHalf = firstHalf[arrLen/2:]
firstHalf = firstHalf[:arrLen/2]
continue
} else {
for idx := 0; len(secHalf) > idx && secHalf[idx] != 0; idx++ {
firstHalf = append(firstHalf, secHalf[idx])
}
}
break
}
return firstHalf
}
这是更快的方法:
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
fmt
更快)。fmt.Printf("%s", bytes)
string(bytes)
我什么时候有递归的解决方案。
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, ""))
}
fmt.Println(CToGoString([]byte("ctogo\x00\x00"), "") == "ctogo")
应该打印true
,然后打印false
。
[100]byte
而是a []byte
,也不会剥离'\x00'
字节。与接受答案的速度相比,其速度(取决于输入)要慢多个数量级。
^@
上没有显示,但是如果您在终端或类似的地方进行测试,它会一直在那儿。这样做的原因是,Go在找到0时不会停止将bytes数组转换为字符串。len(string(bytes))
在您的示例中为5而不是1。这取决于输出函数,即是否完整打印了字符串(带有零)或不。