英文:
Golang: Read buffered input as signed 16bit ints
问题
我正在尝试读取一个带缓冲的有符号16位整数流(wav格式),但是bufio.Read方法只接受字节数组作为参数。我的问题有两个部分:
- 我能否将字节流预格式化为带缓冲的int16数组?
- 如果不能,将字节数组后处理为int16数组的最佳方法是什么?我最初的想法是使用临时数组并不断推送/处理它们,但我想知道是否有更符合惯用方式的方法?
package main
import (
"bufio"
"io"
"log"
"os/exec"
)
func main() {
app := "someapp"
cmd := exec.Command(app)
stdout, err := cmd.StdoutPipe()
r := bufio.NewReader(stdout)
if err != nil {
log.Fatal(err)
}
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
// "someapp"输出有符号16位整数(小端序)
buf := make([]byte, 0, 4*1024)
for {
n, err := r.Read(buf[:cap(buf)]) // r.Read只接受[]byte类型
buf = buf[:n]
if n == 0 {
if err == nil {
continue
}
if err == io.EOF {
break
}
log.Fatal(err)
}
log.Printf("%x\n", buf)
// 在这里处理buf
if err != nil && err != io.EOF {
log.Fatal(err)
}
}
}
英文:
I am trying to read a buffered stream of signed 16 bit integers (wav format), but the bufio.Read method only accepts an array of bytes. My question is a 2-parter:
-
Can I preformat the byte stream into a buffered int16 array?
-
If I can't, whats the best way of post-processing the byte array into int16 array? My initial thought is to use tmp arrays and keep pushing/processing them, but I was curious if there was a more idiomatic way of doing this?
package main import ( "bufio" "io" "log" "os/exec" ) func main() { app := "someapp" cmd := exec.Command(app) stdout, err := cmd.StdoutPipe() r := bufio.NewReader(stdout) if err != nil { log.Fatal(err) } if err := cmd.Start(); err != nil { log.Fatal(err) } //"someapp" outputs signed 16bit integers (little endian)) buf := make([]byte, 0, 4*1024) for { n, err := r.Read(buf[:cap(buf)]) //r.Read only accepts type []byte buf = buf[:n] if n == 0 { if err == nil { continue } if err == io.EOF { break } log.Fatal(err) } log.Printf("%x\n", buf) //process buf here if err != nil && err != io.EOF { log.Fatal(err) } } }
答案1
得分: 4
在处理输入输出(IO)时,你总是使用[]byte
,无法用[]int16
替代它,也无法预先将其格式化为int16
,它始终是一串字节流。
你可以查看encoding/binary
包来解码这个流。
// 获取第一个uint16作为i
i := binary.LittleEndian.Uint16(buf[:2])
然后你可以根据需要遍历buf
。
你还可以使用binary.Read
直接从io.Reader
中读取。
var i uint16
for {
err := binary.Read(r, binary.LittleEndian, &i)
if err != nil {
log.Println(err)
break
}
fmt.Println(i)
}
值得注意的是,需要完成的工作非常简单。每个uint16
通过以下方式创建:
func (littleEndian) Uint16(b []byte) uint16 {
return uint16(b[0]) | uint16(b[1])<<8
}
英文:
When working with IO, you always work with []byte
s, there's no way to substitute that with []int16
, or pre-format that as int16
s, it's always a stream of bytes.
You can look at the encoding/binary
package to decode this stream.
// to get the first uint16 as i
i := binary.LittleEndian.Uint16(buf[:2])
You can then iterate through the buf as needed.
You can also use binary.Read
to read directly from the io.Reader
.
var i uint16
for {
err := binary.Read(r, binary.LittleEndian, &i)
if err != nil {
log.Println(err)
break
}
fmt.Println(i)
}
It may worth noting the simplicity of what needs to be done. Each uint16
is created via:
func (littleEndian) Uint16(b []byte) uint16 {
return uint16(b[0]) | uint16(b[1])<<8
}
答案2
得分: 1
你可以使用encoding/binary.Read
直接从读取器中填充[]int16
,尽管从技术上讲,对于你的第一个问题,答案仍然是否定的(请检查binary.Read
的源代码,它首先将数据读取到[]byte
中)。
英文:
You can use encoding/binary.Read
to fill an []int16
directly from your reader, although technically the answer to your first question is still no (check the source of binary.Read
, it reads the data to a []byte
first).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论