Преобразовать поток неподписанных байтов в подписанный поток потоков Голанг
Каков наилучший способ преобразования байтового потока в слайс байтового потока на Голанге? В настоящее время я пытаюсь реплицировать java-программу на golang, и я считаю, что у меня есть некоторые проблемы с тем фактом, что java читает байтпоток как значение со знаком, тогда как golang рассматривает его как значение без знака.
Когда я печатаю на заметке Java, отрицательные значения разные. Положительные одинаковы:
Джава:
8 |-8|-58| -61 | -56 | -113 | 42 | 16 | -64 | 2 | 24 | -16 | 1
Golang:
8 |248|198| 195 | 200 | 143 | 42 | 16 | 192 | 2 | 2 | 240 | 1
В настоящее время моя реализация прямо в GO выглядит так:
//open the file with os.open
//create new reader and unzip it
//reads from zip file and returns an array of bytes associated with it.
data, err := ioutil.ReadAll(fz)
if err != nil {
return nil, err
}
//reflect.TypeOf shows this is a []uint8
//I want this to be a []int8 (so signed).
В Java реализация была в значительной степени:
//create buffer reader
//create input stream
//create datainput stream
//use the .Read function to get the values required.
Я не видел простого способа быстро привести его к подписанному int (может быть, я ошибаюсь). Я мог бы попытаться перебрать весь срез, преобразовав каждое значение в подписанное int, но такой подход кажется довольно грязным. Это также потребовало бы, чтобы я воздействовал на каждого. Есть ли более чистый способ преобразования среза?
3 ответа
Ты можешь использовать unsafe.Pointer
если вы точно знаете , что делаете. Потому что, как следует из названия, это небезопасно. Поэтому он взорвется, если вы будете использовать его неразумно.
package main
import (
"fmt"
"unsafe"
)
func main() {
unsigned := make([]uint8, 0)
unsigned = append(unsigned, 128)
unsigned = append(unsigned, 255)
signed := *(*[]int8)(unsafe.Pointer(&unsigned))
fmt.Printf("%d : %d\n", signed[0], unsigned[0])
fmt.Printf("%d : %d\n", signed[1], unsigned[1])
}
// -128 : 128
// -1 : 255
Вы можете найти этот пример на игровой площадке Go
Некоторые вещи, которые нужно прояснить: и Java, и Go читают данные одинаково из файлов.
Файлы представляют собой серии двоичных данных, сгруппированных по 8 битам, которые мы называем байтом. Этот байт составляет 8 бит, как вы его интерпретируете, зависит только от вас.
И Go, и Java будут читать одни и те же 8-битные группы, но Java будет хранить их в Java. byte
тип, который является типом со знаком, и Go будет хранить его в Go byte
тип, который без знака. Но оба будут иметь одинаковые 8 бит, считанные данные будут равны:
var b byte = 248
var i int8 = -8
fmt.Printf("%x %x\n", b, byte(i))
Выход:
f8 f8
Если вам нужно интерпретировать прочитанные 8 бит как значение со знаком, просто используйте преобразование типа:
data := []byte{8, 248, 198}
for _, v := range data {
fmt.Println(int8(v))
}
Вывод (аналогично выводу Java):
8|-8|-58|
Попробуйте примеры на игровой площадке Go.
Стоит ли беспокоиться о производительности (из-за преобразования типов)? Точно нет. byte
-> int8
преобразование не требует затрат времени выполнения, так как оба имеют одинаковую структуру памяти (то есть 8 бит = 1 байт), и преобразование просто говорит, что эти 8 бит следует интерпретировать по-разному.
Небезопасный ответ выше вполне подойдет, однако он не будет работать на appengine.
Вот безопасная версия:
signed := make([]int8, len(unsigned))
for i, v := range unsigned {
signed[i] = int8(v)
}