1.读取用户的输入
从键盘和标准输入 os.Stdin 读取输入,最简单的办法是使用 fmt 包提供的 Scan 和 Sscan 开头的函数
Scanln 扫描来自标准输入的文本,将空格分隔的值依次存放到后续的参数内,直到碰到换行。
Scanf 与其类似,除了 Scanf 的第一个参数用作格式字符串,用来决定如何读取。Sscan 和以 Sscan 开头的函数则是从字符串读取,除此之外,与 Scanf 相同。
package main
import "fmt"
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 ful name: ")
fmt.Scanln(&firstName, &lastName)
//fmt.Scanf("%s %s", &firstName, &lastName)
fmt.Printf("hi %s %s\n", firstName, lastName)
fmt.Sscanf(input, format, &f, &i, &s)
fmt.Println("from the strin we read: ", f, i, s)
}
可以使用 bufio 包提供的缓冲读取(buffered reader)来读取数据
Unix和Linux的行结束符是 \n,而Windows的行结束符是 \r\n。
package main
import (
"bufio"
"fmt"
"os"
)
var inputReader *bufio.Reader
var input string
var err error
func main() {
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)
}
}
2.文件读写
读取文件方式汇总
读:bufio.NewReader(inputFile).ReadString('\n')
buf, err := ioutil.ReadFile("in.txt")
bufio.Reader.Read(buf)
写:os.OpenFile("out.txt", os.O_WRONLY|os.O_CREATE, 0666)
bufio.NewWriter(outputFile).WriteString(outputStr)
fmt.Fprintf(outputFile, “Some test data.\n”)
os.OpenFile("test", os.O_CREATE|os.O_WRONLY, 0).WriteString(outputStr)
ioutil.WriteFile(outputFile, buf, 0644)
读文件
文件使用指向 os.File 类型的指针来表示的,也叫做文件句柄
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main() {
inputFile, inputError := os.Open("fileinput/1.txt")
if inputError != nil {
fmt.Println("file error", inputError)
return
}
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
}
}
}
将整个文件的内容读到一个字符串里:
使用 io/ioutil 包里的 ioutil.ReadFile() 方法,该方法第一个返回值的类型是 []byte,里面存放读取到的内容,第二个返回值是错误,如果没有错误发生,第二个返回值为 nil。类似的,函数 WriteFile() 可以将 []byte 的值写入文件。
package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
inputFile := "from.txt"
outputFile := "out.txt"
buf, err := ioutil.ReadFile(inputFile)
if err != nil {
fmt.Fprintf(os.Stderr, "file error : %s \n", err)
}
fmt.Println(string(buf))
err = ioutil.WriteFile(outputFile, buf, 0644)
if err != nil {
panic(err.Error())
}
}
带缓冲的读取
buf := make([]byte, 1024)
...
n, err := inputReader.Read(buf)
if (n == 0) { break}
按列读取文件中的数据
package main
import (
"fmt"
"os"
)
func main() {
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)
}
fmt.Println(col1)
fmt.Println(col2)
fmt.Println(col3)
}
练习:
文件 products.txt 的内容如下:
"The ABC of Go";25.5;1500
"Functional Programming with Go";56;280
"Go for It";45.9;356
"The Go Way";55;500
每行的第一个字段为 title,第二个字段为 price,第三个字段为 quantity。内容的格式基本与 示例 12.3c 的相同,除了分隔符改成了分号。请读取出文件的内容,创建一个结构用于存取一行的数据,然后使用结构的切片,并把数据打印出来。
package main
import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
)
type product struct {
title string
price float64
quantity int
}
func main() {
file, err := os.Open("from.txt")
if err != nil {
fmt.Println(err)
}
defer file.Close()
var products []product
reader := bufio.NewReader(file)
for {
readString, readerErr := reader.ReadString('\n')
readString = strings.TrimSpace(readString)
split := strings.Split(readString, ";")
fmt.Println(readString)
p, _ := strconv.ParseFloat(split[1], 32)
fmt.Println("p ", p)
q, _ := strconv.Atoi(split[2])
fmt.Println("q ", q)
pr := product{split[0], p, q}
products = append(products, pr)
if readerErr == io.EOF {
break
}
}
fmt.Println(products)
}
compress包:读取压缩文件
有需要再学
写文件
我们通常会用到以下标志:
- os.O_RDONLY:只读
- os.O_WRONLY:只写
- os.O_CREATE:创建:如果指定文件不存在,就创建该文件。
- os.O_TRUNC:截断:如果指定文件已存在,就将该文件的长度截为0。
1)除了文件句柄,我们还需要 bufio 的 Writer。我们以只写模式打开文件 output.dat,如果文件不存在则自动创建
缓冲区的内容紧接着被完全写入文件:outputWriter.Flush()
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
outputFile, outputError := os.OpenFile("out.txt", os.O_WRONLY|os.O_CREATE, 0666)
if outputError != nil {
fmt.Println(outputError)
return
}
defer outputFile.Close()
outputWriter := bufio.NewWriter(outputFile)
outputStr := "你好 world\n"
for i := 0; i < 10; i++ {
outputWriter.WriteString(outputStr)
}
outputWriter.Flush()
}
2)如果写入的东西很简单,我们可以使用 fmt.Fprintf(outputFile, “Some test data.\n”) 直接将内容写入文件。fmt 包里的 F 开头的 Print 函数可以直接写入任何 io.Writer,包括文件
3)不使用缓冲区,直接将内容写入文件:f.WriteString( )
f, _ := os.OpenFile("test", os.O_CREATE|os.O_WRONLY, 0)
defer f.Close()
f.WriteString("hello, world in a file\n")
4)ioutil.WriteFile(outputFile, buf, 0644)
3.文件拷贝
如何拷贝一个文件到另一个文件?最简单的方式就是使用 io 包:io.Copy
package main
import (
"fmt"
"io"
"os"
)
func main() {
file, err := CopyFile("out.txt", "from.txt")
if err != nil {
fmt.Println(err)
}
fmt.Println(file)
}
func CopyFile(dstName, sourceName string) (written int64, err error) {
source, err := os.Open(sourceName)
if err != nil {
return
}
defer source.Close()
dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, source)
}
4.从命令行读取参数
这个命令行参数会放置在切片 os.Args[] 中(以空格分隔),从索引1开始(os.Args[0] 放的是程序本身的名字,在本例中是 os_args)。函数 strings.Join 以空格为间隔连接这些参数。
package main
import (
"fmt"
"os"
"strings"
)
func main() {
who := "Alice"
if len(os.Args) > 1 {
who += strings.Join(os.Args[1:], " ")
}
fmt.Println("good morning", who)
}
flag包
flag.Parse() 扫描参数列表(或者常量列表)并设置 flag, flag.Arg(i) 表示第i个参数。
flag.Parse() 扫描参数列表(或者常量列表)并设置 flag, flag.Arg(i) 表示第i个参数。
flag.Bool() 定义了一个默认值是 false 的 flag:当在命令行出现了第一个参数(这里是 “n”),flag 被设置成 true(NewLine 是 bool 类型)。flag 被解引用到 NewLine,所以当值是 true 时将添加一个 newline(”\n”)。
flag.PrintDefaults() 打印 flag 的使用帮助信息。
flag.VisitAll(fn func(*Flag)) 是另一个有用的功能:按照字典顺序遍历 flag,并且对每个标签调用 fn。
package main
import (
"flag"
"os"
)
var NewLine = flag.Bool("n", false, "print newLine")
const (
Space = " "
Newline = "\n"
)
func main() {
flag.PrintDefaults()
flag.Parse() //扫描参数列表并且建立flags
var s string = ""
for i := 0; i < flag.NArg(); i++ {
if i > 0 {
s += " "
if *NewLine {
s += Newline
}
}
s += flag.Arg(i)
}
os.Stdout.WriteString(s)
}
go run .\echo.go -n 1 2 3
-n print newLine
1
2
3go run .\echo.go 1 2 3
-n print newLine
1 2 3
4.用buffer读文件
参数被认为是文件名,如果文件存在的话就打印文件内容到屏幕。
package main
import (
"bufio"
"flag"
"fmt"
"io"
"os"
)
func cat(r *bufio.Reader) {
for {
buf, err := r.ReadBytes('\n')
if err == io.EOF {
break
}
fmt.Fprintf(os.Stdout, "%s", buf)
}
return
}
func main() {
flag.Parse()
if flag.NArg() == 0 {
cat(bufio.NewReader(os.Stdin))
}
for i := 0; i < flag.NArg(); i++ {
f, err := os.Open(flag.Arg(i))
if err != nil {
fmt.Fprintf(os.Stderr, "%s:error reading from %s: %s\n", os.Args[0], flag.Arg(i), err.Error())
continue
}
cat(bufio.NewReader(f))
}
}
5.用切片读取文件
package main
import (
"flag"
"fmt"
"os"
)
func cat(f *os.File) {
const NBUF = 512
var buf [NBUF]byte
for {
switch nr, err := f.Read(buf[:]); true {
case nr < 0:
fmt.Fprint(os.Stderr, "cat: error reading: %s\n", err.Error())
os.Exit(1)
case nr == 0:
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())
}
}
}
}
func main() {
flag.Parse()
if flag.NArg() == 0 {
cat(os.Stdin)
}
for i := 0; i < flag.NArg(); i++ {
f, err := os.Open(flag.Arg(i))
if f == nil {
fmt.Fprintf(os.Stderr, "cat: can't open %s: error %s\n", flag.Arg(i), err.Error())
os.Exit(1)
}
cat(f)
f.Close()
}
}
使用接口的实际例子:fmt.Fprintf
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
//os.Stdout.WriteString("abcd")
fmt.Fprintf(os.Stdout, "%s\n", "hello world - unbuffered")
buf := bufio.NewWriter(os.Stdout)
fmt.Fprintf(buf, "%s\n", "hello world - buffered")
buf.Flush()
}
fmt.Fprintf() 函数的实际签名func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
io.Writer 是接口类型
type Writer interface {
Write(p []byte) (n int, err error)
}
bufio.Writer 实现了 Write 方法:func (b *Writer) Write(p []byte) (nn int, err error)
它还有一个工厂函数:传给它一个 io.Writer 类型的参数,它会返回一个缓冲的 bufio.Writer 类型的 io.Writer:func NewWriter(wr io.Writer) (b *Writer)