Преобразовать поток неподписанных байтов в подписанный поток потоков Голанг

Каков наилучший способ преобразования байтового потока в слайс байтового потока на Голанге? В настоящее время я пытаюсь реплицировать 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)
}

детская площадка

Другие вопросы по тегам