zoukankan      html  css  js  c++  java
  • golang中的文件操作

    一、文件的基本介绍

    文件是数据源(保存数据的地方)的一种,比如经常使用的word文档,txt文件,excel文件都是文件。文件最主要的作用就是保存数据,它既可以保存一张图片,也可以保持视频,声音等等。

    1、输入流和输出流  

    2、os.File封装了所以文件相关操作,File是一个结构体

    type File struct {
    // 内含隐藏或非导出字段
    }
    File代表一个打开的文件对象。

    func (f *File) Read(b []byte) (n int, err error)
    Read方法从f中读取最多len(b)字节数据并写入b。它返回读取的字节数和可能遇到的任何错误。文件终止标志是读取0个字节且返回值err为io.EOF。

    func (f *File) ReadAt(b []byte, off int64) (n int, err error)
    ReadAt从指定的位置(相对于文件开始位置)读取len(b)字节数据并写入b。它返回读取的字节数和可能遇到的任何错误。当n<len(b)时,本方法总是会返回错误;如果是因为到达文件结尾,返回值err会是io.EOF。

    func (f *File) Write(b []byte) (n int, err error)
    Write向文件中写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。

    func (f *File) WriteAt(b []byte, off int64) (n int, err error)
    WriteAt在指定的位置(相对于文件开始位置)写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。

    二、打开文件和关闭文件

    func Open(name string) (file *File, err error)
    Open打开一个文件用于读取。如果操作成功,返回的文件对象的方法可用于读取数据;对应的文件描述符具有O_RDONLY模式。如果出错,错误底层类型是*PathError。

    func (f *File) Close() error
    Close关闭文件f,使文件不能用于读写。它返回可能出现的错误。

    package main
    
    import (
    	"fmt"
    	"os"
    )
    
    func main() {
    	//打开文件
    	//file叫做对象、指针或者文件句柄
    	file, err := os.Open("/Users/test/Desktop/demo/ssh.txt")
    	if err != nil {
    		fmt.Println("open fiel err=", err)
    	}
    	fmt.Printf("file=%v,%T", *file, file)
    
    	err = file.Close()
    	if err != nil {
    		fmt.Println("close file err=", err)
    	}
    }
    

    三、读写文件操作

    读取文件的内容并显示在终端(带缓冲区的方式),使用os.Open,file.Close,bufio.NewReader(),reader.ReadString函数和方法

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"io"
    	"os"
    )
    
    func main() {
    	//打开文件
    	//file叫做对象、指针或者文件句柄
    	file, err := os.Open("/Users/test/Desktop/demo/ssh.txt")
    	if err != nil {
    		fmt.Println("open fiel err=", err)
    	}
    
    	//当函数退出时,要及时关闭file,否则会有内存泄漏
    	defer file.Close()
    	if err != nil {
    		fmt.Println("close file err=", err)
    	}
    	// 创建一个 *Reader ,是带缓冲的
    	/*
    		const (
    		defaultBufSize = 4096 //默认的缓冲区为 4096 )
    	*/
    
    	reader := bufio.NewReader(file)
    
    	//循环读取文件内容
    	for {
    		str, err := reader.ReadString('
    ') //读到一个换行就结束
    		if err == io.EOF { //io.EOF表示文件的末尾
    			break
    		}
    		//输出内容
    		fmt.Print(str)
    	}
    	fmt.Println("文件读取结束...")
    }
    

    读取文件的内容并显示在终端(使用ioutil一次将整个文件读入到内存中),这种方式适用于文件不大的情况。相关方法和函数(ioutil.ReadFile)

    func ReadFile(filename string) ([]byte, error)
    ReadFile 从filename指定的文件中读取数据并返回文件的内容。成功的调用返回的err为nil而非EOF。因为本函数定义为读取整个文件,它不会将读取返回的EOF视为应报告的错误。

    package main
    
    import (
    	"fmt"
    	"io/ioutil"
    )
    
    func main() {
    	//使用ioutil.ReadFile一次性将文件读取到位
    	file := "/Users/test/Desktop/bytedance/ssh.txt"
    
    	content, err := ioutil.ReadFile(file)
    	if err != nil {
    		fmt.Printf("read file err=%v", err)
    	}
    	//把读取到的内容显示到终端
    	fmt.Printf("%v
    ", content) //[]byte
    	fmt.Printf("%v", string(content))
    
    	//没有显式的Open文件,也不需要显式Close文件
    	//文件的Open和Close被封装到ReadFile函数内部
    }
    

    os.OpenFile 函数
    func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
    OpenFile是一个更一般性的文件打开函数,大多数调用者都应用Open或Create代替本函数。它会使用指定的选项(如O_RDONLY等)、指定的模式(如0666等)打开指定名称的文件。如果操作成功,返回的文件对象可用于I/O。如果出错,错误底层类型是*PathError。

    第二个参数:文件打开模式(可以组合)

    const (
    O_RDONLY int = syscall.O_RDONLY // 只读模式打开文件
    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 // 如果可能,打开时清空文件
    )

    第三个参数:权限控制

    r  ->  4

    w  -> 2

    x  ->  1

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"os"
    )
    
    func main() {
    	filePath := "/Users/test/Desktop/test.txt"
    	file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666)
    	if err != nil {
    		fmt.Printf("open file err=%v
    ", err)
    		return
    	}
    	defer file.Close()
    	str := "hello,world
    "
    	//写入时使用带缓存的*Writer
    	writer := bufio.NewWriter(file)
    	for i := 0; i < len(str); i++ {
    		writer.WriteString(str)
    	}
    	//writer是带缓存的,在调用WriterString方法时,内容是先写入缓存的,
    	//需要调用Flush方法,将缓冲的数据真正写入到文件中,否则文件中会没有数据
    	writer.Flush()
    }
    

    打开一个存在的文件,将原来的内容覆盖成新的10句话“欢迎来到go的世界”

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"os"
    )
    
    func main() {
    	filePath := "/Users/test/Desktop/test.txt"
    	file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_TRUNC, 0666)
    	if err != nil {
    		fmt.Printf("open file err=%v
    ", err)
    		return
    	}
    	defer file.Close()
    	str := "欢迎来到go的世界
    "
    	//写入时使用带缓存的*Writer
    	writer := bufio.NewWriter(file)
    	for i := 0; i < 10; i++ {
    		writer.WriteString(str)
    	}
    	//writer是带缓存的,在调用WriterString方法时,内容是先写入缓存的,
    	//需要调用Flush方法,将缓冲的数据真正写入到文件中,否则文件中会没有数据
    	writer.Flush()
    }
    

    打开一个存在的文件,在原来的内容后面追加内容“欢天喜地过大年”

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"os"
    )
    
    func main() {
    	filePath := "/Users/test/Desktop/test.txt"
    	file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_APPEND, 0666)
    	if err != nil {
    		fmt.Printf("open file err=%v
    ", err)
    		return
    	}
    	defer file.Close()
    	str := "欢天喜地过大年!
    "
    	//写入时使用带缓存的*Writer
    	writer := bufio.NewWriter(file)
    	for i := 0; i < 10; i++ {
    		writer.WriteString(str)
    	}
    	//writer是带缓存的,在调用WriterString方法时,内容是先写入缓存的,
    	//需要调用Flush方法,将缓冲的数据真正写入到文件中,否则文件中会没有数据
    	writer.Flush()
    }
    

    打开一个存在的文件,将原来的内容读出显示在终端,并且追加 5 句"hello,北京!"

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"io"
    	"os"
    )
    
    func main() {
    	filePath := "/Users/test/Desktop/test.txt"
    	file, err := os.OpenFile(filePath, os.O_RDWR|os.O_APPEND, 0666)
    	if err != nil {
    		fmt.Printf("open file err=%v
    ", err)
    		return
    	}
    	defer file.Close()
    	//写入时使用带缓存的*Writer
    	reader := bufio.NewReader(file)
    
    	for {
    		str, err := reader.ReadString('
    ')
    		if err == io.EOF {
    			break
    		}
    		fmt.Print(str)
    	}
    
    	str := "hello,北京!
    "
    	writer := bufio.NewWriter(file)
    	for i := 0; i < 10; i++ {
    		writer.WriteString(str)
    	}
    	//writer是带缓存的,在调用WriterString方法时,内容是先写入缓存的,
    	//需要调用Flush方法,将缓冲的数据真正写入到文件中,否则文件中会没有数据
    	writer.Flush()
    }
    

    编程一个程序,将一个文件的内容,写入到另外一个文件。注:这两个文件已经存在了。使用ioutil.ReadFile/ioutil.WriteFile完成写文件的任务。

    package main
    
    import (
    	"fmt"
    	"io/ioutil"
    )
    
    func main() {
    	filePath1 := "/Users/test/Desktop/test.txt"
    	filePath2 := "/Users/test/Desktop/dest.txt"
    	data, err := ioutil.ReadFile(filePath1)
    	if err != nil {
    		fmt.Printf("read file err=%v
    ", err)
    		return
    	}
    	err = ioutil.WriteFile(filePath2, data, 0666)
    	if err != nil {
    		fmt.Printf("write file error=%v
    ", err)
    	}
    }
    

    判断文件是否存在

    golang判断文件或文件夹是否存在的方法为使用os.Stat()函数返回的错误值进行判断:

    (1)、如果返回的错误为nil,说明文件或文件夹存在

    (2)、如果返回的错误类型使用os.IsNotExist()判断为true,说明文件或文件夹不存在

    (3)、如果返回的错误为其它类型,则不确定是否存在

    package main
    
    import (
    	"fmt"
    	"os"
    )
    
    func PathExists(path string) (bool, error) {
    	_, err := os.Stat(path)
    	if err == nil {
    		return true, nil
    	}
    	if os.IsNotExist(err) {
    		return false, nil
    	}
    	return false, err
    }
    
    func main() {
    	filePath := "/Users/test/Desktop/test.txt"
    	fmt.Println(PathExists(filePath))
    }
    

    拷贝文件

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"io"
    	"os"
    )
    
    func CopyFile(dstFileName string, srcFileName string) (written int64, err error) {
    	srcFile, err := os.Open(srcFileName)
    	if err != nil {
    		fmt.Printf("open file err=%v
    ", err)
    	}
    
    	defer srcFile.Close()
    
    	reader := bufio.NewReader(srcFile)
    
    	dstFile, err := os.OpenFile(dstFileName, os.O_WRONLY|os.O_CREATE, 0666)
    
    	if err != nil {
    		fmt.Printf("open file err=%v
    ", err)
    		return
    	}
    
    	writer := bufio.NewWriter(dstFile)
    
    	defer dstFile.Close()
    
    	return io.Copy(writer, reader)
    }
    
    func main() {
    	srcFile := "/Users/bytedance/Desktop/cao.png"
    	dstFile := "/Users/bytedance/Desktop/dst.png"
    	_, err := CopyFile(dstFile, srcFile)
    	if err == nil {
    		fmt.Printf("文件拷贝完成
    ")
    	} else {
    		fmt.Printf("文件拷贝出错,err=%v", err)
    	}
    }
    

    统计英文、数字、空格和其他字符数量

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"io"
    	"os"
    )
    
    type CharCount struct {
    	ChCount    int //记录英文个数
    	NumCount   int //记录数字个数
    	SpaceCount int //记录空格个数
    	OtherCount int //记录其它字符的个数
    }
    
    func main() {
    	fileName := "/Users/bytedance/Desktop/test.txt"
    	file, err := os.Open(fileName)
    	if err != nil {
    		fmt.Printf("open file err=%v
    ", err)
    		return
    	}
    
    	defer file.Close()
    
    	var count CharCount
    
    	reader := bufio.NewReader(file)
    
    	for {
    		s, err := reader.ReadString('
    ')
    		if err == io.EOF {
    			break
    		}
    		//为了兼容中文字符,将str转成[]rune
    		str := []rune(s)
    
    		for _, v := range str {
    			switch {
    			case v >= 'a' && v <= 'z':
    				fallthrough //穿透
    			case v >= 'A' && v <= 'Z':
    				count.ChCount++
    			case v == ' ' || v == '	':
    				count.SpaceCount++
    			case v >= '0' && v <= '9':
    				count.NumCount++
    			default:
    				count.OtherCount++
    			}
    		}
    	}
    
    	fmt.Printf("字符的个数=%v 数字的个数=%v 空格的个数=%v 其它字符个数=%v", count.ChCount, count.NumCount, count.SpaceCount, count.OtherCount)
    }
    

    四、命令行参数

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

    package main
    
    import (
    	"fmt"
    	"os"
    )
    
    func main() {
    	fmt.Println("命令行参数有", len(os.Args))
    	//遍历os.Args切片可以得到所有的命令行输入参数值
    	for i, v := range os.Args {
    		fmt.Printf("args[%v]=%v
    ", i, v)
    	}
    }
    

    flag包解析命令行参数

    package main
    
    import (
    	"flag"
    	"fmt"
    )
    
    func main() {
    	//定义变量用于接收命令行参数值
    	var user string
    	var pwd string
    	var host string
    	var port int
    
    	flag.StringVar(&user, "u", "", "用户名,默认为空")
    	flag.StringVar(&pwd, "pwd", "", "密码,默认为空")
    	flag.StringVar(&host, "h", "localhost", "主机名,默认为localhost")
    	flag.IntVar(&port, "port", 3306, "端口号,默认为3306")
    
    	//转换操作,必须调用该方法
    	flag.Parse()
    
    	fmt.Printf("user=%v pwd=%v host=%v port=%v
    ", user, pwd, host, port)
    }
    

    五、json

    轻量级的数据交换格式。json易于机器解析和生成,并有效地提升网络传输效率,通常程序在网络传输时先将数据(结构体、map等)序列化成json字符串,到接收方得到json字符串时,在反序列化恢复成原来的数据类型(结构体、map等)。这种方式已然成为各个语言的标准。

    1、json的序列化

    json序列化是指将有key-value结构的数据类型(比如结构体、map、切片)序列化成json字符串的操作。

    package main
    
    import (
    	"encoding/json"
    	"fmt"
    )
    
    type Monster struct {
    	Name     string
    	Age      int
    	Birthday string
    	Sal      float64
    	Skill    string
    }
    
    //序列化结构体
    func testStruct() {
    	monster := Monster{
    		Name:     "牛魔王",
    		Age:      500,
    		Birthday: "2011-11-11",
    		Sal:      8000.0,
    		Skill:    "牛魔拳",
    	}
    
    	//将monster序列化
    	data, err := json.Marshal(&monster)
    	if err != nil {
    		fmt.Printf("序列化错误 err=%v
    ", err)
    	}
    
    	//输出序列化后的结果
    	fmt.Printf("monster序列化后=%v
    ", string(data))
    }
    
    //map序列化
    func testMap() {
    	var a map[string]interface{}
    
    	a = make(map[string]interface{})
    
    	a["name"] = "红孩儿"
    	a["age"] = 30
    	a["address"] = "洪崖洞"
    
    	data, err := json.Marshal(a)
    	if err != nil {
    		fmt.Printf("序列化错误 err=%v
    ", err)
    	}
    
    	//输出序列化后的结果
    	fmt.Printf("map序列化后=%v
    ", string(data))
    }
    
    //切片序列化
    func testSlice() {
    	var slice []map[string]interface{}
    
    	var m1 map[string]interface{}
    	m1 = make(map[string]interface{})
    	m1["name"] = "jack"
    	m1["age"] = "7"
    	m1["addresss"] = "北京"
    	slice = append(slice, m1)
    
    	var m2 map[string]interface{}
    	m2 = make(map[string]interface{})
    	m2["name"] = "tom"
    	m2["age"] = "20"
    	m2["address"] = [2]string{"墨西哥", "夏威夷"}
    	slice = append(slice, m2)
    
    	data, err := json.Marshal(slice)
    	if err != nil {
    		fmt.Printf("序列化错误 err=%v
    ", err)
    	}
    
    	//输出序列化后的结果
    	fmt.Printf("slice 序列化后=%v
    ", string(data))
    }
    
    //对基本数据类型序列化,对基本数据类型进行序列化意义不大
    func testFloat64() {
    	var num float64 = 2345.67
    
    	data, err := json.Marshal(num)
    
    	if err != nil {
    		fmt.Printf("序列化错误 err=%v
    ", err)
    	}
    
    	//输出序列化后的结果
    	fmt.Printf("num序列化后=%v
    ", string(data))
    }
    
    func main() {
    	testStruct()
    	testMap()
    	testSlice()
    	testFloat64()
    }
    

    对于结构体的序列化,如果希望序列化后的key的名字重新制定,那么可以给struct指定一个tag标签。

    package main
    
    import (
    	"encoding/json"
    	"fmt"
    )
    
    type Monster struct {
    	Name     string `json:"monster_name"`
    	Age      int    `json:"monster_age"`
    	Birthday string
    	Sal      float64
    	Skill    string
    }
    
    //序列化结构体
    func testStruct() {
    	monster := Monster{
    		Name:     "牛魔王",
    		Age:      500,
    		Birthday: "2011-11-11",
    		Sal:      8000.0,
    		Skill:    "牛魔拳",
    	}
    
    	//将monster序列化
    	data, err := json.Marshal(&monster)
    	if err != nil {
    		fmt.Printf("序列化错误 err=%v
    ", err)
    	}
    
    	//输出序列化后的结果
    	fmt.Printf("monster序列化后=%v
    ", string(data))
    }
    
    func main() {
    	testStruct()
    }
    

    2、json的反序列化

    json反序列化是指将json字符串反序列化成对应的数据类型(比如结构体、map、切片)的操作。

    package main
    
    import (
    	"encoding/json"
    	"fmt"
    )
    
    type Monster struct {
    	Name     string
    	Age      int
    	Birthday string
    	Sal      float64
    	Skill    string
    }
    
    //反序列化结构体
    func unmarshalStruct() {
    	str := "{"Name":"牛魔王","Age":500,"Birthday":"2011-11-11","Sal":8000,"Skill":"牛魔拳"}"
    
    	var monster Monster
    
    	err := json.Unmarshal([]byte(str), &monster)
    	if err != nil {
    		fmt.Printf("unmarshal err=%v
    ", err)
    	}
    
    	fmt.Printf("反序列化后 monster=%v monster.Name=%v
    ", monster, monster.Name)
    }
    
    //map序列化
    func testMap() string {
    	var a map[string]interface{}
    
    	a = make(map[string]interface{})
    
    	a["name"] = "红孩儿"
    	a["age"] = 30
    	a["address"] = "洪崖洞"
    
    	data, err := json.Marshal(a)
    	if err != nil {
    		fmt.Printf("序列化错误 err=%v
    ", err)
    	}
    
    	//输出序列化后的结果
    	fmt.Printf("map序列化后=%v
    ", string(data))
    	return string(data)
    }
    
    //反序列化map
    func unmarshalMap() {
    	str := "{"address":"洪崖洞","age":30,"name":"红孩儿"}"
    
    	var a map[string]interface{}
    
    	//反序列化map不需要make,因为make操作被封装到Unmarshal函数
    	err := json.Unmarshal([]byte(str), &a)
    
    	if err != nil {
    		fmt.Printf("unmarshal err=%v
    ", err)
    	}
    
    	fmt.Printf("反序列化后 a=%v
    ", a)
    }
    
    //反序列化map
    func unmarshalMap2() {
    	str := testMap()
    
    	var a map[string]interface{}
    
    	//反序列化map不需要make,因为make操作被封装到Unmarshal函数
    	err := json.Unmarshal([]byte(str), &a)
    
    	if err != nil {
    		fmt.Printf("unmarshal err=%v
    ", err)
    	}
    
    	fmt.Printf("反序列化后 a=%v
    ", a)
    }
    
    //反序列化切片
    func unmarshalSlice() {
    	str := "[{"address":"北京","age":"7","name":"jack"}," + "{"address":["墨西哥","夏威夷"],"age":"20","name":"tom"}]"
    
    	var slice []map[string]interface{}
    
    	err := json.Unmarshal([]byte(str), &slice)
    
    	if err != nil {
    		fmt.Printf("unmarshal err=%v
    ", err)
    	}
    
    	fmt.Printf("反序列化后 slice=%v
    ", slice)
    }
    func main() {
    	unmarshalStruct()
    	unmarshalMap()
    	unmarshalMap2()
    	unmarshalSlice()
    }
    

    在反序列化一个json字符串时,要确保反序列化后的数据类型和原来序列化前的数据类型一致。

    如果json字符串是通过程序获取到的,则不需要再对“转义处理。

  • 相关阅读:
    bzoj 1022: [SHOI2008]小约翰的游戏John anti_nim游戏
    spoj gss2 : Can you answer these queries II 离线&&线段树
    hduoj 1077 Catching Fish 求单位圆最多覆盖点个数
    HDUOJ Clear All of Them I 状压DP
    bzoj 1013: [JSOI2008]球形空间产生器sphere 高斯消元
    bzoj 1006: [HNOI2008]神奇的国度 弦图的染色问题&&弦图的完美消除序列
    Cocos2d-x Lua中生命周期函数
    Cocos2d-x Lua中使用标签
    Cocos2d-x Lua中Sprite精灵类
    Cocos2d-x Lua Node与Node层级架构
  • 原文地址:https://www.cnblogs.com/xidian2014/p/10666906.html
Copyright © 2011-2022 走看看