filegofilehandler

How to only edit specific bytes of byte of a file instead of rewriting the whole file


I wanted to create a single file database for storing bytes which emulates the way our filesystem works on a hard drive such that I am able to edit specific bytes (changed or saved by the user) while writing to the database instead of reading the whole file into memory changing a few bytes and rewriting the database file back to the disk.

How can I just alter specific bytes in the file using the file handler instead of requiring me loading the whole database into memory, doing the changes (this does not change the size of the overall file) and then storing it back.

I have tried searching my query but I am unable to get the answer I am looking for. I have tried using different modes for opening a file handler and maybe trying that.


Solution

  • Try to use WriteAt:

    package main
    
    import (
        "fmt"
        "log"
        "os"
    )
    
    const fileName = "test.txt"
    
    func createFile(filename string) error {
        f, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
        if err != nil {
            return fmt.Errorf("cannot create file: %v", err)
        }
        defer f.Close()
    
        if _, err := f.Write([]byte("Hello, World!")); err != nil {
            return fmt.Errorf("cannot write data to file: %v", err)
        }
    
        return nil
    }
    
    func changeFileByte(filename string, b []byte, pos int64) error {
        f, err := os.OpenFile(filename, os.O_WRONLY, 0644)
        if err != nil {
            return fmt.Errorf("cannot open file: %v", err)
        }
        defer f.Close()
    
        if _, err := f.WriteAt(b, pos); err != nil {
            return fmt.Errorf("cannot write to file: %v", err)
        }
    
        return nil
    }
    
    func printFile(filename string) error {
        content, err := os.ReadFile(filename)
        if err != nil {
            return fmt.Errorf("cannot read file: %v", err)
        }
        fmt.Printf("%s\n", content)
    
        return nil
    }
    
    func main() {
        if err := createFile(fileName); err != nil {
            log.Fatal(err)
        }
    
        if err := printFile(fileName); err != nil {
            log.Fatal(err)
        }
    
        if err := changeFileByte(fileName, []byte{'.'}, 12); err != nil {
            log.Fatal(err)
        }
    
        if err := printFile(fileName); err != nil {
            log.Fatal(err)
        }
    }