Please enable Javascript to view the contents

Go-Path-文件路径操作汇总

 ·  ☕ 5 分钟

重要

1. 目录操作

1.1 删除目录

  • 删除目录下所有内容
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// Golang program to illustrate how to 
// remove all the files and directories 
// from the default directory 
package main 

import ( 
	"log"
	"os"
) 

func main() { 

	// Remove all the directories and files 
	// Using RemoveAll() function 
	err := os.RemoveAll("/Users/hex/Documents/go") 
	if err != nil { 
		log.Fatal(err) 
	} 
} 

1.2 创建目录

  • 级联创建所有目录
1
os.MkdirAll("/tmp/",FileMode)

1.3 创建临时目录

方法:

调用io.ioutil包的 ioutil.TempDir方法 == == os包的 os.MkdirTemp方法

作用:

创建全局唯一的临时目录。但在使用完成后,需要自行删除此目录。

参数:

  • 第一个dir参数如果不指定,则为os.TempDir()目录。如Linux下取$TMPDIR变量,变量空值则为/tmp目录。

ioutil.TempDir方法调用过程说明:

  • 在目录/tmp目录中创建一个名称以prefix开头的新目录
  • 并返回新创建目录的路径
1
2
3
4
5
6
7
dir, err := ioutil.TempDir("/tmp", "prefix-")
if err != nil {
	log.Fatal(err)
}
defer os.RemoveAll(dir)

fmt.Println(dir) // 例如目录名为 "/tmp/prefix-054003078/"

1.3.1 创建时间目录

1
2
3
// logsDir := os.path.Join("/tmp", time.Now().Format("2006/01/02"))
logsDir := filepath.Join("/tmp", time.Now().Format("2006/01/02"))
err := os.MkdirAll(logsDir, 666)

1.4 检查路径是否为目录

1
2
3
4
5
6
func IsDir(name string) bool {
    if info, err := os.State(name); err == nil {
        return info.IsDir()
    }
    return false
}

1.5 打印当前目录

1
os.Getwd() //获取当前目录

1.6 文件目录拼接

1
2

os.path.join("/tmp", "/text.md")

1.7 目录复制

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
func CopyDir(srcPath, desPath string) error {
	//检查目录是否正确
	if srcInfo, err := os.Stat(srcPath); err != nil {
		return err
	} else {
		if !srcInfo.IsDir() {
			return errors.New("源路径不是一个正确的目录!")
		}
	}
 
	if desInfo, err := os.Stat(desPath); err != nil {
		return err
	} else {
		if !desInfo.IsDir() {
			return errors.New("目标路径不是一个正确的目录!")
		}
	}
 
	if strings.TrimSpace(srcPath) == strings.TrimSpace(desPath) {
		return errors.New("源路径与目标路径不能相同!")
	}
 
	err := filepath.Walk(srcPath, func(path string, f os.FileInfo, err error) error {
		if f == nil {
			return err
		}
 
		//复制目录是将源目录中的子目录复制到目标路径中,不包含源目录本身
		if path == srcPath {
			return nil
		}
 
		//生成新路径
		destNewPath := strings.Replace(path, srcPath, desPath, -1)
 
		if !f.IsDir() {
			CopyFile(path, destNewPath)
		} else {
			if !FileIsExisted(destNewPath) {
				return MakeDir(destNewPath)
			}
		}
 
		return nil
	})
 
	return err
}

1.8 遍历目录下所有文件(不包含子目录)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* 获取指定路径下的所有文件,只搜索当前路径,不进入下一级目录,可匹配后缀过滤(suffix为空则不过滤)*/
func ListDir(dir, suffix string) (files []string, err error) {
   files = []string{}
 
   _dir, err := ioutil.ReadDir(dir)
   if err != nil {
      return nil, err
   }
 
   suffix = strings.ToLower(suffix)  //匹配后缀
 
   for _, _file := range _dir {
      if _file.IsDir() {
         continue   //忽略目录
      }
      if len(suffix) == 0 || strings.HasSuffix(strings.ToLower(_file.Name()), suffix) {
         //文件后缀匹配
         files = append(files, path.Join(dir, _file.Name()))
      }
   }
 
   return files, nil
}

1.9 遍历目录下所有文件(包含子目录)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
/* 获取指定路径下以及所有子目录下的所有文件,可匹配后缀过滤(suffix为空则不过滤)*/
func WalkDir(dir, suffix string) (files []string, err error) {
	files = []string{}
 
	err = filepath.Walk(dir, func(fname string, fi os.FileInfo, err error) error {
		if fi.IsDir() {
			//忽略目录
			return nil
		}
 
		if len(suffix) == 0 || strings.HasSuffix(strings.ToLower(fi.Name()), suffix) {
			//文件后缀匹配
			files = append(files, fname)
		}
 
		return nil
	})
 
	return files, err
}

2. 文件操作

2.1 文件创建或追加内容

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "os"
)

