创建/删除目录
Go语言IO操作可以通过os包或bufio包,bufio是带缓冲的
创建目录:
-
os.Mkdir():创建单个目录,如果存在则失败
-
os.MkdirAll():创建多级目录,如果存在则不操作
name | perm |
---|---|
文件路径 | 操作权限 |
func main() {
// ModePerm = 0777 授最高权限,
err := os.Mkdir("/Users/itzhuzhu/Desktop/笔记", os.ModePerm)
if err != nil {
fmt.Println("Mkdir创建目录失败:", err)
} else {
fmt.Println("Mkdir创建目录成功")
}
err = os.MkdirAll("/Users/itzhuzhu/Desktop/笔记/a/b/c", os.ModePerm)
if err != nil {
fmt.Println("MkdirAll创建目录失败:", err)
} else {
fmt.Println("MkdirAll创建目录成功")
}
}
删除文件或目录:
- Remove:删除文件或空目录,不存在则报错
- RemoveAll:删除文件或目录(包含所有子目录),不存在不操作
func main() {
err := os.Remove("/Users/itzhuzhu/Desktop/笔记/test")
if err != nil {
fmt.Println("Remove删除目录失败:", err)
} else {
fmt.Println("Remove删除目录成功")
}
err = os.RemoveAll("/Users/itzhuzhu/Desktop/笔记/a")
if err != nil {
fmt.Println("RemoveAll删除目录失败:", err)
} else {
fmt.Println("RemoveAll删除目录成功")
}
}
创建文件:
os.Create:文件不存在则创建,存在则删除文件中的内容,成为新文件,该函数本质上是在调用os.OpenFile()函数,
func main() {
// 返回创建文件的指针
file, err := os.Create("/Users/itzhuzhu/Desktop/笔记/test.txt")
if err != nil {
fmt.Println("创建失败 ", err)
}
fmt.Println("创建成功 ")
defer file.Close()
}
打开文件:
os.OpenFile():打开文件,OpenFile有三个参数:
- name:打开文件的路径
- flag:模式,常见的模式有
参数 | 说明 |
---|---|
O_RDONLY | 只读方式打开 |
O_WRONLY | 只写方式打开 |
O_RDWR | 读写方式打开 |
O_APPEND | 追加方式打开 |
O_CREATE | 不存在,则创建 |
O_EXCL | 如果文件存在,且标定了O_CREATE的话,则产生一个错误 |
O_TRUNC | 如果文件存在,且它成功地被打开为只写或读写方式,将其长度裁剪唯一(覆盖) |
O_NOCTTY | 如果文件名代表一个终端设备,则不把该设备设为调用进程的控制设备 |
O_NONBLOCK | 如果文件名代表一个FIFO,或一个块设备,字符设备文件,则在以后的文件及I/O操作中置为非阻塞模式 |
O_SYNC | 当进行一系列写操作时,每次都要等待上次的I/O操作完成再进行 |
- perm:表示权限,取值范围(0-7),和linux里操作文件那个权限一样,如果是用OpenFile打开目录写os.ModeDir
0:没有任何权限
1:执行权限(如果是可执行文件,是可以运行的)
2:写权限
3:写权限与执行权限
4:读权限
5:读权限与执行权限
6:读权限与写权限
7:读权限,写权限,执行权限
演示:
func main() {
file, err := os.OpenFile("/Users/itzhuzhu/Desktop/笔记/test.txt", os.O_RDWR, 6)
if err != nil {
fmt.Println("打开失败", err)
}
fmt.Println("打开成功")
defer file.Close()
}
使用Open也可以打开文件,Open底层调用的是OpenFile方法,但是参数是写死了(只读模式),源码如下
func Open(name string) (*File, error) {
return OpenFile(name, O_RDONLY, 0)
}
读数据:
Read:一次读全部数据,os.Read(读取后存放的切片)
func main() {
file, err := os.Open("/Users/itzhuzhu/Desktop/笔记/test.txt")
if err != nil {
fmt.Println("打开文件失败:", err)
}
defer file.Close()
// 定义一个切片存储文件读取的数据
buffer := make([]byte, 1024)
// len:返回读到数据的字节(文件大小)
len, err := file.Read(buffer)
if err != nil {
fmt.Println("读取数据失败:", err)
}
fmt.Println("读到:", len, "字节")
fmt.Println("内容为:", string(buffer)) // 将读到的字节数据转换为string才可以展示出内容
}
ReadFile:读数据更方便,不需要先用Open打开文件,底层调用了Open会自动完成
func main() {
readFile, _ := os.ReadFile("/Users/itzhuzhu/Desktop/笔记/test.txt")
fmt.Println(string(readFile))
}
ReadDir读目录:
func main() {
file, err := os.OpenFile("/Users/itzhuzhu/Desktop/笔记", os.O_RDONLY, os.ModeDir)
if err != nil {
fmt.Println(err)
}
defer file.Close()
// 参数:要获取的目录数,全部为负数,通常写-1
dirAll, _ := file.ReadDir(-1)
for _, name := range dirAll {
if name.IsDir() {
fmt.Println("目录:", name.Name())
} else {
fmt.Println("文件:", name.Name())
}
}
}
写数据:
Write:一次写入全部数据:
func main() {
file, err := os.OpenFile("/Users/itzhuzhu/Desktop/笔记/test.txt", os.O_RDWR, 6)
if err != nil {
fmt.Println("打开失败:", err)
}
str := "我是写进去的数据"
len, err := file.WriteString(str)
if err != nil {
fmt.Println("写入失败:", err)
}
fmt.Println("写入成功,长度为:", len, "字节")
defer file.Close()
}
WriteString:底层调用了Write做了数据转换,参数不需要转字节切片就可以使用
func main() {
file, err := os.OpenFile("/Users/itzhuzhu/Desktop/笔记/test.txt", os.O_RDWR, 6)
if err != nil {
fmt.Println("打开失败:", err)
}
str := "我是写进去的数据"
len, err := file.WriteString(str)
if err != nil {
fmt.Println("写入失败:", err)
}
fmt.Println("写入成功,长度为:", len, "字节")
defer file.Close()
}
WriteAt写数据:在指定的位置写入数据
方法 | 参数 | 返回值 |
---|---|---|
func (f *File) Seek(offset int64, whence int) (ret int64, err error) | offset:偏移量(空格数) whence:从哪里开始偏移 SeekStart = 0 // 文件的开头 SeekCurrent = 1 // 当前数据的位置 SeekEnd = 2 // 文件的末尾 | 偏移量长度 |
Seek:设置下一次读/写的起始的偏移量(位置)
func main() {
path := "/Users/itzhuzhu/Desktop/笔记/test.txt"
file, err := os.OpenFile(path, os.O_RDWR, 6)
if err != nil {
fmt.Println("打开失败:", err)
}
defer file.Close()
str := "我是WriteAt在指定位置写入的数据"
/*
whence:从哪里开始偏移
SeekStart = 0 // 文件的开头,会从头覆盖原数据,直到将新数据全部写完
SeekCurrent = 1 // 当前数据的位置
SeekEnd = 2 // 文件的末尾
*/
num, err := file.Seek(0, 1)
/*
参数1:要写的数据
参数2:是要写入数据的开始索引,上面引用了io.SeekEnd可以计算出原数据的长度,然后就可以在原数据基础上追加数据,如果写0会从0索引覆盖原数据
返回值1:写入的字符长度
返回值2:异常信息
*/
len, err := file.WriteAt([]byte(str), num)
if err != nil {
fmt.Println("写入失败:", err)
}
fmt.Println("共写入数据:", len, "字节")
}
缓冲区读数据:
缓冲区的设计是为了减少读/写大量数据带来的内存开销,先把数据读/写到缓冲区,然后由缓冲区写入系统。当发起一次读写操作时,计算机会先从缓冲区获取数据,如果当缓冲区数据为空,才会从数据源获取数据更新到缓冲区。
方法 | 作用 |
---|---|
func NewReader(rd io.Reader) *Reader | 创建一个具有默认大小的缓冲区,底层调用了NewReaderSize |
func NewReaderSize(rd io.Reader, size int) *Reader | 创建一个具有4096字节的缓冲区 |
func (b *Reader) ReadBytes(delim byte) ([]byte, error) | 1次读1个字节 |
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) | 1次读1行,由\n分割 |
func (b *Reader) ReadRune() (r rune, size int, err error) | 1次读1个字符 |
func (b *Reader) ReadString(delim byte) (string, error) | 1次读1个字符串 |
NewReaderSize读数据
func main() {
file, err := os.Open("/Users/itzhuzhu/Desktop/笔记/test.txt")
if err != nil {
fmt.Println(err)
}
defer file.Close()
// 读数据,定义一个切片存储文件读取的数据
r := bufio.NewReaderSize(file, 4096)
// 按行读数据,ReadBytes(遇到则停止的字符)
for {
buf, err := r.ReadBytes('\n')
// 先打印已读到的数据
fmt.Print(string(buf))
// 遇到\n继续读下一行
if err == io.EOF {
return
}
}
}
NewReader读数据
func main() {
file, err := os.Open("/Users/itzhuzhu/Desktop/笔记/test.txt")
// 底层调用了NewReaderSize,默认大小是4096
r := bufio.NewReader(file)
}
使用ReadLine读数据,缓冲区读数据会判断最后返回的有么有EOF,如果没有就继续读,如果有就结束,所以会多读一次。
ReadLine底层调用了ReadSlice,ReadSlice会判断是否遇到\n,如果
func main() {
file, err := os.Open("/Users/itzhuzhu/Desktop/笔记/test.txt")
if err != nil {
fmt.Println(err)
}
defer file.Close()
r := bufio.NewReaderSize(file, 4096)
i := 0
for {
// line:读到的数据
i++
line, _, err := r.ReadLine()
fmt.Println("第", i, "次读数据\t", "大小为:", len(line))
fmt.Println("数据:", string(line))
if err == io.EOF {
return
}
}
}
输出:
第 1 次读数据 大小为: 3
数据: 1
第 2 次读数据 大小为: 1
数据: 2
第 3 次读数据 大小为: 1
数据: 3
第 4 次读数据 大小为: 1
数据: 3
第 5 次读数据 大小为: 0
数据:
使用ReadRune读数据
func main() {
file, err := os.Open("/Users/itzhuzhu/Desktop/笔记/test.txt")
if err != nil {
fmt.Println(err)
}
defer file.Close()
r := bufio.NewReaderSize(file, 4096)
for {
// size:读到的大小
readRune, _, err := r.ReadRune()
fmt.Print(string(readRune))
if err == io.EOF {
return
}
}
}
ReadString读数据
func main() {
file, err := os.Open("/Users/itzhuzhu/Desktop/笔记/test.txt")
if err != nil {
fmt.Println(err)
}
defer file.Close()
r := bufio.NewReaderSize(file, 4096)
for {
readString, err := r.ReadString('\n')
fmt.Print("数据为:", string(readString))
if err == io.EOF {
return
}
}
}
Scanner读数据
方法 | 作用 |
---|---|
func NewScanner(r io.Reader) *Scanner | 自带缓冲区的读数据方法,大小为4096,默认按行分割 |
func (s *Scanner) Scan() bool | 指定读取分割的方式 |
Split函数分割的方式:
方法 | 作用 |
---|---|
ScanBytes | 按字节分割 |
SacanLines | 按行分割 |
SacanRunes | 按UTF-8字符分割 |
SacanWords | 按单词分割 |
演示:
func main() {
file, err := os.Open("/Users/itzhuzhu/Desktop/笔记/test.txt")
if err != nil {
fmt.Println("打开文件失败:", err)
}
defer file.Close()
// 创建读数据缓冲
reader := bufio.NewReader(file)
// 创建Scanner对象
scanner := bufio.NewScanner(reader)
// 指定按行读
scanner.Split(bufio.ScanLines)
// 循环读取
for scanner.Scan() {
// 打印读到的数据
fmt.Println(string(scanner.Bytes()))
fmt.Println(scanner.Text())
}
}
缓冲区写数据:
方法 | 作用 |
---|---|
func NewWriter(w io.Writer) *Writer | 创建一个具有默认大小的缓冲区,底层调用了NewReaderSize |
func NewWriterSize(w io.Writer, size int) *Writer | 创建一个具有4096字节的缓冲区 |
func (b *Writer) Flush() error | 清空缓冲区并将数据写入 |
func (b *Writer) WriteByte(c byte) error | 1次写1个字节 |
func (b *Writer) WriteRune(r rune) (size int, err error) | 1次写1个字符 |
func (b *Writer) WriteString(s string) (int, error) | 1次写1个字符串 |
NewWriter写数据
func main() {
readPath := "/Users/itzhuzhu/Desktop/笔记/test.txt"
writerPath := "/Users/itzhuzhu/Desktop/笔记/test2.txt"
// 打开要读的文件
readFile, err := os.Open(readPath)
if err != nil {
fmt.Println(err)
}
defer readFile.Close()
// 创建读缓冲区
reader := bufio.NewReader(readFile)
// 打开要写的文件
writerFile, err := os.OpenFile(writerPath, os.O_RDWR, 6)
if err != nil {
fmt.Println(err)
}
defer writerFile.Close()
// 创建写缓冲区
writer := bufio.NewWriter(writerFile)
// 循环读数据
for {
bytes, err := reader.ReadBytes('\n')
// 读到了就写到写缓冲区
writer.Write(bytes)
// 清空缓冲区,并将缓冲区的数据写到文件
writer.Flush()
if err == io.EOF {
break
}
}
}
文件权限:
例:- rwx rwx rwx权限用八进制表示为:0777
位置 | 含义 |
---|---|
第1位 | 文件类型(d:目录 - :文件) |
第2 ~ 4位 | u:所属用户权限 |
第5 ~ 7位 | g:所属组权限 |
第8 ~ 10位 | o:其他用户权限 |
权限使用数字表示:
权限 | 八进制数字 |
---|---|
r | 4 |
w | 2 |
x | 1 |
- | 0 |
filepath:
方法 | 作用 | |
---|---|---|
func IsAbs(path string) bool | 是否绝对路径 | |
func Split(path string) (dir, file string) | 分割为目录和文件名 | |
func Join(elem …string) string | 将多个字符拼接成路径 | |
func Ext(path string) string | 返回拓展名,如果是目录则为空 | |
func Base(path string) string | 返回路径中最后一个元素 | |
func Dir(path string) string | 返回是目录的路径 | |
func ToSlash(path string) string | 将路径分隔符替换为/ |
演示:
func main() {
path := "/Users/itzhuzhu/Desktop/笔记/test.txt"
str := "aaa"
fmt.Println("是否绝对路径:", filepath.IsAbs(path))
dir, file := filepath.Split(path)
fmt.Println("目录名:", dir, "\t文件名:", file)
fmt.Println("多个字符拼接成路径", filepath.Join(path, str))
ext := filepath.Ext(path)
fmt.Println("拓展名为", ext) // 如果是目录结果为空
base := filepath.Base(path)
fmt.Println("路径中最后一个元素为:", base)
s := filepath.Dir(path)
fmt.Println("目录部分为:", s)
slash := filepath.ToSlash(path)
fmt.Println("将路径分隔符替换为/", slash)
}
输出:
是否绝对路径: true
目录名: /Users/itzhuzhu/Desktop/笔记/ 文件名: test.txt
多个字符拼接成路径 /Users/itzhuzhu/Desktop/笔记/test.txt/aaa
拓展名为 .txt
路径中最后一个元素为: test.txt
目录部分为: /Users/itzhuzhu/Desktop/笔记
将路径分隔符替换为/ /Users/itzhuzhu/Desktop/笔记/test.txt
Stat
Stat可以查看文件属性
type FileInfo interface {
Name() string // 文件名称
Size() int64 // 文件大小(字节)
Mode() FileMode // 文件权限
ModTime() time.Time // 修改时间
IsDir() bool // 是否为目录
Sys() any // 底层数据源,不知道这是干嘛的
}
演示:
func main() {
path := "/Users/itzhuzhu/Desktop/笔记/test22.txt"
stat, err := os.Stat(path)
if err != nil {
fmt.Println("路径错误:", err)
}
fmt.Println("文件名称:", stat.Name())
fmt.Println("文件大小:", stat.Size(), "字节")
fmt.Println("当前权限:", stat.Mode())
fmt.Println("修改时间:", stat.ModTime())
fmt.Println("是否为目录:", stat.IsDir())
fmt.Println("底层数据源:", stat.Sys())
}
IsNotExist
判断文件是否存在
func main() {
_, err := os.Stat("/Users/itzhuzhu/Desktop/笔记/test.txt")
if os.IsNotExist(err) {
fmt.Println("文件不存在")
} else {
fmt.Println("文件存在")
}
}
Copy
func main() {
// 打开原数据文件
oldFile, err := os.Open("/Users/itzhuzhu/Desktop/笔记/test.txt")
if err != nil {
fmt.Println("打开源文件失败", err)
}
defer oldFile.Close()
// 打开新文件
newFile, err := os.OpenFile("/Users/itzhuzhu/Desktop/笔记/NewTest.txt", os.O_RDWR|os.O_CREATE, 0777)
if err != nil {
fmt.Println("打开新文件失败", err)
}
defer newFile.Close()
// dst:新文件 str:源文件
written, err := io.Copy(newFile, oldFile)
if err != nil {
fmt.Println("复制失败", err)
} else {
fmt.Println("复制成功,共", written, "字节")
}
}