miner
miner

Reputation: 305

Trying to write input from keyboard into a file in Golang

I am trying to take input from the keyboard and then store it in a text file but I am a bit confused on how to actually do it.

My current code is as follow at the moment:

// reads the file txt.txt 
bs, err := ioutil.ReadFile("text.txt")
if err != nil {
      panic(err)
}

// Prints out content
textInFile := string(bs)
fmt.Println(textInFile)

// Standard input from keyboard
var userInput string
fmt.Scanln(&userInput)

//Now I want to write input back to file text.txt
//func WriteFile(filename string, data []byte, perm os.FileMode) error

inputData := make([]byte, len(userInput))

err := ioutil.WriteFile("text.txt", inputData, )

There are so many functions in the "os" and "io" packages. I am very confused about which one I actually should use for this purpose.

I am also confused about what the third argument in the WriteFile function should be. In the documentation is says of type " perm os.FileMode" but since I am new to programming and Go I am a bit clueless.

Does anybody have any tips on how to proced? Thanks in advance, Marie

Upvotes: 7

Views: 6795

Answers (3)

nemo
nemo

Reputation: 57747

If you simply want to append the user's input to a text file, you could just read the input as you've already done and use ioutil.WriteFile, as you've tried to do. So you already got the right idea.

To make your way go, the simplified solution would be this:

// Read old text
current, err := ioutil.ReadFile("text.txt")

// Standard input from keyboard
var userInput string
fmt.Scanln(&userInput)

// Append the new input to the old using builtin `append`
newContent := append(current, []byte(userInput)...)

// Now write the input back to file text.txt
err = ioutil.WriteFile("text.txt", newContent, 0666)

The last parameter of WriteFile is a flag which specifies the various options for files. The higher bits are options like file type (os.ModeDir, for example) and the lower bits represent the permissions in form of UNIX permissions (0666, in octal format, stands for user rw, group rw, others rw). See the documentation for more details.

Now that your code works, we can improve it. For example by keeping the file open instead of opening it twice:

// Open the file for read and write (O_RDRW), append to it if it has
// content, create it if it does not exit, use 0666 for permissions
// on creation.
file, err := os.OpenFile("text.txt", os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)

// Close the file when the surrounding function exists
defer file.Close()

// Read old content
current, err := ioutil.ReadAll(file)

// Do something with that old content, for example, print it
fmt.Println(string(current))

// Standard input from keyboard
var userInput string
fmt.Scanln(&userInput)

// Now write the input back to file text.txt
_, err = file.WriteString(userInput)

The magic here is, that you use the flag os.O_APPEND while opening the file, which makes file.WriteString() append. Note that you need to close the file after opening it, which we do after the function exists using the defer keyword.

Upvotes: 3

peterSO
peterSO

Reputation: 166885

For example,

package main

import (
    "fmt"
    "io/ioutil"
    "os"
)

func main() {
    fname := "text.txt"

    // print text file
    textin, err := ioutil.ReadFile(fname)
    if err == nil {
        fmt.Println(string(textin))
    }

    // append text to file
    f, err := os.OpenFile(fname, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
    if err != nil {
        panic(err)
    }
    var textout string
    fmt.Scanln(&textout)
    _, err = f.Write([]byte(textout))
    if err != nil {
        panic(err)
    }
    f.Close()

    // print text file
    textin, err = ioutil.ReadFile(fname)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(textin))
}

Upvotes: 3

matthias
matthias

Reputation: 2499

// reads the file txt.txt 
bs, err := ioutil.ReadFile("text.txt")
if err != nil { //may want logic to create the file if it doesn't exist
      panic(err)
}

var userInput []string

var err error = nil
var n int
//read in multiple lines from user input
//until user enters the EOF char
for ln := ""; err == nil; n, err = fmt.Scanln(ln) {
    if n > 0 {  //we actually read something into the string
        userInput = append(userInput, ln)
    } //if we didn't read anything, err is probably set
}

//open the file to append to it
//0666 corresponds to unix perms rw-rw-rw-,
//which means anyone can read or write it
out, err := os.OpenFile("text.txt", os.O_APPEND, 0666)
defer out.Close() //we'll close this file as we leave scope, no matter what

if err != nil { //assuming the file didn't somehow break
    //write each of the user input lines followed by a newline
    for _, outLn := range userInput {
        io.WriteString(out, outLn+"\n")
    }
}

I've made sure this compiles and runs on play.golang.org, but I'm not at my dev machine, so I can't verify that it's interacting with Stdin and the file entirely correctly. This should get you started though.

Upvotes: 3

Related Questions