func main() {
    // ioutil包 创建文件
    err := ioutil.WriteFile("temp.txt", []byte("first line\n"), 0644)
    if err != nil {
        log.Fatal(err)
    }
    
    // os包 Create方法 创建文件
    f1, _ := os.Create("./temp.txt")
    defer f1.close()
    // os包 Openfile 读写打开文件
    f2, _ := os.Openfile("./temp.txt", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
    defer f2.close()
    
    // 追加文件内容
    file, err := os.OpenFile("temp.txt", os.O_APPEND|os.O_WRONLY, 0644)
    defer file.close()
    if err != nil {
        log.Println(err)
    }
    
    if _, err := file.WriteString("second line"); err != nil {
        log.Fatal(err)
    }
    
    //Print the contents of the file
    data, err := ioutil.ReadFile("temp.txt")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(string(data))
}

2.2 创建临时文件

方法:

调用io.ioutil包的 ioutil.TempFile方法[Go-旧版] == os包的 os.CreateTemp方法[ Go 1.17以上版本]

作用:

创建全局唯一的临时文件。但在使用完成后,需要自行删除此文件。

参数:

  • 第一个dir参数如果不指定,则为os.TempDir()目录。如Linux下取$TMPDIR变量,变量空值则为/tmp目录。

  • 第二个参数pattern,在Go-1.11以后支持使用*占位符来制定随机串的位置,没有*则保持默认,再最后追加随机串。

ioutil.TempFile方法调用过程说明:

  • 在目录/tmp目录中以prefix开头的名称创建一个新文件
  • 打开文件进行读写操作
  • 并返回新创建临时文件对象*os.File
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// 不指定随机串位置
file, err := ioutil.TempFile("/tmp", "prefix-")
if err != nil {
    log.Fatal(err)
}
defer os.Remove(file.Name())

fmt.Println(file.Name()) // 例如文件名为: "/tmp/prefix-054003078"


// 指定随机串位置
file2, err2 := ioutil.TempFile("/tmp", "myname.*.go")
if err2 != nil {
    log.Fatal(err2)
}
defer os.Remove(file2.Name())

fmt.Println(file2.Name()) // 例如文件名为: "/tmp/myname.054003078.bat"

2.3 检查文件是否存在

1
2
3
4
5
6
7
func FileIsExisted(filename string) bool {
    existed := true
    if _, err := os.Stat(filename); os.IsNotExist(err){
        existed = false
    }
    return existed
}

2.4 重命名文件

1
os.Rename("/tmp/1.md", "tmp/2.md")

2.5 复制文件

复制文件过程中一定要注意将原始文件的权限也要复制过去,否则可能会导致可执行文件不能执行等问题。

2.5.1 使用io.Copy

方法简单,但是缺少灵活性。如果文件太大,不是一种很好的方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
func copy(src, dst string) (int64, error) {
    // 获取文件权限
    sourceFileStat, err := os.Stat(src)
    if err != nil {
        return 0, err
    }
    perm := sourceFileStat.Mode()
    // 判断文件状态
    if !perm.IsRegular() {
        return 0, fmt.Errorf("%s is not a regular file", src)
    }
    
    // 打开源文件
    source, err := os.Open(src)
    if err != nil {
        return 0, err
    }
    defer source.Close()
    
    // 创建目标文件
    // destination, err := os.Create(dst)	//无法复制源文件的所有权限
    //复制源文件的所有权限
	destination, err := os.OpenFile(des, os.O_RDWR|os.O_CREATE|os.O_TRUNC, perm)
    if err != nil {
        return 0, err
    }
    defer destination.Close()
    
    // 拷贝
    nBytes, err := io.Copy(destination, source)
    return nBytes, err

2.5.2 使用ioutilWriteFile()ReadFile()

一次性读取输入文件,然后再一次性写入目标文件。依然不是很高效的方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
func CopyFile(src, des string) (written int64, err error) {
	// 打开源文件
    srcFile, err := os.Open(src)
	if err != nil {
		return 0, err
	}
	defer srcFile.Close()

	// 获取源文件的权限
    fi, _ := srcFile.Stat()
	perm := fi.Mode()
    
    // 打开并读取源文件
	input, err := ioutil.ReadFile(src)
	if err != nil {
        fmt.Println(err)
		return 0, err
	}
	
    // 创建并写入目标文件
	err = ioutil.WriteFile(des, input, perm)
	if err != nil {
        fmt.Println("Error creating", destinationFile, err)
		return 0, err
	}

	return int64(len(input)), nil

2.5.3 使用osRead()Write()

  1. 使用buffer一块块地复制文件
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
func CopyFile(src string, des string, bufSize int) (written int64, err error) {
	if bufSize <= 0 {
        bufSize = 1*1024*1024 // buf大小1M
    }
	buf := make([]byte, bufSize)
    
    // 打开源文件
    srcFile, err := os.Open(src)
	if err != nil {
		return 0, err
	}
	defer srcFile.Close()
    
    // 获取文件权限
	fileInfo, _ := srcFile.Stat()
	perm := fileInfo.Mode()

    // 打开目标文件+原权限
	destFile, err := os.OpenFile(des, os.O_RDWR|os.O_CREATE|os.O_TRUNC, perm)
    if err != nil {
        return 0, err
    }
    defer destFile.Close()

	count := 0
	for {
   		n, err := srcFile.Read(buf)
   		if err != nil && err != io.EOF {
      		return err
   		}
   		
        if n == 0 {
      		break
   		}
        
   		if wn, err := destFile.Write(buf[:n]); err != nil {
      		return err
   		} else{
       		count += wn
   		}
	}
    
	return int64(count), nil
}

Reference

path/filepath — 兼容操作系统的文件路径操作
Append to an existing file in Go (Golang)

分享

Hex
作者
Hex
CloudNative Developer

目录