Seeker
设置光标的位置, 读写文件
上图中第一个参数 offset 为偏移量, 第二个参数 whence 为如何设置 (当前光标的位置)
理解参数设置, 如何定位想要的位置 ?
-
- 定下当前光标所在位置
-
- 确定偏移量
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 读取文件
file, _ := os.OpenFile("D:\Environment\GoWorks\src\studygo\basic_learn02\a.txt",
os.O_RDWR, os.ModePerm)
defer file.Close()
file.Seek(2, io.SeekStart) // +x 光标往后 -x 光标往前
buf := []byte{0}
file.Read(buf)
fmt.Println(string(buf))
file.Seek(2, io.SeekCurrent) // 移动光标
file.Read(buf) // 读光标后的字符
fmt.Println(string(buf))
// 在结尾追加内容
file.Seek(0, io.SeekEnd)
file.WriteString("hello, sam")
}
断点续传
如何实现断点续传?
这里采用的是分片传, 记录其间传的文件光标位置, 支持恢复上传
package main
import (
"fmt"
"io"
"os"
"strconv"
"time"
)
// 实现简易的断点续传
func main() {
// 传输数据源文件
srcFile := "D:\OneDrive_files\OneDrive - ebl6\桌面\client\1.jpg"
now := time.Now().Format("150405")
//fmt.Println(now)
// 传输的目的地址
destFile := "D:\Environment\GoWorks\src\studygo\basic_learn02\server\" + now + ".jpg"
// 创建临时文件 (能够持续化存储, 这种直接将偏移值放在txt里, 然后读取 效率高)
tempFile := "D:\Environment\GoWorks\src\studygo\basic_learn02\temp.txt"
file, _ := os.Open(srcFile) // 源文件
file1, _ := os.OpenFile(destFile, os.O_CREATE|os.O_RDWR, os.ModePerm) // 目标文件
file2, _ := os.OpenFile(tempFile, os.O_CREATE|os.O_RDWR, os.ModePerm) // 临时文件
defer file.Close()
defer file1.Close()
file2.Seek(0, io.SeekStart)
buf := make([]byte, 1024, 1024)
n, _ := file2.Read(buf) // 找光标位置
// 把读出的内容转换成 数字 (为下步寻找传输文件的光标做准备)
conStr := string(buf[:n])
i, _ := strconv.ParseInt(conStr, 10, 64) // 十进制 64位
fmt.Println(i)
// 设置偏移量 (读写文件中的光标要保持一致)
file.Seek(i, io.SeekStart) // 可以做到断点续传
file1.Seek(i, io.SeekStart)
// 开始传输
bufData := make([]byte, 1024, 1024)
// 记录读取了多少个字符
total := int(i)
for {
//fmt.Println(total)
read, err := file.Read(bufData)
if err == io.EOF { // 源文件数据已读完
fmt.Println("文件传输完毕")
file2.Close()
os.Remove(tempFile)
break
}
// 向目标文件写入数据
write, _ := file1.Write(bufData[:read])
//fmt.Println(write)
// 若读到一半就出意外了 如何处理
// 1. 重新下载 2. 上次记录的total大小/bufSize(缓冲区大小) + write 可以找到出意外没传输完的光标位置
// 将写入的字符数记录在 total中 -> 记录断点续传的进度
total += write
// 存放临时记录
file2.Seek(0, io.SeekStart)
file2.WriteString(strconv.Itoa(total)) // 覆盖
//if total > 10240 {
// panic("断电了..")
//}
//time.Sleep(time.Second * 2)
}
}
遍历文件夹
package main
import (
"fmt"
"log"
"os"
)
// 遍历文件夹
// 递归实现
// 是文件的话就读名字
// 是文件夹的话就进入 .isDir() 来判断
func main() {
// 获取目录信息
Michael_tree("D:\Environment\GoWorks\src\studygo\basic_learn02", 0)
}
func Michael_tree(dir string, level int) { // 第一个参数为路径 第二个参数记录目录层数
// 层级
tree_level := "|--"
for i := 0; i < level; i++ {
tree_level += "|--"
}
infos, err := os.ReadDir(dir) // 返回的是切片 []DirEntry -> 多个文件信息
if err != nil {
log.Println(err) // log 日志输出
}
for _, file := range infos { // index, value
// 文件全路径
filename := dir + "\" + file.Name()
//fmt.Print(tree_level) // 加层次~
fmt.Print(tree_level + file.Name())
fmt.Println()
if file.IsDir() {
Michael_tree(filename, level+1)
}
}
}
bufio
Go 自带的IO操作包
使用bufio 进行文件读取, 以及读取键盘输入
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
file, err := os.Open("这里换成待读入的文件名(绝对路径)") // 默认是只读模式打开
if err != nil {
log.Println(err)
}
defer file.Close()
reader := bufio.NewReader(file)
//buf := make([]byte, 1024, 1024)
//n, err := reader.Read(buf)
//if err != io.EOF {
// log.Println(err)
//}
//fmt.Println("读取到了多少个字节: ", n)
//fmt.Println("读取数据", string(buf[:n]))
line, _, _ := reader.ReadLine()
fmt.Println(string(line)) // 读一行数据
// 读取键盘输入 (I/O读入)
newReader := bufio.NewReader(os.Stdin)
readString, _ := newReader.ReadString('\n') // 读取键盘输入的信息(以'\n'回车符为分隔)
fmt.Println("读取键盘信息: ", readString)
}
使用bufio 对文件进行写入操作, bufio 会先将输入文件的内容放在缓冲区中, 需要通过手动刷新缓冲区, 这样内容才真正写到文件里 .
package main
import (
"bufio"
"fmt"
"os"
)
// bufio 写入文件
func main() {
file, _ := os.OpenFile("这里换成待操作的文件名(绝对路径)",
os.O_WRONLY|os.O_WRONLY,
os.ModePerm) // 最后一个参数是权限
defer file.Close()
// bufio 写入
bufioWriter := bufio.NewWriter(file)
writeNum, _ := bufioWriter.WriteString("HELLO?")
fmt.Println("写入的字符数:", writeNum)
// 发现文件还是没有写入
// 是因为写入的内容还在缓冲区, 我们需要 flush(手动刷新)缓冲区 这样才能写入到文件中~
bufioWriter.Flush() // 默认是从从头开始写 (光标)
}