Golang 文件及目录操作
文件操作:打开和关闭文件 os.Open()、file.Close()
- 读取文件
- file.Read() 读取文件
- bufio 读取文件
- ioutil 读取整个文件
- 写入文件 os.OpenFile()
- Write 和 WriteString
- bufio.NewWriter
- ioutil.WriteFile
- 重命名文件 os.Rename()
- 复制文件:自定义复制函数
目录操作:
- 创建目录 os.Makedir()、os.MakedirAll() // 创建多级目录,需注意文件权限问题
- 删除目录或文件 os.Remove()、os.RemoveAll()
打开和关闭文件
import (
"fmt"
"os"
)
func main() {
// 以只读的方式打开文件:os包,func Open(name string) (*File, error)
file, err := os.Open("./main.go")
if err != nil {
fmt.Println("open file failed", err)
return
}
fmt.Println(file) // &{0x14000116120}
// 关闭文件
defer file.Close() // 为了防止忘记关闭文件,通常使用 defer 注册文件关闭语句
}
读取文件
「 file.Read() 读取文件 」
func main() {
// 以只读方式打开文件
file, err := os.Open("./main.go")
if err != nil {
fmt.Println("file open failed")
return
}
defer file.Close() // 关闭文件
// 读取文件
tmp := make([]byte, 128) // 设置每次读取128个字节
// 基本语法:func (f *File) Read(b []byte) (n int, err error)
// 作用:它接收一个字节切片,返回读取的字节数和可能的具体错误;读到文件末尾时,会返回 0 和 io.EOF
n, err := file.Read(tmp)
if err == io.EOF {
fmt.Println("文件读完了")
return
}
if err != nil {
fmt.Println("file read failed")
return
}
fmt.Printf("读取了%v个字节 \n", n) // 读取了128个字节
fmt.Println(string(tmp[:n])) // 说明:打印main.go中的128个文件(但文件未读完)
// 使用for循环,读取文件中的所有数据
var content []byte
var tmp1 = make([]byte, 128)
for {
n1, err := file.Read(tmp1)
if err == io.EOF {
fmt.Println("文件读完了")
break
}
if err != nil {
fmt.Println("file read failed")
return
}
content = append(content, tmp1[:n1]...)
}
fmt.Println(string(content))
}
「 bufio 读取文件 」bufio 是在 io 的基础上封装了一层 API,支持更多的功能
func main() {
// 以只读方式打开文件
file, err := os.Open("./main.go")
if err != nil {
fmt.Println("file open failed", err)
return
}
defer file.Close() // 关闭文件
// bufio 读取文件
reader := bufio.NewReader(file)
for {
// 按行读取
line, err := reader.ReadString('\n') // 注意是字符
if err == io.EOF {
//if len(line) != 0 {
// fmt.Println(line)
//}
fmt.Println("文件读完了")
break
}
if err != nil {
fmt.Println("file read err", err)
return
}
fmt.Println(line)
}
}
「 ioutil.ReadFile( 已废弃 )读取整个文件 」io/ioutil 包的 ReadFile 能够读取完整的文件,只需要将文件名作为参数传入
func main() {
content, err := ioutil.ReadFile("./main.go") // 需说明的是,新版本已废弃这种用法
if err != nil {
fmt.Println("file read failed", err)
return
}
fmt.Println(string(content))
}
写入文件
os.OpenFile() 函数,能够以指定模式打开文件,从而实现文件写入相关功能
func OpenFile(name string, flag int, perm FileMode) (*File, error) // 说明: // name,要打开的文件名 // flag,打开文件的模式,可以有多个,使用 | 分隔 os.O_WRONLY 只写 os.O_CREATE 创建文件 os.O_RDONLY 只读 os.O_RDWR 读写 os.O_TRUNC 清空 os.O_APPEND 追加 // perm,文件权限,一个八进制数,类似于linux文件权限,如:0777、0666
「 file.Write / file.WriteString 」
file, err := os.OpenFile("./hello.md", os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
fmt.Println("file open failed", err)
return
}
defer file.Close()
str := "hello world"
file.Write([]byte(str)) // Write,写入字节切片数据
file.WriteString("HelloWorld") // WriteString,可以直接写入字符串数据
「 bufio.NewWriter 」
file, err := os.OpenFile("./hello.md", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
if err != nil {
fmt.Println("file open failed", err)
return
}
defer file.Close()
writer := bufio.NewWriter(file)
for i := 0; i < 5; i++ {
writer.WriteString("hello\r\n") // 先将数据写入缓存
}
writer.Flush() // 然后,将缓存中的内容写入文件
「 ioutil.WriteFile( 已废弃 ) 」
str := "world"
// ioutil.WriteFile 已废弃
err := ioutil.WriteFile("./hello.md", []byte(str), 0666)
if err != nil {
fmt.Println("file write failed", err)
return
}
重命名文件
// 文件重命名
err := os.Rename("./hello.md", "./world.md")
if err != nil {
fmt.Println("file rename failed")
return
}
fmt.Println("file rename success")
复制文件
func main() {
srcFile := "./hello.md"
dstFile := "./world.md"
// 方法1
err := CopyFile(srcFile, dstFile)
// 方法2
//err := CopyFile1(srcFile, dstFile)
if err != nil {
fmt.Println("copy failed")
}
fmt.Println("copy success")
}
// 方法1 - 自定义函数:复制文件
func CopyFile(srcFile string, dstFile string) error {
// 读取文件
fileSlice, err := ioutil.ReadFile(srcFile)
if err != nil {
return err
}
// 写入文件
err = ioutil.WriteFile(dstFile, fileSlice, 0666)
if err != nil {
return err
}
return nil
}
// 方法2 - 自定义函数:以方法流的方式,赋值文件
func CopyFile1(srcFile string, dstFile string) error {
source, _ := os.Open(srcFile)
destination, _ := os.OpenFile(dstFile, os.O_CREATE|os.O_WRONLY, 0666)
buf := make([]byte, 128)
for {
n, err := source.Read(buf)
if err != nil && err != io.EOF {
return err
}
if n == 0 {
break
}
if _, err := destination.Write(buf[:n]); err != nil {
return err
}
}
return nil
}
目录操作
「 创建目录 」
// (1)创建单个目录
// err := os.Mkdir("./abc", 0666)
// if err != nil {
// fmt.Println(err)
// }
// 如果文件已存在,会报错:mkdir ./abc: file exists,实际上并不需要关心它,所以,如下即可:
os.Mkdir("./abc", 0666) // 不需要处理错误
// (2)创建多级目录
//err := os.MkdirAll("dir1/dir2/dir3", 0777)
//if err != nil {
// fmt.Println(err) // 会报错 mkdir dir1/dir2: permission denied
//}
// 解决方式1:先创建文件,然后,在改变文件的权限
err := os.MkdirAll("dir1/dir2/dir3", 0777)
if err != nil {
fmt.Println(err) // 会报错 mkdir dir1/dir2: permission denied
os.Chmod("dir1", 0777)
os.Chmod("dir1/dir2", 0777)
os.Chmod("dir1/dir2/dir3", 0777)
}
// 解决方式2:改变 `umask` 后再创建文件,其后再把 `umask` 改为原来的 umask
mask := syscall.Umask(0) // 改为 0000 八进制
defer syscall.Umask(mask) // 改为原来的umask
err = os.MkdirAll("dir4/dir5/dir6", 0766)
if err != nil {
fmt.Println(err)
}
「 删除目录和文件 」
// 删除一个文件或目录
err := os.Remove("./hello.md")
if err != nil {
fmt.Println(err)
}
// 递归删除
err = os.RemoveAll("./dir1")
if err != nil {
fmt.Println(err)
}