1.读取用户的输入
从键盘和标准输入 os.Stdin 读取输入,最简单的办法是使用 fmt 包提供的 Scan 和 Sscan 开头的函数
Scanln 扫描来自标准输入的文本,将空格分隔的值依次存放到后续的参数内,直到碰到换行。
Scanf 与其类似,除了 Scanf 的第一个参数用作格式字符串,用来决定如何读取。Sscan 和以 Sscan 开头的函数则是从字符串读取,除此之外,与 Scanf 相同。
package mainimport "fmt"var (firstName, lastName, s stringi intf float32input = "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 mainimport ("bufio""fmt""os")var inputReader *bufio.Readervar input stringvar err errorfunc 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 mainimport ("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 mainimport ("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 mainimport ("fmt""os")func main() {file, err := os.Open("products2.txt")if err != nil {panic(err)}defer file.Close()var col1, col2, col3 []stringfor {var v1, v2, v3 string_, err := fmt.Fscanln(file, &v1, &v2, &v3)// scans until newlineif 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 mainimport ("bufio""fmt""io""os""strconv""strings")type product struct {title stringprice float64quantity int}func main() {file, err := os.Open("from.txt")if err != nil {fmt.Println(err)}defer file.Close()var products []productreader := 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 mainimport ("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 mainimport ("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 mainimport ("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 mainimport ("flag""os")var NewLine = flag.Bool("n", false, "print newLine")const (Space = " "Newline = "\n")func main() {flag.PrintDefaults()flag.Parse() //扫描参数列表并且建立flagsvar 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 mainimport ("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 mainimport ("flag""fmt""os")func cat(f *os.File) {const NBUF = 512var buf [NBUF]bytefor {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:returncase 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 mainimport ("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)
