目录

读取用户输入

从控制台读取输入

var (
   firstName, lastName, s string
   i int
   f float32
   input = "56.12 / 5212 / Go"
   format = "%f / %d / %s"
)

func main() {
    fmt.Println("Please enter your full name: ")
    fmt.Scanln(&firstName, &lastName) // 将空格分隔的值依次存放到后续的参数内,直到碰到换行
    fmt.Printf("Hi %s %s!\n", firstName, lastName) // Hi Chris Naegels
    fmt.Scanf(format, &f, &i, &s) // 第一个参数用作格式字符串,用来决定如何读取
    
    fmt.Sscanf(input, format, &f, &i, &s) // 从字符串读取
    fmt.Println("read: ", f, i, s) // read: 56.12 5212 Go
}
var inputReader *bufio.Reader
var input string
var err error

func main() {
    // 函数返回一个新的带缓冲的 io.Reader 对象,它将从指定读取器(例如 os.Stdin)读取内容
    inputReader = bufio.NewReader(os.Stdin)
    fmt.Println("Please enter some input: ")
    // 从输入中读取内容,直到碰到指定的字符,然后将读取到的内容连同字符一起放到缓冲区。
    input, err = inputReader.ReadString('\n')
    if err == nil {
        fmt.Printf("The input was: %s\n", input)
    }
}

读文件

逐行读取出来

func main() {
    inputFile, inputError := os.Open("input.dat")
    if inputError != nil {
        fmt.Printf("An error occurred on opening the inputfile\n" +
            "Does the file exist?\n" +
            "Have you got acces to it?\n")
        return // exit the function on error
    }
    defer inputFile.Close()

    inputReader := bufio.NewReader(inputFile)
    for {
        inputString, readerError := inputReader.ReadString('\n')
        fmt.Printf("The input was: %s", inputString)
        if readerError == io.EOF { // 读取到文件末尾了
            return
        }      
    }
}

将整个文件的内容读取到一个字符串里

func main() {
    inputFile := "products.txt"
    outputFile := "products_copy.txt"
    buf, err := ioutil.ReadFile(inputFile)
    if err != nil {
        fmt.Fprintf(os.Stderr, "File Error: %s\n", err)
        // panic(err.Error())
    }
    fmt.Printf("%s\n", string(buf))
    err = ioutil.WriteFile(outputFile, buf, 0644) // oct, not hex
    if err != nil {
        panic(err.Error())
    }
}

在很多情况下,文件的内容是不按行划分的,或者干脆就是一个二进制文件。在这种情况下,ReadString()就无法使用了,我们可以使用 bufio.ReaderRead(),它只接收一个参数:

buf := make([]byte, 1024)
...
n, err := inputReader.Read(buf)
if (n == 0) { break}

在一个切片缓冲内使用无限 for 循环(直到文件尾部 EOF)读取文件,并写入到标准输出(os.Stdout

func cat(f *os.File) {
    const NBUF = 512
    var buf [NBUF]byte
    for {
        switch nr, err := f.Read(buf[:]); true {
        case nr < 0:
            fmt.Fprintf(os.Stderr, "cat: error reading: %s\n", err.Error())
            os.Exit(1)
        case nr == 0: // EOF
            return
        case nr > 0:
            if nw, ew := os.Stdout.Write(buf[0:nr]); nw != nr {
                fmt.Fprintf(os.Stderr, "cat: error writing: %s\n", ew.Error())
            }
        }
    }
}

按列读取

如果数据是按列排列并用空格分隔的,你可以使用 fmt 包提供的以 FScan 开头的一系列函数来读取他们

file, err := os.Open("products2.txt")
if err != nil {
    panic(err)
}
defer file.Close()

var col1, col2, col3 []string
for {
    var v1, v2, v3 string
    _, err := fmt.Fscanln(file, &v1, &v2, &v3)
    // scans until newline
    if err != nil {
        break
    }
    col1 = append(col1, v1)
    col2 = append(col2, v2)
    col3 = append(col3, v3)
}

获得路径中的最后一个元素(不包含后面的分隔符):

import "path/filepath"
filename := filepath.Base(path)

读取一个 gzip 文件

func main() {
    fName := "MyFile.gz"
    var r *bufio.Reader
    fi, err := os.Open(fName)
    if err != nil {
        fmt.Fprintf(os.Stderr, "%v, Can't open %s: error: %s\n", os.Args[0], fName,
            err)
        os.Exit(1)
    }
    defer fi.Close()
    fz, err := gzip.NewReader(fi)
    if err != nil {
        r = bufio.NewReader(fi)
    } else {
        r = bufio.NewReader(fz)
    }

    for {
        line, err := r.ReadString('\n')
        if err != nil {
            fmt.Println("Done reading file")
            os.Exit(0)
        }
        fmt.Println(line)
    }
}

写入文件

// var outputWriter *bufio.Writer
// var outputFile *os.File
// var outputError os.Error
// var outputString string
outputFile, outputError := os.OpenFile("output.dat", os.O_WRONLY|os.O_CREATE, 0666)
if outputError != nil {
    fmt.Printf("An error occurred with file opening or creation\n")
    return  
}
defer outputFile.Close()

outputWriter := bufio.NewWriter(outputFile)
outputString := "hello world!\n"

for i:=0; i<10; i++ {
    outputWriter.WriteString(outputString)
}
outputWriter.Flush()
  • os.O_RDONLY:只读

  • os.O_WRONLY:只写

  • os.O_CREATE:创建:如果指定文件不存在,就创建该文件。

  • os.O_TRUNC:截断:如果指定文件已存在,就将该文件的长度截为0。

    os.Stdout.WriteString("hello, world\n") // 输出到屏幕
    f, _ := os.OpenFile("test", os.O_CREATE|os.O_WRONLY, 0666)
    defer f.Close()
    f.WriteString("hello, world in a file\n") // 我们不使用缓冲区,直接将内容写入文件

文件拷贝

CopyFile("target.txt", "source.txt")
    fmt.Println("Copy done!")
}

func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()

dst, err := os.Create(dstName)
if err != nil {
return
}
defer dst.Close()

return io.Copy(dst, src)

从命令行读取参数

who := "Alice "
if len(os.Args) > 1 {
who += strings.Join(os.Args[1:], " ")
}
fmt.Println("Good Morning", who)

flag 包有一个扩展功能用来解析命令行选项。但是通常被用来替换基本常量,例如,在某些情况下我们希望在命令行给常量一些不一样的值。

Fprintf

type Writer interface {
    Write(p []byte) (n int, err error)
}
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)

// unbuffered
fmt.Fprintf(os.Stdout, "%s\n", "hello world! - unbuffered")
// buffered: os.Stdout implements io.Writer
buf := bufio.NewWriter(os.Stdout)
// and now so does buf.
fmt.Fprintf(buf, "%s\n", "hello world! - buffered")
buf.Flush()