io.Copy 조사
개요
정의
func Copy(dst Writer, src Reader) (written int64, err error)
type Writer interface {
Write(p []byte) (n int, err error)
}
type Reader interface {
Read(p []byte) (n int, err error)
}
예제
package main
import (
"io"
"log"
"os"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
if _, err := io.Copy(os.Stdout, r); err != nil {
log.Fatal(err)
}
}
기본 프로세스
io.Copy
func Copy(dst Writer, src Reader) (written int64, err error) {
return copyBuffer(dst, src, nil)
}
copyBuffer
if buf == nil {
size := 32 * 1024
buf = make([]byte, size)
}
for {
nr, er := src.Read(buf)
if nr > 0 {
nw, ew := dst.Write(buf[0:nr])
if nw < 0 || nr < nw {
nw = 0
if ew == nil {
ew = errInvalidWrite
}
}
written += int64(nw)
if ew != nil {
err = ew
break
}
if nr != nw {
err = ErrShortWrite
break
}
}
if er != nil {
if er != EOF {
err = er
}
break
}
}
src에서 WriterTo를 설치할 때
//Avoids an allocation and a copy.
if wt, ok := src.(WriterTo); ok {
return wt.WriteTo(dst)
}
WriterTo interface
type WriterTo interface {
WriteTo(w Writer) (n int64, err error)
}
ag 'WriteTo implements' -l
bufio/bufio.go
net/net.go
net/iprawsock.go
net/unixsock.go
net/udpsock.go
strings/reader.go
bytes/reader.go
strings.Reader.WriteTo
func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
r.prevRune = -1
if r.i >= int64(len(r.s)) {
return 0, nil
}
s := r.s[r.i:]
m, err := io.WriteString(w, s)
if m > len(s) {
panic("strings.Reader.WriteTo: invalid WriteString count")
}
r.i += int64(m)
n = int64(m)
if m != len(s) && err == nil {
err = io.ErrShortWrite
}
return
}
StringWriter Interface
func WriteString(w Writer, s string) (n int, err error) {
if sw, ok := w.(StringWriter); ok {
return sw.WriteString(s)
}
return w.Write([]byte(s))
}
File.WriteString
bytes 슬라이드 unsafe 선포.Pointer 확보
func (f *File) WriteString(s string) (n int, err error) {
var b []byte
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&b))
hdr.Data = (*unsafeheader.String)(unsafe.Pointer(&s)).Data
hdr.Cap = len(s)
hdr.Len = len(s)
return f.Write(b)
}
dst에서 ReaderFrom을 설치할 때
package main
import (
"io"
"log"
"os"
)
type myReader struct {
}
func (r *myReader) Read(p []byte) (n int, err error) {
copy(p, []byte("hello,world\n"))
return len(p), io.EOF
}
func main() {
r := &myReader{}
if _, err := io.Copy(os.Stdout, r); err != nil {
log.Fatal(err)
}
}
package main
import (
"io"
"log"
"os"
)
func main() {
r, err := os.Open("hoge.txt")
if err != nil {
panic(err)
}
if _, err := io.Copy(os.Stdout, r); err != nil {
log.Fatal(err)
}
}
hello,world
ReaderFrom interface
type ReaderFrom interface {
ReadFrom(r Reader) (n int64, err error)
}
ag 'ReadFrom implements' -l
bufio/bufio.go
net/tcpsock.go
net/iprawsock.go
net/unixsock.go
net/udpsock.go
os/file.go
File.ReadFrom
// ReadFrom implements io.ReaderFrom.
func (f *File) ReadFrom(r io.Reader) (n int64, err error) {
n, handled, e := f.readFrom(r)
return n, f.wrapErr("write", e)
}
func (f *File) readFrom(r io.Reader) (written int64, handled bool, err error) {
written, handled, err = pollCopyFileRange(&f.pfd, &src.pfd, remain)
if lr != nil {
lr.N -= written
}
return written, handled, NewSyscallError("copy_file_range", err)
}
pollCopyFileRange는 poll입니다.CopyFileRange의 실제 상태var pollCopyFileRange = poll.CopyFileRange
CopyFileRange
func CopyFileRange(dst, src *FD, remain int64) (written int64, handled bool, err error) {
if supported := atomic.LoadInt32(©FileRangeSupported); supported == 0 {
return 0, false, nil
} else if supported == -1 {
major, minor := kernelVersion()
if major > 5 || (major == 5 && minor >= 3) {
atomic.StoreInt32(©FileRangeSupported, 1)
}
}
for remain > 0 {
max := remain
n, err := copyFileRange(dst, src, int(max))
}
return written, true, nil
}
copyFileRange
func copyFileRange(dst, src *FD, max int) (written int64, err error) {
if err := dst.writeLock(); err != nil {
return 0, err
}
defer dst.writeUnlock()
if err := src.readLock(); err != nil {
return 0, err
}
defer src.readUnlock()
var n int
for {
n, err = unix.CopyFileRange(src.Sysfd, nil, dst.Sysfd, nil, max, 0)
if err != syscall.EINTR {
break
}
}
return int64(n), err
}
unix.CopyFileRange
func CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error) {
r1, _, errno := syscall.Syscall6(copyFileRangeTrap,
uintptr(rfd),
uintptr(unsafe.Pointer(roff)),
uintptr(wfd),
uintptr(unsafe.Pointer(woff)),
uintptr(len),
uintptr(flags),
)
n = int(r1)
if errno != 0 {
err = errno
}
return
}
syscall.Syscall6
TEXT ·Syscall6(SB),NOSPLIT,$0-80
CALL runtime·entersyscall(SB)
MOVQ a1+8(FP), DI
MOVQ a2+16(FP), SI
MOVQ a3+24(FP), DX
MOVQ a4+32(FP), R10
MOVQ a5+40(FP), R8
MOVQ a6+48(FP), R9
MOVQ trap+0(FP), AX // syscall entry
SYSCALL
CMPQ AX, $0xfffffffffffff001
JLS ok6
MOVQ $-1, r1+56(FP)
MOVQ $0, r2+64(FP)
NEGQ AX
MOVQ AX, err+72(FP)
CALL runtime·exitsyscall(SB)
RET
ok6:
MOVQ AX, r1+56(FP)
MOVQ DX, r2+64(FP)
MOVQ $0, err+72(FP)
CALL runtime·exitsyscall(SB)
RET
참고 자료
Reference
이 문제에 관하여(io.Copy 조사), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/hiroyukim/articles/e17285ed06ebff텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)