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.