zoukankan      html  css  js  c++  java
  • Go语言基础之15--文件基本操作

    一、文件读写

    1.1 os.File

    os.File封装所有文件相关操作, 是一个自定义的struct。

    a. 打开一个文件进行读操作: os.Open(name string) (*File, error)

    Open是以读的方式打开文件(底层调用的是Openfile函数)。

    b. 关闭一个文件: File.Close()

    1.2 文件操作简单实例

     示例1:

    package main
    
    import (
        "fmt"
        "io" //读取文件末尾特殊情况需要用到
        "os" //读取文件需要用到
    )
    
    func main() {
        filename := "c:/tmp.txt"
        file, err := os.Open(filename) //返回2个参数,第一个file指针,第二个错误值
        if err != nil {                //如果打开文件有错误,在这里输出
            fmt.Printf("open %s failed,err:%v
    ", filename, err)
            return
        }
        defer func() { //打开一个文件,最后我们必须要将其关闭
            file.Close()
        }()
    
        var content []byte //定义1个变量存读取到的所有数据
        var buf [4096]byte //定义一个4k的字节数组,每次读取一点,4k读性能高
        for {
            n, err := file.Read(buf[:])      //将整个数组转换成切片读进去,Read函数返回2个参数,第1个n是读到的字节数,第二个是err
            if err != nil && err != io.EOF { //有一个特殊问题,当一个文件读读完,遇到文件末尾时,它也会返回一个错误,但是此时我已经读到文件末尾EOF,这个错误应该不算错误,所以应该把读到文件末尾这个错误给去掉。
                fmt.Printf("read %s failed, err:%v
    ", filename, err)
                return //如果有错误就返回
            }
    
            if err == io.EOF {
                break //如果读取到文件末尾了,直接break退出。
            }
    
            vaildBuf := buf[0:n] //把有效数据都拿出来,不可能整个buf数组都是有效数据(最后一次读取到是很大可能是占据数组的一部分。),这里我们就需要借助切片。
            //fmt.Printf("%s
    ", string(vaildBuf))
            content = append(content, vaildBuf...) //将有效的数据存到定义的变量切片中,另外将一个切片append到另一个切片中用...
        }
        fmt.Printf("content:%s
    ", content)
    }

     执行结果:

    示例2:

    通过函数传参

    package main
    
    import (
        "fmt"
        "io"
        "os"
    )
    
    func Read(filename string) (string, error) {
        //获得一个file
        f, err := os.Open(filename)
        if err != nil {
            fmt.Println("read fail")
            return "", err
        }
    
        //把file读取到缓冲区中
        defer f.Close()
        var content []byte
        var buf [1024]byte
        for {
            //从file读取到buf中, n表示本次读到的字节数
            n, err := f.Read(buf[:])
            if err != nil && err != io.EOF {
                fmt.Println("read buf fail", err)
                return "", err
            }
            //说明读取结束
            if err == io.EOF {
                break
            }
            //读取到最终的缓冲区中
            content = append(content, buf[:n]...)
        }
        fmt.Printf("content:%s
    ", content)
        return string(content), nil
    }
    
    func main() {
        a := "c:/tmp.txt"
        Read(a)
    }

     执行结果:

    1.3 使用bufio提高文件读取性能

    之前我们是直接从文件读,因为读取文件是一个相对比较慢的操作,所以当我们读一个大的文件时,或者又多次io操作时会影响性能,所以我们使用bufio(缓存机制,跟redis(缓存)有点类似,可以把文件操作类比成数据库操作)提高文件读取性能。

    bufio包go语言已经帮我们封装好了。

    bufio包总结如下:

    1)bufio 包实现了带缓存的 I/O 操作

    2)它封装一个 io.Reader 或 io.Writer 对象

    3)使其具有缓存和一些文本读写功能

    参考网址:https://blog.csdn.net/wangshubo1989/article/details/70177928

    代码示例1:

    package main
    
    import (
        "bufio"
        "fmt"
        "io"
        "os"
    )
    
    func main() {
        filename := "c:/tmp.txt"
        file, err := os.Open(filename) //返回2个参数,第一个file指针,第二个错误值
        if err != nil {                //如果打开文件有错误,在这里输出
            fmt.Printf("open %s failed,err:%v
    ", filename, err)
            return
        }
        defer func() { //打开一个文件,最后我们必须要将其关闭
            file.Close()
        }()
    
        reader := bufio.NewReader(file) //要封装这个文件读写,需要把文件传到bufio里面去,然后在bufio里面操作这个缓存,这里我们传的是file文件对象
        //为什么要传一个文件对象进去?   答:首先看缓存里有么有,有就读缓存,没有的话就用文件去读,也就是file这个文件对象(是一个结构体,里面包含很多用法)
        var content []byte //定义1个变量存读取到的所有数据
        var buf [4096]byte //定义一个4k的字节数组,每次读取一点,4k读性能高
        for {
            n, err := reader.Read(buf[:])    //将整个数组转换成切片读进去,Read函数返回2个参数,第1个n是读到的字节数,第二个是err
            if err != nil && err != io.EOF { //有一个特殊问题,当一个文件读读完,遇到文件末尾时,它也会返回一个错误,但是此时我已经读到文件末尾EOF,这个错误应该不算错误,所以应该把读到文件末尾这个错误给去掉。
                fmt.Printf("read %s failed, err:%v
    ", filename, err)
                return //如果有错误就返回
            }
    
            if err == io.EOF {
                break //如果读取到文件末尾了,直接break退出。
            }
    
            vaildBuf := buf[0:n] //把有效数据都拿出来,不可能整个buf数组都是有效数据(最后一次读取到是很大可能是占据数组的一部分。),这里我们就需要借助切片。
            //fmt.Printf("%s
    ", string(vaildBuf))
            content = append(content, vaildBuf...) //将有效的数据存到定义的变量切片中,另外将一个切片append到另一个切片中用...
        }
        fmt.Printf("content:%s
    ", content)
    }

     执行结果:

     

    代码示例2:函数传参

    package main
    
    import (
        "bufio"
        "fmt"
        "io"
        "os"
    )
    
    func Read(filename string) (string, error) {
        fi, err := os.Open(filename)
        if err != nil {
            return "", err
        }
        defer fi.Close()
        r := bufio.NewReader(fi)
        var content []byte
        var buf [1024]byte
        for {
            n, err := r.Read(buf[:])
            if err != nil && err != io.EOF {
                return "", err
            }
            if err == io.EOF {
                break
            }
            content = append(content, buf[:n]...)
        }
        fmt.Printf("content:%s
    ", content)
        return string(content), nil
    }
    
    func main() {
        a := "c:/tmp.txt"
        Read(a)
    }

     执行结果:

    1.4 使用ioutil读取整个文件

    针对小文件读取,十分方便

    代码示例:

    package main
    
    import (
        "fmt"
        "io/ioutil"
    )
    
    func main() {
        filename := "c:/tmp.txt"
        content, err := ioutil.ReadFile(filename)
        if err != nil {
            fmt.Printf("read file %s failed, err:%v
    ", filename, err)
            return
        }
        fmt.Printf("content:%s
    ", string(content))  //因为上面返回的是一个字节数组,所以必须转一下
    }

    执行结果:

     

    代码示例2:使用函数传参

    package main
    
    import (
        "fmt"
        "io/ioutil"
    )
    
    func Read(filename string) (string, error) {
        content, err := ioutil.ReadFile(filename)
        if err != nil {
            return "", err
        }
        fmt.Printf("content:%s
    ", content)
        return string(content), nil
    }
    
    func main() {
        a := "c:/tmp.txt"
        Read(a)
    }

     执行结果:

    1.5 读取压缩文件示例

    gizp就相当于read,gzip使用传进去的文件对象去读取文件内容,解压完了在将数据返回。

    下面我们通过几个例子来验证一系列理论

    1.5.1 bufio读取压缩文件结果

    package main
    
    import (
        "bufio"
        "fmt"
        "io"
        "os"
    )
    
    func main() {
        fmt.Printf("start run...
    ")
    
        filename := "c:/tmp.txt.gz"
        file, err := os.Open(filename)
        if err != nil {
            fmt.Printf("open %s failed, err:%v
    ", filename, err)
            return
        }
        fmt.Printf("start0 read file
    ")
        defer file.Close()
    
        reader := bufio.NewReader(file) 
        var content []byte 
        var buf [4096]byte 
        for {
            n, err := reader.Read(buf[:])   
            if err != nil && err != io.EOF { 
                fmt.Printf("read %s failed, err:%v
    ", filename, err)
                return
            }
    
            if err == io.EOF {
                break
            }
    
            vaildBuf := buf[0:n] 
            content = append(content, vaildBuf...) 
        }
        fmt.Printf("content:%s
    ", content)
    }

     执行结果:

    解释:

    可以看到用bufio读取到的是压缩文件的二进制代码,也是乱码的。

    1.5.2 读取压缩文件出现问题

    这个问题目前只有读取压缩文件的实例存在,直接读取、bufio、ioutil都不存在这个问题,下面我们通过实例来演示一下。

    package main
    
    import (
        _ "bufio"
        "compress/gzip" //gzip要用到
        "fmt"
        "io"
        "os"
    )
    
    func main() {
        fmt.Printf("start run...
    ")
    
        filename := "c:/tmp.txt.gz"
        file, err := os.Open(filename)
        if err != nil {
            fmt.Printf("open %s failed, err:%v
    ", filename, err)
            return
        }
        fmt.Printf("start0 read file
    ")
        defer file.Close()
        /*
            defer func() {
                file.Close()
            }()
        */
    
        reader, err := gzip.NewReader(file) //用gzip构建文件对象,reader就变成了一个读对象
        if err != nil {
            fmt.Printf("gzip read failed, err:%v
    ", err)
            return
        }
    
        var content []byte
        var buf [100]byte
        for {
            //reader.Read
            fmt.Printf("start read file
    ")
            n, err := reader.Read(buf[:])
            fmt.Printf("read %d  err:%v
    ", n, err)
            if err != nil && err != io.EOF {
                fmt.Printf("read %s failed, err:%v
    ", filename, err)
                return
            }
    
            //读到文件末尾了,文件已经读取完毕,Read方法会返回一个io.EOF错误。
            if err == io.EOF {
                break
            }
            validBuf := buf[0:n]
            content = append(content, validBuf...)
        }
    
        fmt.Printf("content:%s
    ", content)
    }

     执行结果:

    解释:

    可以发现出现了一个严重问题就是当我们每次读取100字节,分多次读取,会出现最后一次读取不到100字节(是52字节),但是err确是EOF,这个时候按照我们上面代码就会break退出,而此次读取到的52字节也会随之丢失,最终实际的结果也是造成了数据丢失。

    1.5.3 读取压缩文件完整代码(解决文件丢失问题)

    package main
    
    import (
        _ "bufio"
        "compress/gzip" //gzip要用到
        "fmt"
        "io"
        "os"
    )
    
    func main() {
        fmt.Printf("start run...
    ")
    
        filename := "c:/tmp.txt.gz"
        file, err := os.Open(filename)
        if err != nil {
            fmt.Printf("open %s failed, err:%v
    ", filename, err)
            return
        }
        fmt.Printf("start0 read file
    ")
        defer file.Close()
        /*
            defer func() {
                file.Close()
            }()
        */
    
        reader, err := gzip.NewReader(file) //用gzip构建文件对象,reader就变成了一个读对象
        if err != nil {
            fmt.Printf("gzip read failed, err:%v
    ", err)
            return
        }
    
        //reader := bufio.NewReader(file)
        var content []byte
        var buf [100]byte
        for {
            //reader.Read
            fmt.Printf("start read file
    ")
            n, err := reader.Read(buf[:])
            fmt.Printf("read %d  err:%v
    ", n, err)
            if err != nil && err != io.EOF {
                fmt.Printf("read %s failed, err:%v
    ", filename, err)
                return
            }
    
            if n > 0 { //做一个判断,只要有字节就追加到储存读取到内容的切片
                validBuf := buf[0:n]
                content = append(content, validBuf...)
            }
    
            //读到文件末尾了,文件已经读取完毕,Read方法会返回一个io.EOF错误。
            if err == io.EOF {
                break
            }
        }
    
        fmt.Printf("content:%s
    ", content)
    }

     执行结果:

    因输出结果太长,此处截图只截取部分内容。

    解释:

    通过对读取的字节数进行判断,避免了数据丢失的问题。

    1.5.4 补充

    下面实例有部分用法可能会有疑问,但是写法比较标准,可以学习借鉴。

    package main
    
    import (
        "bufio"
        "compress/gzip"
        "fmt"
        "os"
    )
    
    func main() {
        fName := "c:/tmp.txt.gz"
        var r *bufio.Reader
        fi, err := os.Open(fName)
        if err != nil {
            fmt.Fprintf(os.Stderr, "%v, Can’t open %s: error: %s
    ", os.Args[0], fName, err)
            os.Exit(1)
        }
        fz, err := gzip.NewReader(fi)
        if err != nil {
            fmt.Fprintf(os.Stderr, "open gzip failed, err: %v
    ", err)
            return
        }
        r = bufio.NewReader(fz)
        for {
            line, err := r.ReadString('
    ')
            if err != nil {
                fmt.Println("Done reading file")
                os.Exit(0)
            }
            fmt.Println(line)
        }
    }

    执行结果:

     

    解释:

    先用gizp解压,再用bufio缓存

    1.6 文件写入

    1)    os.OpenFile("filename",os.O_WRONLY|os.O_CREATE,066)

    第一个参数是文件名

    第二个参数是文件的打开模式:

    os.O_WRONLY:只写

    os.O_CREATE:创建文件

    os.O_RDONLY:只读

    os.O_RDWR:读写

    os.O_TRUNC:清空

    os.O_APPEND:文件存在以追加方式写入

    第三个参数:权限控制

    r-->4

    w-->2

    x-->1

    2)    os.Create("output.dat")

    用途:如果文件不存在需要先创建文件,用到的就是os.Create方法。(如果要创建的这个文件本来就存在,还要用Create(底层调用的Openfile函数)方法创建该文件,那么该文件就会被清空)

    1.7 文件写入实例

     示例1:

    package main
    
    import (
        "fmt"
        "os"
    )
    
    func isFileExists(filename string) bool { //判断文件是否存在
        _, err := os.Stat(filename) //os.Stat会返回文件是否存在的相关属性
        if os.IsNotExist(err) {
            return false
        }
        return true
    }
    
    func main() {
        filename := "c:/tmp.txt"
    
        var file *os.File
        var err error
        if isFileExists(filename) {
            file, err = os.OpenFile(filename, os.O_APPEND, 0755) //如果文件存在则追加进去
            //file, err = os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0755) //mac系统追加时还需要在加一个os.O_WRONLY方法
        } else {
            file, err = os.Create(filename) //不存在就创建该文件
        }
    
        if err != nil {
            fmt.Printf("open %s failed, err:%v
    ", filename, err)
            return
        }
    
        defer file.Close()
    
        //给文件中写入内容
        n, err := file.WriteString("hello world") //WriteString可以传入字符串
        //io.WriteString(file,"hello world")   //io.WriteString也可以用来进行传入
        if err != nil {
            fmt.Printf("write failed, err:%v
    ", err)
            return
        }
        fmt.Printf("write %d succ
    ", n)
    }

     执行结果:

    查看文件内容:可以发现新追加的也添加进去了。

     

    示例2:

    package main
    
    import (
        "io"
        "os"
    )
    
    func CheckFileExist(fileName string) bool {
        _, err := os.Stat(fileName)
        if os.IsNotExist(err) {
            return false
        }
        return true
    }
    
    func Write(fileName string) error {
        var f *os.File
        var err error
        if CheckFileExist(fileName) { //文件存在
            f, err = os.OpenFile(fileName, os.O_APPEND, 0666) //打开文件
            if err != nil {
                return err
            }
        } else { //文件不存在
            f, err = os.Create(fileName) //创建文件
            if err != nil {
                return err
            }
        }
        _, err = io.WriteString(f, "strTest")
        if err != nil {
            return err
        }
        return nil
    }
    
    func main() {
        Write("c:/tmp.txt")
    }

     执行结果:

     

    查看文件内容:

     

    示例3:Fprintf

    fmt包的Printf底层调用的就是Fprintf

    实例如下:

    package main
    
    import (
        "fmt"
        "os"
    )
    
    func isFileExists(filename string) bool {
        _, err := os.Stat(filename)
        if os.IsNotExist(err) {
            return false
        }
    
        return true
    }
    
    func main() {
        filename := "c:/tmp.txt"
    
        var file *os.File
        var err error
        if isFileExists(filename) {
            //mac机器
            file, err = os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0755)
        } else {
            file, err = os.Create(filename)
        }
    
        if err != nil {
            fmt.Printf("open %s failed, err:%v
    ", filename, err)
            return
        }
    
        defer file.Close()
    
        fmt.Fprintf(file, "%d %d is good", 100, 300) //这里主要是为了演示一下Printf的底层调用Fprintf,我们可以通过传入文件对象,将其写入文件
    }

    执行结果如下:

     

    查看文件内容:

     

    1.8 使用ioutil直接文件写入

    ioutil相当于每次把要写入的内容以覆盖形式写入到文件内

    实例1:

    package main
    
    import (
        "fmt"
        "io/ioutil"
    )
    
    func main() {
        filename := "c:/tmp.txt"
        str := "dkfslfjdsklfjlskjflsjflsjflsjflks"
        err := ioutil.WriteFile(filename, []byte(str), 0755)
        if err != nil {
            fmt.Println("write fail")
        }
        fmt.Println("write success")
    }

     执行结果:

    查看文件内容:

    实例2:

    package main
    
    import (
        "fmt"
        "io/ioutil"
    )
    
    func Write() {
        fileName := "c:/tmp.txt"
        strTest := "测试测试"
        var d = []byte(strTest)
        err := ioutil.WriteFile(fileName, d, 0666)
        if err != nil {
            fmt.Println("write fail")
        }
        fmt.Println("write success")
    }
    
    func main() {
        Write()
    }

    执行结果:

     

    查看文件内容:

     

    1.9 使用bufio进行文件写入 

    bufio会减少写入文件的次数,先写到缓存中,然后会调用Flush方法将内存中的内容刷新到磁盘中。

    bufio写入的缺点:

    会造成文件丢失(当要写入的内容还在缓存中,还未被写入到磁盘时,程序挂了,那这些数据就丢失了。)

    示例1:

    package main
    
    import (
        "bufio"
        "fmt"
        "os"
    )
    
    func isFileExists(filename string) bool {
        _, err := os.Stat(filename)
        if os.IsNotExist(err) {
            return false
        }
    
        return true
    }
    
    func main() {
        filename := "c:/tmp.txt"
    
        var file *os.File
        var err error
    
        file, err = os.Create(filename)
        if err != nil {
            fmt.Printf("open %s failed, err:%v
    ", filename, err)
            return
        }
    
        defer file.Close()
    
        writer := bufio.NewWriter(file)
        writer.WriteString("hello worldldfdsfsfsf")
    
        writer.Flush()
    }

    执行结果:

    查看文件内容:

    示例2:

    package main
    
    import (
        "bufio"
        "fmt"
        "os"
    )
    
    func Write() {
        fileName := "c:/tmp.txt"
        f, err3 := os.Create(fileName) //创建文件
        if err3 != nil {
            fmt.Println("create file fail")
        }
        w := bufio.NewWriter(f)                //创建新的 Writer 对象
        n4, err3 := w.WriteString("bufferedn") //此时还是写入在内存中
        fmt.Printf("写入 %d 个字节
    ", n4)
        w.Flush() //刷新了磁盘
        defer f.Close()
    }
    
    func main() {
        Write()
    }

     执行结果:

     

    查看文件内容:

     

    1.10 拷贝文件

    就相当于一个读另一个写,很简单,核心是io.Copy(其就相当于一个for循环,不断读取源文件内容,然后写入目标文件)

    示例如下:

    package main
    
    import (
        "fmt"
        "io"
        "os"
    )
    
    func main() {
        CopyFile("c:/tmp.txt", "d:/tmp.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.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644) //写入文件
        if err != nil {
            return
        }
        defer dst.Close()
        return io.Copy(dst, src) //核心在这里,io.Copy 一行代码搞定
    }

     执行结果如下:

     

    查看源文件和拷贝文件:

    二、终端读写

    2.1 终端读写相关介绍

    操作终端相关文件句柄常量

    os.Stdin:标准输入

    os.Stdout:标准输出

    os.Stderr:标准错误输出

    2.2 终端读写实例

    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 full name: ")
        fmt.Scanln(&firstName, &lastName)
        // fmt.Scanf("%s %s", &firstName, &lastName)
        fmt.Printf("Hi %s %s!
    ", firstName, lastName) // Hi Chris Naegels
        fmt.Sscanf(input, format, &f, &i, &s)
        fmt.Println("From the string we read: ", f, i, s)
    }

     执行结果:

     

    2.3 带缓冲区的读写

    终端(底层就是一个文件操作)就像1个文件,我们该如何像操作文件一样去操作终端呢?

    实例1:

    package main
    
    import (
        "bufio"
        "fmt"
        "os"
    )
    
    func main() {
        //标准输出
        writer := bufio.NewWriter(os.Stdout) //写的话相当于从终端输出,读的话相当于从终端输入
        writer.WriteString("hello world")
        writer.Flush() //因为bufio还写在内存中,需要flush一下
    
        fmt.Printf("hello world")
        //标准输入
        reader := bufio.NewReader(os.Stdin)   //从终端读入
        data, err := reader.ReadString('
    ')  //readstring方法是传入分隔符,此处传入
    表示直到读入
    为止,也就相当于读一行内容即可
        if err != nil {
            fmt.Printf("read from console failed, err:%v
    ", err)
            return
        }
        fmt.Fprintf(os.Stdout, "data:%s
    ", data)
    }

    执行结果:

    实例2:

    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('
    ')
        if err == nil {
            fmt.Printf("The input was: %s
    ", input)
        }
    }

     执行结果:

    三、命令行参数

    3.1 os.Args

    os.Args是一个string的切片,用来存储所有的命令行参数。

    package main
    
    import (
        "fmt"
        "os"
    )
    
    func main() {
        fmt.Printf("args count:%d
    ", len(os.Args))   //获取当前程序的参数个数
        for index, v := range os.Args {
            fmt.Printf("args%d, value:%s
    ", index, v)
        }
    }

     执行结果如下:

    3.2 flag包使用

    布尔:flag.BoolVar(&test, "b", false, "print on newline")

    字符串:flag.StringVar(&str, "s", "", "print on newline")

    整型:flag.IntVar(&count, "c", 1001, "print on newline")

    flag要传入的参数依次是:传入值-终端参数-默认值-用法

    实例:

    package main
    
    import (
        "flag"
        "fmt"
    )
    
    func main() {
        var num int
        var mode string
    
        flag.IntVar(&num, "num", 16, "-num the passwd length") //IntVar参数依次是:传入值-终端参数-默认值-用法
        flag.StringVar(&mode, "mode", "mix", "-mode the password generate mode")
    
        flag.Parse() //真正解析命令行参数,IntVar、StringVar只是设置命令行需要的一些参数
    
        fmt.Printf("num:%d mode:%s
    ", num, mode)
    }

    执行结果如下:

     

    可以发现传入的参数直接就被flag包解析了。更牛逼的是连--help都直接帮我们做好了

    3.3 命令行参数解析

     实例:

    package main
    
    import (
        "flag" // command line option parser
        "fmt"
    )
    
    func main() {
        var test bool
        var str string
        var count int
        flag.BoolVar(&test, "b", false, "print on newline")
        flag.StringVar(&str, "s", "", "print on newline")
        flag.IntVar(&count, "c", 1001, "print on newline")
        flag.Parse()
        fmt.Println(test)
        fmt.Println(str)
        fmt.Println(count)
    }

     执行结果:

    3.4 带缓冲区的终端读写

    实例:

    package main
    
    import (
        "bufio"
        "fmt"
        "os"
    )
    
    func main() {
        fmt.Fprintf(os.Stdout, "%s
    ", "hello world! - unbuffered")
        buf := bufio.NewWriter(os.Stdout)
        fmt.Fprintf(buf, "%s
    ", "hello world! - buffered")
        buf.Flush()
    }

     执行结果:

  • 相关阅读:
    Tiny模板引擎之开发工具
    Tiny框架应用实践之Tiny社区
    TINY框架:组件化的J2EE开发框架
    TinyRMI---RMI的封装、扩展及踩到的坑的解决
    新手如何入门
    从应用示例来认识Tiny框架
    图形化插件对Eclipse的版本要求
    可不可以在局域网编译TINY?
    批量创建的方法
    不在框架中,利用Django的models操作
  • 原文地址:https://www.cnblogs.com/forever521Lee/p/9445443.html
Copyright © 2011-2022 走看看