文件 & IO 操作

文件 & IO操作

文件操作#

读取文件#

相对路径读取

多次遍历读取

os.open:针对磁盘

相对路径:相对运行程序的路径

Copy
func main() { path := "user.txt" file, err := os.Open(path) // 返回指针和错误信息 fmt.Println(err) // nil fmt.Println(file) // &{0xc00014e780} fmt.Printf("%T", file) // *os.File if err != nil { fmt.Println(err) } else { var bytes []byte = make([]byte, 20) // 长度为20的字节切片 for { n, err := file.Read(bytes) // 返回长度和错误,但是最多读取20个元素,相当于读取文件后将切片填充 if err == io.EOF { // 当读取完毕,返回EOF break // 读取完毕,退出循环 } else if err != nil { // 如果返回不为空,但是报其他错误 fmt.Println(err) // 将错误结果输出 } else { fmt.Println(string(bytes[:n])) // 反之没有读完,继续读取,但一行只读取20个字符 } } file.Close() // 关闭文件 } }
  • 一次性读取完
  • ioutil
Copy
func main() { file, err := os.Open("user.txt") if err == nil { bytes, err := ioutil.ReadAll(file) // 所有内容一次性读出,返回字节切片 fmt.Println(string(bytes), err) // 将字节切片转换为字符串 file.Close() } }
  • ioutil写入
Copy
func main() { err := ioutil.WriteFile("abc.txt", []byte("xxxxxxxxxxxxxx"), os.ModePerm) fmt.Println(err) }

写入文件#

两种写入方式:

  1. 字节切片形式写入,存储还是字符串
  2. WriteString,存储为字符串
Copy
// 写入文件,先清除再写入 func main() { path := "user1.txt" file, err := os.Create(path) // 创建文件,返回指针和错误 if err != nil { fmt.Println(err) } else { file.Write([]byte("abcdefj")) // 字节切片方式写入,最后存储还是字符串 file.WriteString("abc123") // 字符串方式写入,返回int和error file.Close() } }

文件追加#

Copy
func main() { path := "user.log" // os.O_APPEND: 追加写入 // os.O_CREATE: 文件不存在就创建 file, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE, os.ModePerm) if err == nil { // 模拟将当前时间(int64转换为字符串)写入文件 file.WriteString(strconv.FormatInt(time.Now().Unix(), 10)) file.WriteString("\n") file.Close() } }
  • 模拟日志信息写入文件
Copy
func main() { path := "user.log" // os.O_APPEND: 追加写入 // os.O_CREATE: 文件不存在就创建 file, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE, os.ModePerm) if err == nil { log.SetOutput(file) // 设置日志输出到文件 log.Print(time.Now().Unix()) file.Close() } }

文件指针(少用)#

Copy
func main() { file, _ := os.Open("user.txt") // 偏移量,相对位置 // 文件开始 0 // 当前位置 1 // 文件末尾 2 file.Seek(3, 0) bytes := make([]byte, 100) // 返回int64和err n, err := file.Read(bytes) fmt.Println(n, err, string(bytes[:n])) file.Close() }

获取文件信息#

Copy
func main() { //os.Rename("abc.txt", "ddd.txt") // 重命名文件 //os.Remove("ddd.txt") // 删除文件 //os.Mkdir("ddd", 0644) // 创建目录权限为0644 //os.MkdirAll("tesst01/xxx", 0644) // 在不存在的test01目录下创建xxx目录 //os.RemoveAll("tesst01") // 目录中有文件也一起删除 // 判断文件是否存在 // 如果不存在,则提示文件不存在,否则关闭文件 //file, err := os.Open("llc.txt") //if err != nil { // if os.IsNotExist(err) { // fmt.Println("文件不存在") // } //} else { // file.Close() //} for _, path := range []string{"user.log", "user.txt", "ddd"} { info, err := os.Stat(path) if err != nil { if os.IsNotExist(err) { fmt.Println("文件不存在") } } else { fmt.Println(strings.Repeat("*", 20)) fmt.Println(info.Name()) // 获取文件名称 fmt.Println(info.IsDir()) // 是否是目录 fmt.Println(info.Size()) // 文件大小 fmt.Println(info.ModTime()) // 修改时间 if info.IsDir() { dirfile, err := os.Open(path) if err != nil { defer dirfile.Close() //childrens, _ := dirfile.Readdir(-1) // 获取所有信息,-1 为获取所有参数 //for _, children := range childrens { // fmt.Println(children.Name(), children.IsDir(), children.Size(), children.ModTime()) //} names, _ := dirfile.Readdirnames(-1) // 获取文件夹信息 for _, name := range names { fmt.Println(name) } } } } } }

获取文件路径#

Copy
func main() { fmt.Println(os.TempDir()) fmt.Println(os.UserCacheDir()) fmt.Println(os.UserHomeDir()) // 获取用户主目录 path, _ := filepath.Abs(os.Args[0]) dirpath := filepath.Dir(path) fmt.Println(filepath.Abs(".")) // 获取运行当前目录 fmt.Println(filepath.Abs(os.Args[0])) // 获取运行程序绝对路径 fmt.Println(filepath.Base(path)) // 获取运行程序名 fmt.Println(filepath.Dir(path)) // 获取运行程序目录 fmt.Println(filepath.Ext(path)) // 获取文件后缀 inipath := dirpath + "/conf/ip.ini" // 路径拼接 fmt.Println(inipath) fmt.Println(filepath.Join(dirpath, "config", "ip.init")) // 推荐路径拼接方式 fmt.Println(filepath.Glob("./*.ext")) // 找当前目录下所有.exe结尾的文件 filepath.Walk(".", func(path string, fileInfo os.FileInfo, err error) error { fmt.Println(path, fileInfo.Name()) // 遍历一个目录下所有文件 return nil }) }

标准输入输出#

Copy
func main() { // os.Stdout fmt.Println("xxx") // os.Stdin bytes := make([]byte, 5) n, err := os.Stdin.Read(bytes) // 获取命令行输入 fmt.Println(n, err, bytes) // 将输入信息放入buffer中打印 scanner := bufio.NewScanner(os.Stdin) scanner.Scan() fmt.Println(scanner.Text()) // 传递文件输出对象 fmt.Fprintf(os.Stdout, "%", 1) }

带缓冲的io#

bufio带缓冲io读#

按行读取文件,for遍历

bufio好处:

将文件读取到内存中作处理,并不会直接对函数或者方法做处理

Copy
func main() { file, err := os.Open("user.txt") if err == nil { defer file.Close() // 延迟函数,放在代码最后执行 i := 0 scanner := bufio.NewScanner(file) // 创建对象 for scanner.Scan() { // 将buffer中的信息一行行扫描 fmt.Println(i, scanner.Text()) // 获取数据 i++ } } } /* 0 my name is tcy 1 dfsakjdfasjdfsdls 2 my name is tcymy name is 3 tcymy name is tcymy name is tcymy name is tcy 4 aaaa 5 bbbbb 6 ddddd 7 cccc */

按行读取文件,for遍历

Copy
func main() { file, err := os.Open("user.txt") if err == nil { defer file.Close() reader := bufio.NewReader(file) for { // 返回字节切片,布尔类型,错误信息 line, isPrefix, err := reader.ReadLine() if err != nil { if err != io.EOF { fmt.Println(err) } break } else { fmt.Println(isPrefix, err, string(line)) } } } } /* false <nil> my name is tcy false <nil> dfsakjdfasjdfsdls false <nil> my name is tcymy name is false <nil> tcymy name is tcymy name is tcymy name is tcy false <nil> aaaa false <nil> bbbbb false <nil> ddddd false <nil> cccc */

指定切割符号遍历

Copy
func main() { file, err := os.Open("user.txt") if err == nil { defer file.Close() reader := bufio.NewReader(file) for { // 返回字节切片,错误信息,指定\n进行切割 //line, err := reader.ReadSlice('\n') // 同样的切割,但针对字符串,而不是和上面一样使用字节切片,所以后面也可以直接打印 line, err := reader.ReadString('\n') if err != nil { if err != io.EOF { fmt.Println(err) } break } else { //fmt.Println(err, string(line)) fmt.Println(err, line) } } } } /* <nil> my name is tcy <nil> dfsakjdfasjdfsdls <nil> my name is tcymy name is <nil> tcymy name is tcymy name is tcymy name is tcy <nil> aaaa <nil> bbbbb <nil> ddddd */

bufio带缓冲写#

Copy
func main() { file, err := os.Create("user.txt") if err == nil { defer file.Close() write := bufio.NewWriter(file) write.WriteString("abcdef") write.Write([]byte("123455")) write.Flush() // 内存中的操作刷新到磁盘 } } /* abcdef123455 */

持久化#

CSV#

特点:

csv就是excel表格文件

存储都是每行用逗号分隔

  • 存入
Copy
func main() { file, err := os.Create("user.csv") if err == nil { defer file.Close() write := csv.NewWriter(file) write.Write([]string{"编号", "姓名", "电话"}) write.Write([]string{"1", "tcy", "110"}) write.Write([]string{"2", "twg", "188"}) write.Flush() } }
  • 读取
Copy
func main() { file, err := os.Open("user.csv") if err == nil { defer file.Close() reader := csv.NewReader(file) for { line, err := reader.Read() if err != nil { if err != io.EOF { fmt.Println(err) } break } else { fmt.Println(line) } } } }

编码解码gob#

使用gob进行编码解码,是go内置的,其他语言不支持

  • 编码,存储为字符串类型映射
Copy
func main() { // 编码 user := map[int]string{1: "汤采玉", 2: "汤文广", 3: "尹金秀"} file, err := os.Create("user03.txt") if err == nil { defer file.Close() encoder := gob.NewEncoder(file) // 创建对象,将新建文件传入 encoder.Encode(user) // 将映射信息编码存入 } }
  • 编码,存储为结构体类型映射
Copy
//编码 user := map[int]User{ 1: User{1, "tcy", time.Now()}, 2: User{2, "汤文广", time.Now()}, 3: {3, "汤国华", time.Now()}, } file, err := os.Create("user03.txt") if err == nil { defer file.Close() encoder := gob.NewEncoder(file) // 创建对象,将新建文件传入 encoder.Encode(user) // 将映射信息编码存入 }
  • 解码,查看字符串类型映射
Copy
func main() { // 解码查看 users := map[int]string{} file, err := os.Open("user03.txt") if err == nil { defer file.Close() decoder := gob.NewDecoder(file) decoder.Decode(&users) fmt.Println(users) // map[1:汤采玉 2:汤文广 3:尹金秀] } }
  • 解码,查看结构体类型映射
Copy
//解码查看 users := map[int]User{} file, err := os.Open("user03.txt") if err == nil { defer file.Close() decoder := gob.NewDecoder(file) decoder.Decode(&users) fmt.Println(users) // map[1:汤采玉 2:汤文广 3:尹金秀] }

strings/bytes#

strings#

场景:

当网络中传输过来的数据,放入到内存中,分批次处理,而不是直接在硬盘中处理。

针对文件,io操作上

  • string.Reader 读
Copy
func main() { // 创建对象 reader := strings.NewReader("abcdefgijk") bytes := make([]byte, 3) for { // 每次读指定长度 n, err := reader.Read(bytes) if err != nil { if err != io.EOF { fmt.Println(err) } break } else { fmt.Println(n, bytes[:n]) // 每次读取三个,每次打印三个元素 } } }
  • string.Builder 写
  • 不用每次对数据新增就新加一个变量,主要用来拼装字符串,主要是用切片做存储。可以用来提高字符串的操作速度。
Copy
// string.Builder var builder strings.Builder builder.Write([]byte("abc")) builder.WriteString("abcdefg!@#") fmt.Println(builder.String()) // abcabcdefg!@#

buffer#

  • 在内存中对字符串做操作
Copy
buffer := bytes.NewBufferString("badjdfj") buffer.Write([]byte("123")) buffer.WriteString("!@#") fmt.Println(buffer.String()) // badjdfj123!@# bytes := make([]byte, 2) buffer.Read(bytes) fmt.Println(string(bytes)) // ba 因为每次就读2个字节 line, _ := buffer.ReadString('!') // 按照!作为分隔符打印 fmt.Println(line) // djdfj123!

案例#

copyfile#

命令行参数写入源文件和目标文件,将源文件内容拷贝至目标文件,目标文件不存在则创建。

Copy
func copyfile(src, dest string) { srcfile, err := os.Open(src) if err != nil { fmt.Println(err) } else { defer srcfile.Close() destfile, err := os.Create(dest) if err != nil { fmt.Println(err) } else { defer destfile.Close() bytes := make([]byte, 1024*1024*10) // 初始化字节切片,单次容量为10m for { n, err := srcfile.Read(bytes) if err != nil { if err != io.EOF { fmt.Println(err) } break } destfile.Write(bytes[:n]) } } } } func main() { // 命令行传参,-s参数,默认值,描述信息,返回指针类型 src := flag.String("s", "", "src file") dest := flag.String("d", "", "dest file") help := flag.Bool("h", false, "help") flag.Usage = func() { fmt.Println(` Usage: copyfile -s srcfile -d destfile Option: `) flag.PrintDefaults() // 将所有参数帮助信息输出 } // 解析命令行 flag.Parse() if *help || *src == "" || *dest == "" { flag.Usage() } else { copyfile(*src, *dest) } //fmt.Printf("%v %v %v\n", *src, *dest, *help) }

md5计算文件或字符#

Copy
func md5file(path string) string { file, err := os.Open(path) if err != nil { fmt.Println(err) } else { defer file.Close() // 为了防止文件过大,使用批量读取文件的方式进行计算 bytes := make([]byte, 1024*1024*10) hasher := md5.New() for { n, err := file.Read(bytes) if err != nil { if err != io.EOF { fmt.Println(err) } break } else { hasher.Write(bytes[:n]) } } return fmt.Sprintf("%x", hasher.Sum(nil)) } return "" } func md5string(txt string) string { return fmt.Sprintf("%X", md5.Sum([]byte(txt))) } func main() { // md5值的计算,或者文件的计算 // -s :对参数字母的计算 // -f:文件的计算 txt := flag.String("s", "", "md5.txt") path := flag.String("f", "", "file path") help := flag.Bool("h", false, "help") flag.Usage = func() { fmt.Println(` Usage: md5.exe [-s 123abc] [-f filepath] Option: `) flag.PrintDefaults() } flag.Parse() if *help || *txt == "" && *path == "" { flag.Usage() } else { var md5 string if *path != "" { md5 = md5file(*path) } else { md5 = md5string(*txt) } fmt.Println(md5) } }
posted @   元气少女郭德纲!!  阅读(267)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
CONTENTS