125

So I can read from a local file like so:

data, error := ioutil.ReadFile(name)

And I can write to a local file

ioutil.WriteFile(filename, content, permission)

But how can I append to a file? Is there a built in method?

Sridhar Ratnakumar
  • 81,433
  • 63
  • 146
  • 187
seveibar
  • 4,403
  • 4
  • 30
  • 31
  • 4
    Yep, you got it. The ioutil functions are just conveniences that take care of common tasks. If you want more control, see the os package. – Evan Shaw Aug 23 '11 at 01:21

7 Answers7

202

This answers works in Go1:

f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
    panic(err)
}

defer f.Close()

if _, err = f.WriteString(text); err != nil {
    panic(err)
}
Debosmit Ray
  • 5,228
  • 2
  • 27
  • 43
Sridhar Ratnakumar
  • 81,433
  • 63
  • 146
  • 187
  • 3
    Why not 0666 file mode? I thought that was a better default value. – Dmitri Shuralyov Mar 04 '13 at 03:57
  • 1
    @SridharRatnakumar: see [another comment](http://stackoverflow.com/questions/2245193/c-linux-file-permission-problem-with-open#comment-2203227) and _[man umask](http://man7.org/linux/man-pages/man2/umask.2.html)_. With typical umask of 022, you'll get typical permissions: `0666 & ~022 = 0644 = rw-r--r--` – akavel Oct 22 '13 at 19:52
  • 57
    os.O_CREATE is nice to include if the file might not already exist. – bugloaf Jun 19 '15 at 03:27
  • 4
    maybe a bit stupid question but why would it need both `os.O_APPEND` and `os.O_WRONLY`? This works for sure but why both? – Dusan Gligoric Oct 29 '19 at 19:30
  • os.O_APPEND and os.O_WRONLY os.O_APPEND is to control behaviour in this case to Append mode so it does not need to maintain a file pointer. os.O_WRONLY is to state the file mode, wether read,write, or both, in this case write. – Cyberience Dec 14 '20 at 08:13
  • I realize the docs say `Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified.`, but couldn't `O_WRONLY` be _implied_ by `O_APPEND`? I can't think of a case where you would ever open with mode `O_RDONLY|O_APPEND` (and only a contrived use case for `O_RDWR|O_APPEND`). Ya know, `os.Append` seems like a reasonable addition to the stdlib, alongside the other wrappers `os.Open` and `os.Create` – ardnew May 10 '23 at 18:53
73

Go docs has a perfect example :

package main

import (
    "log"
    "os"
)

func main() {
    // If the file doesn't exist, create it, or append to the file
    f, err := os.OpenFile("access.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }
    if _, err := f.Write([]byte("appended some data\n")); err != nil {
        log.Fatal(err)
    }
    if err := f.Close(); err != nil {
        log.Fatal(err)
    }
}
Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40
Jimmy Obonyo Abor
  • 7,335
  • 10
  • 43
  • 71
32

Figured it out

More info

f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0644) 

n, err := f.WriteString(text) 

f.Close()
Robert
  • 33,429
  • 8
  • 90
  • 94
seveibar
  • 4,403
  • 4
  • 30
  • 31
8

... I would use fmt.Fprintf, because accept a writer... and a connection or files will be a writer and easy to write in a way of string...

f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0600)
if err != nil {
    panic(err)
}

defer f.Close()
fmt.Fprintf(f, "%s", text)

I hope this help!

Javier,

6

If you also want to create the file

f, err := os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)

Luke W
  • 8,276
  • 5
  • 44
  • 36
5
f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
    panic(err)
}

defer f.Close()

if _, err = f.WriteString(text); err != nil {
    panic(err)
}

Made a slight change from the one provided in the golang site by adding flags to the os.OpenFile function which by default will only allow reading of a file and not editing amongst other features.

  • What is the change and why? – Mitar Feb 18 '22 at 21:06
  • @Mitar what exactly do u mean cause I'm using different functions. Though, if u are asking about how the appending is done specifically I'll point u to the `os.OpenFile` function which can accepts flags for what u can do with a file, i.e. u can create the said file if it doesn't exist using this flag `os.O_CREATE` or for this case u can append using the `os.O_APPEND` flag for allowing to append to the file. ps. u can use a couple of them at the same time – paradox earthling Mar 02 '22 at 15:45
  • You said that you made a slight change to the highest voted comment. But I do not see any change from the accepted answer. What is the change? – Mitar Mar 03 '22 at 22:36
  • Only chmod is different and set to 644? – Mitar Mar 03 '22 at 22:37
  • @Mitar sorry didn't get what u meant before, but yes, by default u are only allowed to read, so u need to specify the rights to said file. – paradox earthling Mar 04 '22 at 12:47
  • Sorry, I was not clear as well. I am saying that you should update your answer and explain in it what you changed. – Mitar Mar 04 '22 at 17:34
  • @mitar done editing :) – paradox earthling Mar 14 '22 at 13:51
1

Let's say you want to add the contents of filecurrent to the file all, then below code is working:

func updateTrx() {
    var err error
    var f *os.File

    // If the file doesn't exist, create it, or append to the file
    if f, err = os.OpenFile("all.csv", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err != nil {
        log.Fatal(err)
    }
    defer func() {
        if err := f.Close(); err != nil {
            log.Fatal("error", err)
        }
    }()

    var current *os.File
    if current, err = os.OpenFile("current.csv", os.O_RDONLY, 0); err != nil {
        log.Fatal("error", err)
    }

    defer func() {
        if err := current.Close(); err != nil {
            log.Fatal("error", err)
        }
    }()

    if fileBytes, err := ioutil.ReadAll(current); err != nil {
        log.Fatal("error", err)
    } else {
        if _, err := f.Write([]byte(fileBytes)); err != nil {
            log.Fatal(err)
        }
    }
}
Hasan A Yousef
  • 22,789
  • 24
  • 132
  • 203