在Golang中创建自定义作家和读者

I'm new to golang (wrangling it for a week or so). At this point, I'm porting a library from PHP to Golang since I felt like I should move this to a language that is way more efficient especially when doing low-level stuff.

In PHP, manual serialization is done by opening a filehandle first.

public function __construct($filename, $mode='r+b')
{
    some checking and stuff...

    $this->_fileHandle = @fopen($filename, $mode);

}

public function seek($offset, $whence=SEEK_SET)
{
    return fseek($this->_fileHandle, $offset, $whence);
}

public function readInt()
{
    $str = $this->_fread(4);

    return  ord($str[0]) << 24 |
            ord($str[1]) << 16 |
            ord($str[2]) << 8  |
            ord($str[3]);
}

public function readLong()
{ ....... }

public function writeInt($value)
{
    settype($value, 'integer');
    $this->_fwrite( chr($value>>24 & 0xFF) .
                    chr($value>>16 & 0xFF) .
                    chr($value>>8  & 0xFF) .
                    chr($value     & 0xFF),   4  );
}

public function writeLong($value)
{ ..... }

protected function _fwrite($data, $length=null)
{
    if ($length === null ) {
        fwrite($this->_fileHandle, $data);
    } else {
        fwrite($this->_fileHandle, $data, $length);
    }
}

protected function _fread($length=1)
{
    if ($length == 0) {
        return '';
    }

    if ($length < 1024) {
        return fread($this->_fileHandle, $length);
    }

    $data = '';
    while ( $length > 0 && ($nextBlock = fread($this->_fileHandle, $length)) != false ) {
        $data .= $nextBlock;
        $length -= strlen($nextBlock);
    }
    return $data;
}

Everything pretty much revolves around the fileHandle.

In Golang, I understood that os.File can be wrapped in a custom reader and writer (io.Reader and io.Writer) which is fine until I needed to move offsets (using seek in php) and replacing some bytes.

type FileSystem struct {
    FileHandle      *os.File
    byte        []byte
    Pos   int64
}

func NewFileSystem(filepath string, create bool) (*FileSystem, error) {

    var file *os.File
    var err error

    if create == false {
        if _, err_r := os.Stat(filepath); os.IsNotExist(err_r) {
            return nil, err_r
        }
        file, err = os.OpenFile(filepath, os.O_RDWR, 0644)
    } else {
        file, err = os.Create(filepath)
    }

        if err != nil { 
            os.Exit(0)
            return nil, err
        }

        fileinfo, err := file.Stat()
        if err != nil {
          return nil, err
        }
        filesize := fileinfo.Size()
        text := make([]byte, filesize)

        if create == false {
            file.Read(text)
        }

        return &FileSystem{
            FileHandle: file,
            byte: text,
            Pos: 0,
        }, nil

}

func (fs *FileSystem) Seek(offset int64, whence int) (int64, error) {

   var newoffset int64
   switch whence {
   case 0:
       newoffset = offset
   case 1:
       newoffset = fs.Pos + offset
   case 2:
       newoffset = int64(len(fs.byte)) - offset
   }

   if newoffset == fs.Pos {
       return newoffset, nil
   }

   fs.Pos = newoffset
   return fs.Pos, nil
}

func (fs *FileSystem) ReadByte() (b byte, err error) {
    fs.Pos++
    return fs.byte[fs.Pos-1], nil
}

func (fs *FileSystem) ReadInt() (n int32, err error) {
   fs.Pos += 4
   return (int32(fs.byte[fs.Pos-4]) << 24) | (int32(fs.byte[fs.Pos-3]) << 16) |
    (int32(fs.byte[fs.Pos-2]) << 8) | int32(fs.byte[fs.Pos-1]), nil
}

func (fs *FileSystem) ReadLong() (n int64, err error) {
   i1, _ := fs.ReadInt()
   i2, _ := fs.ReadInt()
   return (int64(i1) << 32) | int64(i2), nil
}

func (fs *FileSystem) WriteByte(b byte) error {

    w := bufio.NewWriter(fs.FileHandle)
    if (len(fs.byte) <= 0) {
        fs.byte = append(fs.byte, b)
    } else {
        fs.byte[fs.Pos] = b
    }

    err := w.WriteByte(b)
    if err != nil {
        fmt.Errorf("Error writing data: ", err)
    }

    w.Flush()
    fs.Pos++
    return nil
}

func (fs *FileSystem) WriteInt(i int32) error {

    err := fs.WriteByte(byte(i >> 24))
    if err == nil {
        err = fs.WriteByte(byte(i >> 16))
        if err == nil {
            err = fs.WriteByte(byte(i >> 8))
            if err == nil {
                err = fs.WriteByte(byte(i))
            }
        }
    }
    return err
}

func (fs *FileSystem) WriteLong(i int64) error {
    err := fs.WriteInt(int32(i >> 32))
    if err == nil {
        err = fs.WriteInt(int32(i))
    }
    return err
}

Which doesn't actually replace the byte when I do, Seek(12, 0) and WriteInt/WriteLong, etc.. (because WriteByte() pretty much writes at the end of file always..and yes the sample above actually gives out error when index is out of range, especially for new file (length is 0)).

I'm wondering if there is something (other than WriteByte()) that takes offset as argument to overwrite the byte at that offset.