zoukankan      html  css  js  c++  java
  • Go 终端读写 && 文件读写、copy

    终端读写

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

    • os.Stdin(standard):标准输入
    • os.Stdout:标准输出
    • os.Stderr:标准错误输出

    标准输出

    demo:直接输出和 判断之后输出的结果不一致

    func main(){
    	//标准输出接口, 格式, 需要格式化的内容
    	fmt.Fprintf(os.Stdout, "%s
    ", "hello world ~")
    
    	fmt.Fprintln(os.Stdout, "hello, world ~")
    }
    
    运行结果:
    hello world ~
    hello, world ~
    

    标准输入

    package main
    import (
    	"fmt"
    )
    
    var (
    	firstName, lastName string
    	age, salary int
    	)
    
    func main(){
    	//从键盘获取string类型赋值给fistName
    	fmt.Scanf("%s", &firstName)
    
    	//将字符串赋值给lastName, 中间不能空格
    	fmt.Sscan("helloworld", &lastName)
    
    	//将一个字符串按照指定格式赋值给变量
    	fmt.Sscanf("18-3000", "%d-%d", &age, &salary)
    
    	fmt.Printf("%s
    %s
    %d
    %d", firstName, lastName, age, salary)
    }
    
    运行结果:
    "holle go"  //手动输入,有空格不行
    "holle
    helloworld
    18
    3000
    

      

    带缓存的输出

    package main
    import (
    	"bufio"
    	"fmt"
    	"os"
    )
    
    func main(){
    	//先得到*Write缓存
    	buf := bufio.NewWriter(os.Stdout)
    	
    	//标准输出接口, 格式, 需要格式化的内容
    	fmt.Fprintf(buf, "%s
    ", "hello world ~")
    
    	fmt.Fprintln(buf, "hello, world ~")
    	
    	buf.Flush()
    }
    
    运行结果:
    hello world ~
    hello, world ~
    

      

    带缓存的输入

    package main
    import (
    	"bufio"
    	"fmt"
    	"os"
    )
    
    func main(){
    	buf := bufio.NewReader(os.Stdin)
    
    	input, err := buf.ReadString('
    ')  //delim 定界符
    	if err == nil {
    		fmt.Println(input)
    	}
    }
    
    运行结果:
    hello world  //手动输入
    hello world
    

      

    读文件

    Go 中读取一个文件有多种方式,下面介绍主要的几种:

    使用 ioutil 包直接读取

    先需要引入 io/ioutil 包,该包默认拥有以下函数供使用者调用

    func NopCloser(r io.Reader) io.ReadCloser
    func ReadAll(r io.Reader) ([]byte, error)
    func ReadDir(dirname string) ([]os.FileInfo, error)
    func ReadFile(filename string) ([]byte, error)
    func TempDir(dir, prefix string) (name string, err error)
    func TempFile(dir, prefix string) (f *os.File, err error)
    func WriteFile(filename string, data []byte, perm os.FileMode) error
    

    1)通过指定路径,读取一个文件,并返回 []byte 数据和错误信息

    func ReadFile(filename string) ([]byte, error)

    demo:通过文件路径读取一个文件,输出文件中的内容

    package main
    import (
    	"fmt"
    	"io/ioutil"
    )
    
    func readFileByName(fileName string){
    	contentSlice, err := ioutil.ReadFile(fileName)
    	if err == nil {
    		fmt.Print(string(contentSlice))
    	}
    }
    
    func main(){
    	var fileName string = "D:\code\go_dev\projects\src\part_10_终端输入输出 && 文件操作\01_使用os.osutil读取文件\test.txt"
    	readFileByName(fileName)
    }
    
    运行结果:
    my name is johny
    i'm 12 years old
    i like speaking english
    i like to eat cake

    2)通过指定路径,读取一个目录,并返回目录下的文件类型列表和错误信息

    func ReadDir(dirname string) ([]os.FileInfo, error)

    demo:打开一个目录,输出目录下文件的名称

    package main
    import (
    	"fmt"
    	"io/ioutil"
    )
    
    func readDiractory(dirName string) {
    	fileInfoSlice, err := ioutil.ReadDir(dirName)
    	if err != nil {
    		fmt.Println(err)
    		return
    	}
    	for _, fileInfo := range fileInfoSlice {
    		fileName := fileInfo.Name()
    		fmt.Println(fileName)
    	}
    }
    
    func main() {
    	var dirName string = "D:\code\go_dev\file_test"
    	readDiractory(dirName)
    }
    
    运行结果:
    test1.txt
    test2.txt
    test3.txt
    

    使用 os.Open() 和 os.OpenFile() 函数读取

    不论是 os.Open() 还是 os.OpenFile,都返回一个文件类型指针(*File),File 文件类型是一个结构体,封装了关于文件相关操作的方法

    关闭一个文件:

    File.Close()
    

    1)os.Open()

    打开一个将被读取的文件,如果读取成功,返回文件类型,默认的权限是 O_RDONLY,也就是只读权限,否则返回错误

    func os.Open(name string) (*File, error)
    

      

    2)os.OpenFile()

    大部分用户会选择这个函数来代替 os.Open() 函数

    主要原因是这个函数打开文件时可以指定参数(os.O_APPEND | os.O_CREATE | os.O_WRONLY),以及文件权限(0666)

    func os.OpenFile(name string, flag int, perm FileMode) (*File, error)
    

    flag 相关参数:

    const (
            O_RDONLY int = syscall.O_RDONLY // 只读打开文件和os.Open()同义
            O_WRONLY int = syscall.O_WRONLY // 只写打开文件
            O_RDWR   int = syscall.O_RDWR   // 读写方式打开文件
            O_APPEND int = syscall.O_APPEND // 当写的时候使用追加模式到文件末尾
            O_CREATE int = syscall.O_CREAT  // 如果文件不存在,此案创建
            O_EXCL   int = syscall.O_EXCL   // 和O_CREATE一起使用, 只有当文件不存在时才创建
            O_SYNC   int = syscall.O_SYNC   // 以同步I/O方式打开文件,直接写入硬盘.
            O_TRUNC  int = syscall.O_TRUNC  // 如果可以的话,当打开文件时先清空文件
    )
    

    3)使用 os.Open() 函数和 ioutil.ReadAll() 函数来读取文件

    由于 os.Open 是打开一个文件并返回文件指针类型(*File),因此其实可以结合 ioutil 包中的 ReadAll(r io.Reader) ([]byte, error) 函数来进行读取的(这里还有点疑问)

    io.Reader 其实是一个包含 Read() 方法的接口类型,而文件类型(File)是实现了 Read() 方法的

     ioutil.ReadAll() 函数从一个文件类型( io.Reader )中读取内容直到返回错误或者结束(EOF)时返回读取的数据,当 err == nil 时,数据成功读取到 []byte 中

    func ReadAll(r io.Reader) ([]byte, error)

    demo:打开一个绝对路径下的文件

    package main
    import (
    	"fmt"
    	"io"
    	"io/ioutil"
    	"os"
    )
    
    func readByFielType(fileType io.Reader){
    	contentSlice, err := ioutil.ReadAll(fileType)
    	if err == nil {
    		fmt.Print(string(contentSlice))
    	}
    }
    
    func main(){
    	fileType, err := os.Open("D:\code\go_dev\projects\src\part_10_终端输入输出 && 文件操作\01_使用os.osutil读取文件\test.txt")
    	if err != nil {
    		fmt.Printf("file open failed, detail is %v", err.Error())
    	} else {
    		readByFielType(fileType)
    	}
            defer fileType.Close()
    }
    
    运行结果:
    my name is johny
    i'm 12 years old
    i like speaking english
    i like to eat cake

    这种方式会比较繁琐一些,因为使用了 os 的同时借助了 ioutil,但是在读取大文件的时候还是比较有优势的

    带缓存的读取(bufio)

    bufio 包实现了缓存 IO,创建了 Reader 和 Writer 类型结构体,这种带有缓存的方式,对于文本 I/O 来说,提供了一些便利

    bufio 包中对 Reader 类型结构体有很多相关的函数及方法:

    //首先定义了一个用来缓冲io.Reader对象的结构体,同时该结构体拥有以下相关的方法
    type Reader struct {
    }
    
    //NewReader函数用来返回一个默认大小buffer的Reader对象(默认大小好像是4096) 等同于NewReaderSize(rd,4096)
    func NewReader(rd io.Reader) *Reader
    
    //该函数返回一个指定大小buffer(size最小为16)的Reader对象,如果 io.Reader参数已经是一个足够大的Reader,它将返回该Reader
    func NewReaderSize(rd io.Reader, size int) *Reader
    
    
    //该方法返回从当前buffer中能被读到的字节数
    func (b *Reader) Buffered() int
    
    //Discard方法跳过后续的 n 个字节的数据,返回跳过的字节数。如果0 <= n <= b.Buffered(),该方法将不会从io.Reader中成功读取数据。
    func (b *Reader) Discard(n int) (discarded int, err error)
    
    //Peekf方法返回缓存的一个切片,该切片只包含缓存中的前n个字节的数据
    func (b *Reader) Peek(n int) ([]byte, error)
    
    //把Reader缓存对象中的数据读入到[]byte类型的p中,并返回读取的字节数。读取成功,err将返回空值
    func (b *Reader) Read(p []byte) (n int, err error)
    
    //返回单个字节,如果没有数据返回err
    func (b *Reader) ReadByte() (byte, error)
    
    //该方法在b中读取delimz之前的所有数据,返回的切片是已读出的数据的引用,切片中的数据在下一次的读取操作之前是有效的。如果未找到delim,将返回查找结果并返回nil空值。因为缓存的数据可能被下一次的读写操作修改,因此一般使用ReadBytes或者ReadString,他们返回的都是数据拷贝
    func (b *Reader) ReadSlice(delim byte) (line []byte, err error)
    
    //功能同ReadSlice,返回数据的拷贝
    func (b *Reader) ReadBytes(delim byte) ([]byte, error)
    
    //功能同ReadBytes,返回字符串
    func (b *Reader) ReadString(delim byte) (string, error)
    
    //该方法是一个低水平的读取方式,一般建议使用ReadBytes('
    ') 或 ReadString('
    '),或者使用一个 Scanner来代替。ReadLine 通过调用 ReadSlice 方法实现,返回的也是缓存的切片,用于读取一行数据,不包括行尾标记(
     或 
    )
    func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)
    
    //读取单个UTF-8字符并返回一个rune和字节大小
    func (b *Reader) ReadRune() (r rune, size int, err error)
    

     demo:使用 NewReader() 函数返回一个 *Reader 类型,然后使用 ReadString() 方法读取文件内容,使用 for 循环,一直读到文件结尾

    package main
    import (
    	"bufio"
    	"fmt"
    	"io"
    	"os"
    )
    
    func bufioRead(){
    	fileType, err := os.Open("D:\golang_workspace\file_test\test.txt")
    	if err != nil {
    		fmt.Printf("file open failed, detail is %v", err.Error())
    		os.Exit(2)
    	}
    	defer fileType.Close()
    
    	var bufReader *bufio.Reader = bufio.NewReader(fileType)
    	for {
    		contents, err := bufReader.ReadString('
    ')
    		if err != io.EOF {
    			fmt.Print(contents)
    		} else {
    			break
    		}
    	}
    }
    
    func main(){
    	bufioRead()
    }
    
    运行结果:
    想带你逃学看一场演唱会
    想你难过时在我怀中流泪
    想和你背包走遍天南地北
    想你共我尝尽人生的滋味
    想下雨时小伞中有你依偎
    想把酒言欢时也有你作陪
    

    写文件

    上面的读操作的方式同样也支持写操作

    使用 ioutil 包进行文件写入

    写入 []byte 类型的数据到 filename 文件中,文件的权限为 perm

    func WriteFile(filename string, data []byte, perm os.FileMode) error
    

    demo:使用 WriteFile() 函数写入内容到文件

    package main
    import (
    	"fmt"
    	"io/ioutil"
    )
    
    func ioutilWrite(){
    	var contents string = "hello world ~"
    	var data []byte = []byte(contents)
    	err := ioutil.WriteFile("D:\golang_workspace\file_test\test.txt", data, 0644)
    	if err != nil {
    		fmt.Printf("open file failed, detail is %v", err)
    	} else {
    		fmt.Println("write success ~")
    	}
    }
    
    func main(){
    	ioutilWrite()
    }
    
    运行结果:
    write success ~  //覆盖写入
    

    使用 os.OpenFile() 函数进行文件写入

    因为 os.OpenFile() 函数会打开文件,并返回文件类型结构体指针,而该文件类型是一个结构体,拥有一些写入相关的方法

    func os.OpenFile(name string, flag int, perm FileMode) (*File, error)
    

    flag 相关参数及含义:

    const (
            O_RDONLY int = syscall.O_RDONLY // 只读打开文件和os.Open()同义
            O_WRONLY int = syscall.O_WRONLY // 只写打开文件
            O_RDWR   int = syscall.O_RDWR   // 读写方式打开文件
            O_APPEND int = syscall.O_APPEND // 当写的时候使用追加模式到文件末尾
            O_CREATE int = syscall.O_CREAT  // 如果文件不存在,此案创建
            O_EXCL   int = syscall.O_EXCL   // 和O_CREATE一起使用, 只有当文件不存在时才创建
            O_SYNC   int = syscall.O_SYNC   // 以同步I/O方式打开文件,直接写入硬盘.
            O_TRUNC  int = syscall.O_TRUNC  // 如果可以的话,当打开文件时先清空文件
    )
    

    文件类型结构体以及相关写入文件的方法:

    1)写入长度为b字节切片到文件f中,返回写入字节号和错误信息。当n不等于len(b)时,将返回非空的err

    func (f *File) Write(b []byte) (n int, err error)
    

    2)在off偏移量出向文件f写入长度为b的字节

    func (f *File) WriteAt(b []byte, off int64) (n int, err error)
    

    3)类似于Write方法,但是写入内容是字符串而不是字节切片

    func (f *File) WriteString(s string) (n int, err error)

    demo:使用 os.OpenFile() 函数打开文件,使用 Write() 和 WriteString() 方法将内容写入到文件

    package main
    import (
    	"fmt"
    	"os"
    )
    
    func osOpenWrite(){
    	fileType, errOpen := os.OpenFile("D:\golang_workspace\file_test\test.txt", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
    	if errOpen != nil {
    		fmt.Printf("openfile failed, detail is %v", errOpen.Error())
    		return
    	}
    	defer fileType.Close()
    
    	//写入字符串
    	_, errWrite1 := fileType.WriteString("hello world")
    	if errWrite1 != nil {
    		fmt.Printf("write file error, detail is %v", errWrite1.Error())
    	} else {
    		fmt.Println("write string success ~")
    	}
    
    	//写入字符切片
    	_, errWrite2 := fileType.Write([]byte("hello world"))
    	if errWrite2 != nil {
    		fmt.Printf("write file error, detail is %v", errWrite2.Error())
    	} else {
    		fmt.Println("write []byte success ~")
    	}
    }
    
    func main(){
    	osOpenWrite()
    }
    
    运行结果:
    write string success ~
    write []byte success ~
    

    带缓存的写入(bufio)

    bufio 和 io 包中很多操作都是相似的,唯一不同的是 bufio 提供了一些缓冲的操作,如果对文件操作比较频繁的,使用 bufio 还是能提高程序的性能和效率的

    在 bufio 中,有一个 Writer 类型结构体,与其相关的方法支持一系列的写入操作:

    //Writer是一个空的结构体,一般需要使用NewWriter或者NewWriterSize来初始化一个结构体对象
    type Writer struct {
            // contains filtered or unexported fields
    }
    
    //NewWriterSize和NewWriter函数
    //返回默认缓冲大小的Writer对象(默认是4096)
    func NewWriter(w io.Writer) *Writer
    
    //指定缓冲大小创建一个Writer对象
    func NewWriterSize(w io.Writer, size int) *Writer
    
    //Writer对象相关的写入数据的方法
    
    //把p中的内容写入buffer,返回写入的字节数和错误信息。如果nn<len(p),返回错误信息中会包含为什么写入的数据比较短
    func (b *Writer) Write(p []byte) (nn int, err error)
    //将buffer中的数据写入 io.Writer
    func (b *Writer) Flush() error
    
    //以下三个方法可以直接写入到文件中
    //写入单个字节
    func (b *Writer) WriteByte(c byte) error
    //写入单个Unicode指针返回写入字节数错误信息
    func (b *Writer) WriteRune(r rune) (size int, err error)
    //写入字符串并返回写入字节数和错误信息
    func (b *Writer) WriteString(s string) (int, error)
    

    demo:使用 NewWriter() 函数得到一个 *Writer(指针类型结构体),然后调用 Write() 方法将内容写入到文件,最后调用 Flush() 方法把数据刷新到磁盘

    package main
    import (
    	"bufio"
    	"fmt"
    	"os"
    )
    
    func bufioWrite(){
    	fileType, errOpen := os.OpenFile("D:\golang_workspace\file_test\test.txt", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
    	if errOpen != nil {
    		fmt.Printf("openfile failed, detail is %v", errOpen.Error())
    		return
    	}
    	defer fileType.Close()
    
    	//生成 *Writer 指针结构体
    	var writer *bufio.Writer = bufio.NewWriter(fileType)
    	_, errWrite := writer.Write([]byte("hello world ~"))
    	if errWrite != nil {
    		fmt.Printf("file write error, detail is %v", errWrite.Error())
    	}
        
    	//刷新数据到磁盘
    	errFlush := writer.Flush()
    	if errFlush != nil {
    		fmt.Println("file flush error")
    		panic(errFlush)
    	} else {
    		fmt.Println("write file success")
    	}
    }
    
    func main(){
    	bufioWrite()
    }
    
    运行结果:
    write file success
    

    文件 copy

    demo:把一个文件的内容,拷贝到另一个文件中

    package main
    import (
    	"fmt"
    	"io"
    	"os"
    )
    
    func main(){
    	var srcFileName string = "D:\golang_workspace\file_test\source.txt"
    	var targetFileName string = "D:\golang_workspace\file_test\target.txt"
    	CopyFile(srcFileName, targetFileName)
    }
    
    func CopyFile(srcFileName, targetFileName string){
    	srcFile, err := os.Open(srcFileName)
    	if err != nil {
    		fmt.Printf("open srcfile failed, err:[%v]", err)
    	}
    	defer srcFile.Close()
    
    	targetFile, err := os.OpenFile(targetFileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
    	if err != nil {
    		fmt.Printf("open targetfile failed, err:[%v]", err)
    	}
    	defer targetFile.Close()
    
    	written, err := io.Copy(targetFile, srcFile)
    	if err != nil {
    		fmt.Printf("file copy failed, err[%v]", err)
    	}
    	fmt.Printf("copy complete, writen[%v]", written)
    }
    
    运行结果:
    copy complete, writen[14]
    

      

    总结:

    Go 语言中,文件操作读和写用到了三个包,分别是 ioutil    os    bufio:

    1. ioutil.ReadFile,   ioutil.ReadDir,  ioutil.ReadAll       和       ioutil.WriteFile
    2. os.Open      和      os.OpenFile
    3. bufio.Reader      和      bufio.Writer

     其中也有穿插使用,比如:os.Open 和 ioutil.ReadAll,os.Open 和 bufio.Reader,os.OpenFile 和 bufio.Writer

    ending ~

    每天都要遇到更好的自己.
  • 相关阅读:
    iOS事件机制,以及不同手势使用touchesBegan等表现形式
    UIview 动画
    核心动画与UIView
    代理与Block
    关于清除浮动的几个写法
    关于一个自适应屏幕的高宽
    关于loading 的一个css样式
    用margin还是用padding?(3)—— 负margin实战
    jquery回顾part1——选择器
    解读mysql主从配置及其原理分析(Master-Slave)
  • 原文地址:https://www.cnblogs.com/kaichenkai/p/11117574.html
Copyright © 2011-2022 走看看