GoLang读写数据---中
Posted 大忽悠爱忽悠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GoLang读写数据---中相关的知识,希望对你有一定的参考价值。
GoLang读写数据---中
文件拷贝
如何拷贝一个文件到另一个文件?最简单的方式就是使用 io 包:
// filecopy.go
package main
import (
"fmt"
"io"
"os"
)
func main()
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)
注意 defer
的使用:当打开dst文件时发生了错误,那么 defer
仍然能够确保 src.Close()
执行。如果不这么做,src文件会一直保持打开状态并占用资源。
从命令行读取参数
os 包中有一个 string 类型的切片变量 os.Args
,用来处理一些基本的命令行参数,它在程序启动后读取命令行输入的参数。来看下面的打招呼程序:
package main
import (
"fmt"
"os"
"strings"
)
func main()
var who string
if len(os.Args) > 1
who += strings.Join(os.Args[1:], ",")
fmt.Println("你好 ", who)
这个命令行参数会放置在切片 os.Args[] 中(以空格分隔),从索引1开始(os.Args[0] 放的是程序本身的名字,在本例中是 os_args)。函数 strings.Join 以空格为间隔连接这些参数。
flag 包
不管是在linux还是windows下,都支持在程序运行的情况下传递命令行参数。如:
./demo -i 10 -b=true
关于如何将命令行的参数取出来,我们可以通过os包来实现。
通过range os.Args,我们可以取出所有的命令行参数,但是这种方法存在一定的局限性。这种方法没有将每一个参数的标志和其值映射起来(对于./demo -i 10 -b=true来说,-i是参数的标志,10是该标志的值)。
flag包相比os提供的取命令行参数方法相比,flag包在取命令行参数时可以将每个标志和其值做映射,将特定标志的参数值放入我们期望的变量中。
实例演示
在 flag 包中有一个 Flag 被定义成一个含有如下字段的结构体:
type Flag struct
Name string // key
Usage string // 帮助信息
Value Value // 用户输入的值
DefValue string //默认值
- flag.Parse函数
这个函数中做的内容比较多。取输入的命令行参数,在其中一一检测之前已绑定的检测标志。如果找到标志,将其值存入对应的变量。如果一切正常,往后执行。如果检测到不在待检测集合中的标志,则打印Usage信息,退出程序。
flag.Arg(0) 就是第一个真实的 flag,而不是像 os.Args(0) 放置程序的名字。
i.为检测标志指定存放变量系列函数
①StringVar(&val, "val","default val","usage note")
②StringInt(&val, "val",default val,"usage note")
③StringBool(&val, "val",default val,"usage note")
以StringVar(&val, "val","default val","usage note")为例,
参数1:&val,存放标志值的变量
参数2:"val",待检测的标志
参数3:"default val",标志的默认值
参数4:"usage note",用法信息,当检测异常时打印该信息提示命令行参数的使用方法
其他雷同
ii.定义存放指定检测标志值的变量
①String("val","default val","usage note")
②Int("val",default val,"usage note")
③Bool("val",default val,"usage note")
和i系列的区别点:
s := flag.String("s","defalut val","字符串")
等价于:
var s string
flag.StringVar(&s,"s","default val","字符串")
实例:
package main
import (
"flag"
"fmt"
)
//用来存放命令行参数
var (
name string
age int
addr string
)
//flag参数初始化,将flag绑定各个存放命令行参数的变量
func FlagInit()
//我们需要通过flag检测命令行中的-name这个标志,那就需要告诉flag,1.需要取哪些标志;2.取出
//的标志放在哪里。通过flag包的StringVar、IntVar等函数就可以实现这种绑定。下同
flag.StringVar(&name, "name", "匿名", "你的姓名")
flag.IntVar(&age, "age", -1, "你的年龄")
flag.StringVar(&addr, "addr", "杭州", "你的地址")
func main()
//在flag.Parse()之前必须先要做好绑定
FlagInit()
//Parse执行时,检测命令行中的各个标志。我们在FlagInit中已经绑定了name、age、addr这3个标
//志,Parse时就会从命令行参数中找这三个标志,并将对应的值保存在相应的变量中
flag.Parse()
fmt.Printf("%s你好,你的年龄是%d,你的地址是:%s\\n", name, age, addr)
return
用 buffer 读取文件
在下面的例子中,我们结合使用了缓冲读取文件和命令行 flag 解析这两项技术。如果不加参数,那么你输入什么屏幕就打印什么。
参数被认为是文件名,如果文件存在的话就打印文件内容到屏幕。命令行执行 cat test 测试输出。
package main
import (
"bufio"
"flag"
"fmt"
"io"
"os"
)
func cat(r *bufio.Reader)
for
buf, err := r.ReadBytes('\\n')
fmt.Fprintf(os.Stdout, "%s", buf)
if err == io.EOF
break
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))
f.Close()
用切片读写文件
切片提供了 Go 中处理 I/O 缓冲的标准方式,下面 cat 函数的第二版中,在一个切片缓冲内使用无限 for 循环(直到文件尾部 EOF)读取文件,并写入到标准输出(os.Stdout)。
func cat(f *os.File)
const NBUF = 512
var buf [NBUF]byte
for
switch nr, err := f.Read(buf[:]);
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())
对于函数的返回值含义,大家可以参考源码注释
如果结合flag包使用,效果如下:
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.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())
func main()
flag.Parse() // Scans the arg list and sets up flags
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)
os.Exit(1)
cat(f)
f.Close()
使用接口的实际例子:fmt.Fprintf
// interfaces being used in the GO-package fmt
package main
import (
"bufio"
"fmt"
"os"
)
func main()
// 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()
输出:
hello world! - unbuffered
hello world! - buffered
下面是 fmt.Fprintf()
函数的实际签名
func Fprintf(w io.Writer, format string, a ...interface) (n int, err error)
其不是写入一个文件,而是写入一个 io.Writer
接口类型的变量,下面是 Writer
接口在 io
包中的定义:
type Writer interface
Write(p []byte) (n int, err error)
fmt.Fprintf() 依据指定的格式向第一个参数内写入字符串,第一个参数必须实现了 io.Writer 接口。Fprintf() 能够写入任何类型,只要其实现了 Write 方法,包括 os.Stdout,文件(例如 os.File),管道,网络连接,通道等等,同样的也可以使用 bufio 包中缓冲写入。bufio 包中定义了 type Writer struct…。
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)
其适合任何形式的缓冲写入。
在缓冲写入的最后千万不要忘了使用 Flush(),否则最后的输出不会被写入。
以上是关于GoLang读写数据---中的主要内容,如果未能解决你的问题,请参考以下文章
golang中接口interface和struct结构类的分析
Golang面经ChannelContextGoroutine