io가 뭐예요?Go의 리더?
19087 단어 gocodenewbie
io.Reader
인터페이스를 상당히 많이 만날 것이다.그것은 많은 다른 출처에서 읽은 데이터를 나타내는 데 광범위하게 사용되지만, 그 유형의 정의는 사실상 상당히 간단하다.type Reader interface {
Read(p []byte) (n int, err error)
}
오직 한 가지 방법!이것은 Read라는 방법으로 형식을 생성하고 바이트를 받아들여 int에 발생한 오류를 되돌려준다면 형식은 io.Reader
이라는 것을 의미합니다.그러나 이 인터페이스의 생각은 무엇입니까? 우리는 어떻게 코드에서 그것을 사용합니까?함수 서명 봐.
Reader
는 강력한 추상적인 작은 인터페이스입니다!그 추상은 도대체 무엇입니까?Read
방법의 사상은 어떤 원본에서 데이터 바이트를 읽으면 코드에서 이 바이트를 사용할 수 있다는 것을 나타낸다.이 출처는 파일, 카메라, 네트워크 연결일 수도 있고, 일반적인 오래된 문자열일 수도 있다.예를 들어 파일에서 데이터를 읽으면 io.Reader
은 *os.File
입니다.시도하기 전에
Reader.Read
함수 서명 부분을 살펴보겠습니다.Read(p []byte) (n int, err error)
p []byte
는 우리가 읽는 방법에 전달하는 바이트이다.판독기는 파일 같은 데이터 원본에서 읽은 데이터를 이 바이트로 복사합니다.n int
은 Read
호출에서 몇 바이트를 읽었는지 알려 줍니다.err error
은 데이터를 읽을 때 발생할 수 있는 모든 오류입니다. 예를 들어 파일 끝에 도달하는 것입니다.sloth.txt
라는 새 디렉토리의 파일에 저장합니다.I'm a sloth and hibiscus flowers are tasty!
이제 Go 코드를 작성하여 파일을 읽는 방법을 사용합니다.이 코드를 복사해서 sloth가 있는 디렉터리에 있는 파일 main.go
에 저장합니다.txt:package main
import (
"log"
"os"
)
func main() {
file, err := os.OpenFile("sloth.txt")
if err != nil {
log.Fatalf("error opening sloth.txt: %v", err)
}
defer file.Close()
// Make a byte slice that's big enough to store a few words of the message
// we're reading
bytesRead := make([]byte, 33)
// Now read some data, passing in our byte slice
n, err := file.Read(bytesRead)
if err != nil {
log.Fatalf("error reading from sloth.txt: %v", err)
}
// Take a look at the bytes we copied into the byte slice
log.Printf("We read \"%s\" into bytesRead (%d bytes)",
string(bytesRead), n)
}
go run main.go
명령을 실행하면 다음과 같은 출력을 얻을 수 있습니다.We read "I'm a sloth and hibiscus flowers " (33 bytes) into bytesRead
따라서 Go 는 호출 os.File.Read
시 파일에서 데이터를 읽어 bytesRead
로 복사합니다. 오류가 발생하지 않았기 때문에 0 으로 되돌아옵니다.우리는bytesRead 부분을 Read
함수에 전달할 것입니다. 마치 우리가 컵을 사이다 분수에 전달하는 것처럼!이것이 바로 우리가 바이트를 얻는 방식이지만, 왜 우리는 심지어 읽은 바이트 수를 되돌려줍니까?
원인을 알아보기 위해 우리가 다시 전화를 걸면
Read
무슨 일이 일어날지 봅시다.우리는 나무늘보가 부용화에 대한 견해를 보고 싶다!주 함수의 끝에 추가: n, err = file.Read(bytesRead)
if err != nil {
log.Fatalf("error reading from sloth.txt: %v", err)
}
log.Printf("We read \"%s\" into bytesRead (%d bytes)",
string(bytesRead), n)
현재 go run main.go
의 출력은 다음과 같습니다.2020/03/01 13:38:50 We read "I'm a sloth and hibiscus flowers " into bytesRead (33 bytes)
2020/03/01 13:38:50 We read "are tasty!
and hibiscus flowers " into bytesRead (11 bytes)
예상대로 우리는 책에서 우리의 나무늘보가 확실히 부용화를 좋아하지만, 왜 우리가 수출한 세 번째 줄설and hibiscus flowers
을 읽었다.왜냐하면 우리의 리더가 파일에 남은 11바이트를 우리의
bytesRead
슬라이스의 시작 부분에 복사했을 때, 슬라이스의 나머지 부분에 닿지 않았기 때문이다.슬라이스의 나머지 부분은 우리가 지난번 호출 Read
때 읽은 바이트를 포함합니다!따라서 되돌아오는 정수
n
는 바이트에 우리가 읽은 내용을 포함하는 바이트를 알려준다.이렇게 하면 이 바이트를 처리하는 코드는 영화의 어떤 바이트에 관심을 가져야 하는지, 어떤 바이트에 관심을 가져야 하는지 알게 될 것이다.io 오류 처리.독자
다시 한 번 전화해 봅시다
file.Read
: n, err = file.Read(bytesRead)
if err == io.EOF {
log.Printf("End of file reached; we got %d bytes on the last read", n)
} else {
log.Fatalf("unexpected error reading from the file: %v\n", err)
}
go run main.go
를 사용하여 다음 명령을 실행합니다.2020/03/01 13:44:35 We read "I'm a sloth and hibiscus flowers " into bytesRead (33 bytes)
2020/03/01 13:44:35 We read "are tasty!
and hibiscus flowers " into bytesRead (11 bytes)
2020/03/01 13:44:35 End of file reached; we got 0 bytes on the last read
우리가 얻은 오류는 io.EOF
로'파일이 끝났다'는 것을 대표한다. 이것은 우리가 통상적으로 기대하는 오류이다.EOF를 만났을 때, 코드가 읽은 바이트를 처리하고 이 io에서 데이터를 읽는 것을 멈추는 것이 일반적입니다.데이터가 없으니까.그러나 EOF는
io.Reader.Read
에서 반환할 수 있는 유일한 오류가 아닙니다.만약 우리가 EOF 이외의 오류를 얻게 된다면, 통상적으로 코드에 오류가 있거나, 의외의 일이 발생했다는 것을 의미한다.예를 들어, 이 코드를 close-early.go
로 복사하여 닫힌 파일에서 읽으려면 다음과 같이 하십시오.package main
import (
"log"
"os"
)
func main() {
file, err := os.OpenFile("sloth.txt")
if err != nil {
log.Fatalf("error opening sloth.txt: %v", err)
}
file.Close()
bytesRead := make([]byte, 0, 33)
if _, err := file.Read(bytesRead); err != nil {
log.Fatalf("error reading from sloth.txt: %#v", err)
}
}
go run close-early.go
를 사용하여 실행할 경우 다음을 수행해야 합니다.2020/03/01 13:45:45 error reading from sloth.txt: &os.PathError{Op:"read", Path:"sloth.txt",
Err:(*errors.errorString)(0xc000010110)}
exit status 1
닫힌 파일을 읽으려고 시도하고 있기 때문에 os.PathError
따라서 일반적으로 실행 중인 경우io.Reader.Read
bytesRead[:n]
바이트로 복사되어 더 많은 데이터를 계속 읽을 수 있습니다.io.EOF
을 얻게 된다면, 우리는 데이터 읽기를 멈춰야 합니다. 만약 어떤 바이트가 bytesRead
로 복사된다면, 우리는 당신의 코드 처리 n
의 마지막 bytesRead[:n]
바이트를io.Reader
을 사용하는 코드는 통상적으로 이 바이트를 처리해야 한다.io에 구축합니다.독자
io.Reader.Read
는 대량의 데이터 원본에서 데이터를 읽는 일반적인 방법을 제공하지만, Go 프로젝트에서는 일반적으로 직접 호출하지 않습니다Read
.반대로 우리는 이 방법 위에 구축된 코드가 있다.그 중 일부는 다음과 같습니다.ioutil.ReadAll
에 전달할 수 있습니다!bufio.Scanner
방법으로 한 줄의 데이터를 읽을 수 있고, 스캐너는 새로운 줄을 찾는 작업을 처리할 것이다. 그러면 당신의 코드는 당신을 위해 이 점을 고려할 필요가 없다.Scan
인터페이스로 디코딩하는 데 도움을 줄 것입니다!image.Image
"JSON 논리가 이미 포함되어 있습니다!json.Decoder.Decode
?Read
는 저급 인터페이스이기 때문이다.원본에서 데이터를 읽고 바이트로 복사하는 작업이지만, 어떤 바이트를 읽었는지는 상관없습니다.실제로 이 바이트를 처리하는 것은 Read를 호출하는 코드로 처리됩니다.이 점을 보려면 JSON을 반서열화해봅시다!이 Go 코드를 에 저장하기
io.Reader
:package main
import (
"encoding/json"
"fmt"
"strings"
)
type AnimalFacts struct {
CommonName string `json:"commonName"`
ScientificName string `json:"scientificName"`
HeightInInches int `json:"heightInInches"`
FavoriteFoods []string `json:"favoriteFoods"`
CanSwim bool `json:"canSwim"`
}
func main() {
jsonData := `
{
"commonName": "brown-throated three-toed sloth",
"scientificName": "Bradypus variegatus",
"heightInInches": 31,
"favoriteFoods": ["Cecropia leaves", "Hibiscus flowers"],
"canSwim": true
}`
// an io.Reader that isn't a file!
rdr := strings.NewReader(jsonData)
var sloth AnimalFacts
if err := json.NewDecoder(rdr).Decode(&sloth); err != nil {
fmt.Printf("error deserializing JSON: %v", err)
return
}
fmt.Printf("Hi! I'm a %s (%s)! I'm about %d\" tall, and love eating %v!\n",
sloth.CommonName, sloth.ScientificName, sloth.HeightInInches,
sloth.FavoriteFoods)
if sloth.CanSwim {
fmt.Println("By the way, I can swim!")
}
}
sloth-facts.go
를 사용하여 이 명령을 실행하면 다음과 같은 출력을 얻을 수 있습니다.Hi! I'm a brown-throated three-toed sloth (Bradypus variegatus)! I'm about 31"
tall, and love eating [Cecropia leaves Hibiscus flowers]!
By the way, I can swim
여기서 무슨 일이 일어났습니까?go run sloth-facts.go
을 생성합니다.파일을 io로 사용하는 것이 아니라독자, 우리는 일반적인 낡은 문자열에서 데이터를 읽을 수 있도록 io.Reader
을 만들고 있습니다!strings.Reader
수용json.NewDecoder
, 그래서 문자열을 전달합니다.리더는 JSON 데이터를 리더에서 읽는 구조를 설정하고 Go 변수로 들어갑니다.io.Reader
구조를 가리키는 바늘을 json.Decoder
에 전달하고 우리의 JSON 데이터는 이 구조에 읽힌다!AnimalFacts
에 대한 간단한 조정을 통해 JSON 데이터를 읽는다면, 우리는 괄호와 쉼표, 그리고 우리가 현재 JSON에 있는 필드 등을 추적해야 한다.하지만 json.Decoder.Decode
Go팀은 이미 우리를 위해 이 문제를 해결했고 io.Reader.Read
을 바탕으로 JSON 디코딩 논리를 구축했다!보시다시피
json.Decoder.Decode
은 진정한 다기능 인터페이스입니다!이것이 바로 Go 코드에서 곳곳에서 볼 수 있는 이유입니다Read
. io.Reader
방법과 함께 작업하는 코드로 모든 데이터 형식을 처리할 수 있습니다. 이것은 훌륭한 Go 인터페이스 추상입니다!
Reference
이 문제에 관하여(io가 뭐예요?Go의 리더?), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/andyhaskell/what-is-the-io-reader-in-go-48co텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)