首页 > 其他分享 >golang: os.Write函数

golang: os.Write函数

时间:2023-01-17 16:45:41浏览次数:45  
标签:Write return err int golang write fd os

函数解析


  • os.Write函数
func (f *File) Write(b []byte) (n int, err error) {
    // 判断是否f为nil
	if err := f.checkValid("write"); err != nil {
		return 0, err
	}
    // 把b写入文件
	n, e := f.write(b)
	if n < 0 {
		n = 0
	}
    // 没有完成写入
	if n != len(b) {
		err = io.ErrShortWrite
	}
    // 检查e 是否是错误的管道和file.stdoutOrErr是否为真
	epipecheck(f, e)
    // 如果e扔不为nil则生成一个写错误
	if e != nil {
		err = f.wrapErr("write", e)
	}

	return n, err
}

主要实现是f.write()函数

  • f.write函数
func (f *File) write(b []byte) (n int, err error) {
    // 是否file结构的pfd即文件描述符的Write方法,将b写入f, f.pfd是一个poll.FD结构体
	n, err = f.pfd.Write(b)
	runtime.KeepAlive(f)
	return n, err
}

  • fd.Write函数
// Write implements io.Writer.
func (fd *FD) Write(p []byte) (int, error) {
    // 获取写锁
	if err := fd.writeLock(); err != nil {
		return 0, err
	}
	defer fd.writeUnlock()
    // 判断fd是否是个文件的描述符
	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
		return 0, err
	}
    // 
	var nn int
	for {
		max := len(p)
		if fd.IsStream && max-nn > maxRW {
			max = nn + maxRW
		}
		n, err := ignoringEINTRIO(syscall.Write, fd.Sysfd, p[nn:max])
		if n > 0 {
			nn += n
		}
        // nn 等于len(p)写入正确
		if nn == len(p) {
			return nn, err
		}
        // 如果nn > 0 但是不等len(p)说明写入不完全意外中断
		if err == syscall.EAGAIN && fd.pd.pollable() {
			if err = fd.pd.waitWrite(fd.isFile); err == nil {
				continue
			}
		}
		if err != nil {
			return nn, err
		}
		if n == 0 {
			return nn, io.ErrUnexpectedEOF
		}
	}
}

// ignoringEINTRIO is like ignoringEINTR, but just for IO calls.
func ignoringEINTRIO(fn func(fd int, p []byte) (int, error), fd int, p []byte) (int, error) {
	for {
        // fn : syscall.Write
		n, err := fn(fd, p)
		if err != syscall.EINTR {
			return n, err
		}
	}
}

  • syscall.Write函数
func Write(fd int, p []byte) (n int, err error) {
	if race.Enabled {
		race.ReleaseMerge(unsafe.Pointer(&ioSync))
	}
	if faketime && (fd == 1 || fd == 2) {
		n = faketimeWrite(fd, p)
		if n < 0 {
			n, err = 0, errnoErr(Errno(-n))
		}
    // 进程打开的第一个文件的fd应该默认是3
	} else {
		n, err = write(fd, p)
	}
	if race.Enabled && n > 0 {
		race.ReadRange(unsafe.Pointer(&p[0]), n)
	}
	if msanenabled && n > 0 {
		msanRead(unsafe.Pointer(&p[0]), n)
	}
	if asanenabled && n > 0 {
		asanRead(unsafe.Pointer(&p[0]), n)
	}
	return
}

  • syscall.write函数
func write(fd int, p []byte) (n int, err error) {
	var _p0 unsafe.Pointer
	if len(p) > 0 {
		_p0 = unsafe.Pointer(&p[0])
	} else {
		_p0 = unsafe.Pointer(&_zero)
	}
	r0, _, e1 := syscall(abi.FuncPCABI0(libc_write_trampoline), uintptr(fd), uintptr(_p0), uintptr(len(p)))
	n = int(r0)
	if e1 != 0 {
		err = errnoErr(e1)
	}
	return
}

  • libc_unmount_trampoline函数
func libc_unmount_trampoline()

//go:cgo_import_dynamic libc_unmount unmount "/usr/lib/libSystem.B.dylib"

// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT

根据注释说明是一个c库里的引用

  • glibc里的write函数定义
ssize_t
__libc_write (int fd, const void *buf, size_t nbytes)

实例

package main

import (
	"fmt"
	"log"
	"os"
)

func main() {
	file, err := os.OpenFile("./fio.conf", os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		log.Fatalln("OpenFile failed")
	}
	defer file.Close()
	content := []byte("hello world")
	n, err := file.Write(content)
	if err != nil {
		log.Fatalln("Write failed")
	}
	fmt.Printf("write %d bytes\n", n)
}

标签:Write,return,err,int,golang,write,fd,os
From: https://www.cnblogs.com/ishmaelwanglin/p/17058135.html

相关文章