【os】
os 基础使用
package main
import (
"fmt"
"os"
)
func main() {
/* os 模块 */
// os.Stat 获取文件信息 :FileInfo
fileInfo, err := os.Stat("/Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO/Readme.md")
if err != nil {
return
}
fmt.Println("该文件文件名:", fileInfo.Name())
fmt.Println("该文件大小:", fileInfo.Size(), "【单位:字节】")
fmt.Println("该文件是否是文件夹:", fileInfo.IsDir())
fmt.Println("该文件权限:", fileInfo.Mode())
fmt.Println("该文件更新时间:", fileInfo.ModTime())
}
os 创建文件夹
- os.Mkdir
- os.MkdirAll
- os.Remove
- os.RemoveAll
package main
import (
"fmt"
"os"
)
func main() {
/* os 模块 */
// os 创建目录,创建文件
/*
- 文件路径
- 相对路径 reference path,相对某个文件或者某个目录
- 绝对路径 absolute path, 从盘符开始
*/
// os.Mkdir(文件路径,权限0777) 创建一个文件夹。1.存在,2.不存在,创建
err1 := os.Mkdir("/Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO/noExistFile", os.ModePerm)
if err1 != nil {
fmt.Println(err1) // mkdir /Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO/noExistFile: file exists
} else {
fmt.Println("noExistFile创建成功")
}
// os.MkdirAll 递归创建文件夹
err2 := os.MkdirAll("/Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO/noExistFile/aa/bb/cc", os.ModePerm)
if err2 != nil {
fmt.Println(err2)
} else {
fmt.Println("多层文件夹创建成功")
}
// os.remove 移除文件夹【只能删除空目录】,删除文件
err3 := os.Remove("/Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO/noExistFile/aa/bb/cc")
if err3 != nil {
fmt.Println(err3) // : directory not empty 文件夹内还有文件,无法删除
} else {
fmt.Println("文件夹已删除")
}
// os.RemoveAll 全部删除,该文件夹内的文件也被删除
err4 := os.RemoveAll("/Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO/noExistFile/aa/bb/cc")
if err4 != nil {
fmt.Println(err4) // 强制删除文件夹
} else {
fmt.Println("有内容的文件夹,removeAll 全部删除")
}
}
os 创建文件
- os IO写文件。 注意权限问题:可读,可写,可追加, os.O_RDONLY|os.O_WRONLY|os.O_APPEND
- os.OpenFile 打开文件 并指定权限[只读,只写,读写,追加写等]
- os.OpenFile 如果没有 赋予 追加的权限,文件将会被清空后重新写一个新文件。
- 模式:os.O_RDONLY|os.O_WRONLY|os.O_APPEND|os.O_CREATE
- 权限:os.ModePerm
package main
import (
"fmt"
"os"
)
func main() {
/* os 模块 */
// os IO写文件。 注意权限问题:可读,可写,可追加, os.O_RDONLY|os.O_WRONLY|os.O_APPEND
// os.OpenFile 打开文件 并指定权限[只读,只写,读写,追加写等]
// os.OpenFile 如果没有 赋予 追加的权限,文件将会被清空后重新写一个新文件。
file3, _ := os.OpenFile("/Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO/noExistFile/WriteFile.txt", os.O_RDONLY|os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.ModePerm)
fmt.Println("file3:", file3)
defer file3.Close()
bs2 := []byte{65, 66, 67, 68}
file3.Write(bs2) // Write 只能写入字节码
file3.WriteString("追加一段字符传") // 写入一段字符串
}
os 实现 Copy 文件的三种方式
package main
import (
"fmt"
"io"
"os"
)
func copyFile01(src string, dest string, bufferSize int) error {
/*
src : 原始文件
dest : 拷贝文件
bufferSize: 缓冲区大小
*/
// 1. 读取原文件
srcFile, readFileErr := os.Open(src)
// 2. 处理读取文件错误
if readFileErr != nil {
fmt.Println("读取原文件错误:", readFileErr)
}
// 3. 打开目标文件. 赋予:读写和创建模式. 赋予:666权限:【4读2写1执行】(用户:可读写,用户组:可读写,其他:可读写)
destFile, writeFileErr := os.OpenFile(dest, os.O_RDWR|os.O_CREATE, 0666)
if writeFileErr != nil {
fmt.Println("写入新文件错误:", writeFileErr)
}
// 4. copy 业务逻辑具体实现
// - 4.1 字节缓冲区 : 设定读取字节切片。容量由外部传入
//字节缓冲区
byteSlice := make([]byte, bufferSize)
fmt.Printf("定义:byteSlice内存地址 :%p\n", byteSlice) // :0xc0000cec00
// - 4.2 使用for循环读取
for {
// - 4.3 字节类型切片接收数据,并写入数据
// 读取数据到字节切片内
readByteCount, readErr := srcFile.Read(byteSlice)
fmt.Printf("读前:byteSlice内存地址 :%p\n", byteSlice) // :0xc0000cec00
//fmt.Printf("读前:byteSlice内容 :%v\n", byteSlice) // :0xc0000cec00
fmt.Println("readByteCount:", readByteCount, "readErr:", readErr)
// readByteCount读取字节长度为:0 或者readErr为:io.EOF 表示文件读取完毕
if readByteCount == 0 || readErr == io.EOF {
fmt.Println("原文件读取完毕")
break // 终止循环
} else if readErr != nil {
fmt.Println("读取文件出现异常!", readErr)
// 终止函数继续执行,返回错误
return readErr
}
// 将 字节切片写入到 新文件中
fmt.Printf("写前:byteSlice内存地址 :%p\n", byteSlice) // :0xc0000cec00
//fmt.Printf("写前:byteSlice内容 :%v\n", byteSlice) // :0xc0000cec00
writeByteCount, writeErr := destFile.Write(byteSlice[:readByteCount])
fmt.Println("writeByteCount:", writeByteCount, "writeErr:", writeErr)
if writeErr != nil {
fmt.Println("写入文件失败", writeErr)
return writeErr
}
}
// 循环会影响 defer 执行
// 2. 延时关闭 读IO 连接
defer srcFile.Close() // 关闭 读io连接
// 5. 关闭写入IO连接
destFile.Close()
return nil
}
func copyFile02(src string, dest string) {
srcFile, readFileErr := os.Open(src)
if readFileErr != nil {
}
defer srcFile.Close()
destFile, writeFileErr := os.Create(dest)
if writeFileErr != nil {
}
defer destFile.Close()
// 使用 io 下的 Copy 拷贝文件
io.Copy(destFile, srcFile)
}
func copyFile03(src string, dest string) {
fileBuffer, _ := os.ReadFile(src)
os.WriteFile(dest, fileBuffer, 0666)
}
func main() {
/* os 模块 */
// os 文件复制 .
/*
流程: 原文件 , 目标文件, 缓冲区
1. 读取原文件,将读取的数据存储到缓冲区
2. 读取缓冲区的数据,将内容写入到新的文件
3. 确保读取原文时,是否读取完毕。 通过 EOF 判断
*/
src := "/Users/dengshuai/my_files/个人文件/家人/IMG20181201091508.jpg"
dest1 := "/Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO/noExistFile/aa/bb/family1.png"
dest2 := "/Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO/noExistFile/aa/bb/family2.jpg"
dest3 := "/Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO/noExistFile/aa/bb/family3.jpg"
copyErr := copyFile01(src, dest1, 1024)
fmt.Println("copyErr:", copyErr)
copyFile02(src, dest2)
copyFile03(src, dest3)
}
Seeker使用
- 设置光标位置,读取文件
- offset 偏移量
- whence 当前光标的位置
- Seek(offset int64, whence int) (int64, error)
package main
import (
"fmt"
"io"
"os"
)
func main() {
/*
Seeker接口使用
- 设置光标位置,读取文件
type Seeker interface {
// offset 偏移量
// whence 当前光标的位置
Seek(offset int64, whence int) (int64, error)
whence 如何设置参数:
// Seek whence values.
const (
SeekStart = 0 // seek relative to the origin of the file。文件开头
SeekCurrent = 1 // seek relative to the current offset 相对于当前光标的位置
SeekEnd = 2 // seek relative to the end 文件的末尾
)
}
*/
// 1. 读取文件
fileObj, _ := os.OpenFile("/Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO/noExistFile/WriteFile.txt", os.O_RDWR, os.ModePerm)
// 2. close 文件
defer fileObj.Close()
// 3. 测试 Seeker 方法
fileObj.Seek(2, io.SeekStart) // 从文件开头,往后偏移两个光标位置,默认光标从0开始
//fileObj.Seek(-2, io.SeekEnd) // 从文件结尾,往前偏移两个光标位置
buffer := make([]byte, 1) // 读取一个字节
n, _ := fileObj.Read(buffer)
fmt.Println(n)
fmt.Println(string(buffer))
fileObj.Seek(-1, io.SeekCurrent) // 从当前光标位置,再往前移动1位
// 从当前位置追加 字符串
fileObj.WriteString("haha")
}
文件断点续传
package main
import (
"fmt"
"io"
"os"
"strconv"
)
func main() {
/* 通过 io.Seeker 实现io断点续传 */
// 传输原文件地址
srcFile := "/Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO/client/a.png"
// 传输目标地址
destFile := "/Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO/server/new2.png"
// 临时文件记录
tmpFile := "/Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO/temp.txt"
// 逻辑思路
//fileSrc1, _ := os.Open(srcFile) // 读取原文件
fileSrc1, _ := os.OpenFile(srcFile, os.O_CREATE|os.O_RDWR, os.ModePerm) // 读取原文件
fileDest1, _ := os.OpenFile(destFile, os.O_CREATE|os.O_RDWR, os.ModePerm) // 写入新文件
fileTmp1, _ := os.OpenFile(tmpFile, os.O_CREATE|os.O_RDWR, os.ModePerm) // 临时文件存储seek记录
defer fileSrc1.Close()
defer fileDest1.Close()
// 1. 读取 temp.txt
fileTmp1.Seek(0, io.SeekStart)
buf := make([]byte, 1024, 1024) // 设置自己切片接收读取的字节
n, _ := fileTmp1.Read(buf) // 读取buf
// 2. 转换string 为 数字
countStr := string(buf[:n])
count, _ := strconv.ParseInt(countStr, 10, 64) // 将读取的字符转换成数量
fmt.Println("读取临时文件tmp.txt的数量:", count)
// 3. 设置新的偏移量
fileSrc1.Seek(count, io.SeekStart)
fileDest1.Seek(count, io.SeekStart)
// 4. 边读边写
bufData := make([]byte, 1024, 1025)
// 5. 记录读取多少字节
total := int(count)
for {
readNum, err := fileSrc1.Read(bufData)
println("readNum:", readNum)
if err == io.EOF {
// 读取完毕
fmt.Println("文件传输完毕!")
fileTmp1.Close()
os.Remove(tmpFile) // 移除临时文件
break
}
// 向目标文件写入字符
writeNum, err := fileDest1.Write(bufData[:readNum])
total += writeNum
// tmp.txt 存放临时写入多少字符量
fileTmp1.Seek(0, io.SeekStart)
fileTmp1.WriteString(strconv.Itoa(total))
fmt.Println(total)
// 模拟异常中断,导致数据传输失败
if total > 1022224 {
panic("断电了")
}
}
}
遍历文件夹
package main
import (
"fmt"
"os"
)
func tree(dir string, level int) {
// mac 版本哈!!!
// 编写层级
tabString := "|--"
for i := 0; i < level; i++ {
tabString = "|--" + tabString
}
// os.ReadDir 获取目录信息。 类型:[]DirEntry
fileInfos, err := os.ReadDir(dir)
if err != nil {
//log.Println(err)
}
for _, eachFile := range fileInfos {
filePath := dir + string(os.PathSeparator) + eachFile.Name()
filePathFmt := tabString + dir + string(os.PathSeparator) + eachFile.Name()
fmt.Println(filePathFmt)
if eachFile.IsDir() {
tree(filePath, level+1)
}
}
}
func main() {
/*
遍历文件夹
- 递归 方式实现遍历文件目录
*/
dir := "/Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO"
tree(dir, 0)
}
Go自带的IO操作包 bufio
- 使用bufio 可以大幅度提升文件读写效率
- buf 缓冲区
- 默认io操作效率还不错,还会频繁访问本地磁盘效率低。使用bufio修改缓冲区的大小
- 读写到新的缓冲区内。一次性写入或读取,减少磁盘访问频率。
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
/*
go 语言自带的IO操作包
- 使用bufio 可以大幅度提升文件读写效率
- buf 缓冲区
- 默认io操作效率还不错,还会频繁访问本地磁盘效率低。使用bufio修改缓冲区的大小
- 读写到新的缓冲区内。一次性写入或读取,减少磁盘访问频率。
*/
// bufio 的应用
file, err := os.Open("/Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO/demo05Seeker接口使用.go")
if err != nil {
log.Println(err)
}
defer file.Close()
// 读取文件
// 创建一个bufio包下的 reader 对象
bufioReader := bufio.NewReader(file)
//buf := make([]byte, 1024)
//n, err := bufioReader.Read(buf)
//fmt.Println("读取到多少个字节:", n)
//fmt.Println("内容:", string(buf[:n]))
// bufio 自己的方法
s1, _, _ := bufioReader.ReadLine() // 读一行
fmt.Println(string(s1))
// bufio 读取键盘输入流
inputerReader := bufio.NewReader(os.Stdin)
// delim 分隔符参数,必须是字符 byte
readString, _ := inputerReader.ReadString('\n')
fmt.Println("读取键盘输入信息:", readString)
}
bufio包的使用:写文件
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
/* 使用 bufio 写入文件*/
writeFilePath := "/Users/dengshuai/my_files/CProject/GoRoad/src/GoStudy/golang_base_17/day12IO/noExistFile/writeBufio.txt"
writeFile, _ := os.OpenFile(writeFilePath, os.O_CREATE|os.O_RDWR, os.ModePerm)
defer writeFile.Close()
// 使用bufio 写入
bufWriter := bufio.NewWriter(writeFile)
writeNum, _ := bufWriter.WriteString("12345")
fmt.Println("writeNum:", writeNum)
// 手动刷新进新文件
// 如果不实用flush,内容会存到缓冲区中。不会写入到文件
bufWriter.Flush()
}