GoWeb——操作目录与文件

本文详细介绍了Go语言中如何操作文件和目录,包括创建、重命名、删除目录,创建、打开、关闭、读写文件,以及移动、重命名、删除文件,修改文件权限,创建文件链接等。同时,文中给出了各种操作的实例代码,涵盖了os、path、path/filepath等包的相关函数使用。
摘要由CSDN通过智能技术生成

1、操作目录

Go语言对文件和目录的操作,主要是通过os包和path包实现的。下面介绍os包和path包中的一些常用函数。

1.1、创建目录

Go语言创建目录,主要使用Mkdir()、MkdirAllO两个函数。其中,Mkdir()函数的定义如下:

func Mkdir (name string,perm FileMode) error

其中,name为目录名字,perm为权限设置码。比如perm为0777,表示该目录对所有用户可读写及可执行。

例如,创建一个名为“test”的目录,perm权限为0777的示例如下:

import (
	"fmt"
	"os"
)

func main() {
	//创建一个名为"test"的目录,权限为0777
	err := os.Mkdir("test", 0777)
	if err != nil {
		fmt.Println(err)
	}
}

MkdirAll()函数的定义如下:

func MkdirAll(path string,perm FileMode) error

其中,path为目录的路径(例如“dir1/dir2/dir3)”,perm为权限设置码。

用MkdirAll(0函数创建目录的示例如下:

import (
	"fmt"
	"os"
)

func main() {
	//根据path创建多级子目录,录入dir1/dir2/dir3
	err := os.MkdirAll("dir1/dir2/dir2", 0777)
	if err != nil {
		fmt.Println(err)
	}
}

在Wb开发中,多级目录使用得比较多的地方是上传文件。例如我们可以创建一个形如
“static/upload/2020/10/1”的多级目录来保存上传的文件。用MkdirAll0函数创建多级目录的示例如下。

import (
	"fmt"
	"os"
	"time"
)

func main() {
	uploadDir := "static/upload/" + time.Now().Format("2006/01/02/")
	err := os.MkdirAll(uploadDir, 777)
	if err != nil {
		fmt.Println(err)
	}
}

1.2、重命名目录

在Go语言的os包中有一个Rename()函数用来对目录和文件进行重命名。该函数也可以用于移动一个文件。该函数的定义如下:

func Rename (oldpath,.newpath string) error

其中,参数oldpath为旧的目录名或多级目录的路径,参数newpath为新目录的路径。如果newpath已经存在,则替换它。其使用示例如下。

import (
	"log"
	"os"
)

func main() {
	//将test目录重命名为test1
	oldName := "test"
	newName := "test1"
	err := os.Rename(oldName, newName)
	if err != nil {
		log.Fatal(err)
	}
}

1.3、删除目录

Go语言删除目录的函数的定义如下:

func Remove (name string) error

其中,参数name为目录的名字。Remove()函数有一个局限性:当目录下有文件或者其他目录时会出错。

如果要删除多级子目,则可以使用RemoveAll()函数,其定义如下:

func RemoveAll(path string) error

其中,参数path为要删除的多级子目录。如果path是单个名称,则该目录下的子目录将全部被删除。用Remove()函数删除名为dir1的目录的示例如下。

import (
	"log"
	"os"
)

func main() {
	err := os.RemoveAll("dir1")
	if err != nil {
		log.Fatal(err)
	}
}

1.4、遍历目录

在Go语言的path/filepath包中,提供了Walk()函数来遍历目录,其定义如下:

func Walk(root string,walkFn WalkFunc) error

其中,参数root为遍历的初始根目录,参数walkFn为自定义函数(例如,显示所有文件夹、子文件夹、文件、子文件)。用WalK()函数遍历目录的示例如下。

import (
	"fmt"
	"os"
	"path/filepath"
)

func main() {
	//根据path创建多级子目录,例如dir1/dir2/dir3
	err := os.MkdirAll("dir1/dir2/dir3", 0777)
	if err != nil {
		fmt.Println(err)
	}
	root := `./dir1`
	err = filepath.Walk(root, scan)
	fmt.Printf("filepath.Walk() returnned %v\n", err)
}

func scan(path string, f os.FileInfo, err error) error {
	fmt.Printf("Scaned: %s\n", path)
	return nil
}
Scaned: ./dir1
Scaned: dir1/dir2
Scaned: dir1/dir2/dir3
filepath.Walk() returnned <nil>

2、创建文件

Go语言os包中提供了Create()函数来创建文件,其定义如下:

func Create(name string)(*File,error)

其中,参数name为文件名字的字符串,返回值为指针型文件描述符。
用Create()函数创建一个名为name的文件,默认采用模式0666。如果文件已存在,则它会被重置为空文件。如果成功,则返回的文件描述符对象可用于文件的读写。其使用示例如下。

import (
	"fmt"
	"os"
)

func main() {
	//创建文件
	//Create()函数会根据传入的文件名创建文件,默认权限是0666
	fp, err := os.Create("./demo.txt") //如果文件已经存在,则将文件清空
	fmt.Println(fp, err)
	fmt.Printf("%T", fp) //*os.File文件指针

	if err != nil {
		fmt.Println("文件创建失败")
		//创建文件失败的原因有:
		//1.路径不存在 2.权限不足 3.打开文件数量超过上限 4.磁盘空间不足等
		return
	}
}

3、打开与关闭文件

在Go语言的os包中提供了Open)函数和OpenFile()函数用来打开文件。在Open()、OpenFile()函数使用完毕后,都需要调用Close()方法来关闭文件。(go的后续版本File实现了Closer接口,可以自动关闭)

3.1、Open()函数

文件的打开使用os包中的Open()函数,其定义如下:

func Open (name string)(file *File,err Error)

其中参数name为文件名字的字符串,返回值为文件描述符对象。
文件关闭用Close()方法,其定义如下:

func (f *File)close()error

其中,参数f为文件描述符指针;Close()方法可使文件不能用于读写,它的返回值为可能出现的错误。Open()函数的使用示例如下。

import (
	"fmt"
	"os"
)

func main() {
	//打开文件
	file, err := os.Open("demo.txt")
	if err != nil {
		fmt.Printf("打开文件出错:%v\n", err)
	}
	fmt.Println(file)

	//go1.19 File实现了Closer接口,可自动关闭
}

3.2、OpenFile()函数

OpenFile()函数比Open()函数更加强大,可以定义文件的名字、文件打开方式,以及文件权限设置。其定义如下:

func OpenFile(name string,flag int,perm uint32)(file *File,err Error)

其中,name为文件的名字,flag参数为打开的方式(可以是只读、读写等),perm是权限模式,形如0777。其使用示例如下。

import (
	"fmt"
	"os"
)

func main() {
	//以读写方式打开文件
	fp, err := os.OpenFile("./demo.txt", os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		fmt.Println("文件打开失败!")
		return
	}
	fmt.Println(fp)
}

4、读写文件

4.1、读文件

4.1.1、用带缓冲方式读取

这种方式使用bufio包中的NewReader()函数。其定义如下:

func NewReader(rd io.Reader)*Reader

该函数的使用示例如下。

import (
	"bufio"
	"fmt"
	"io"
	"os"
)

func main() {
	//打开文件
	file, err := os.Open("a.txt")
	if err != nil {
		fmt.Println("打开文件出错:", err)
	}
	reader := bufio.NewReader(file)
	//循环读取文件的内容
	for {
		line, err := reader.ReadString('\n') //读到一个换行符就结束
		if err == io.EOF {
			break
		}
		fmt.Print(line)
	}
}
4.1.2、直接读取到内存

如果想将文件直接读取到内存中,则可使用io/ioutil包中的ReadFile()函数,其定义如下:

func ReadFile(filename string)([]byte,error)

其中参数filename为文件名。ReadFile()函数的使用示例如下。

import (
	"fmt"
	"io/ioutil"
)

func main() {
	//用io/ioutil.ReadFile()函数一次性将文件读取到内存中
	filePath := "a.txt"
	//content, err := os.ReadFile(filePath) 1.16版本后,改用os.ReadFile()函数
	content, err := ioutil.ReadFile(filePath)

	if err != nil {
		fmt.Println("读取文件出错:", err)
	}
	fmt.Printf("%v\n", content)
	fmt.Printf("%v\n", string(content))
}

4.2、写文件

Go语言中os包中提供了一个名为File的对象来处理文件,该对象有Write()、WriteAt()、WriteString03种方法可以用于写文件。

4.2.1、Write()方法

Write()方法用于写入[]byte类型的信息到文件中,其定义如下:

func (file *File)Write(b []byte)(n int,err Error)

其使用示例如下。

import (
	"fmt"
	"os"
)

func main() {
	file, err := os.OpenFile("a.txt", os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)
	if err != nil {
		fmt.Println(err)
	}
	content := []byte("你好!")
	if _, err = file.Write(content); err != nil {
		fmt.Println(err)
	}
	fmt.Println("写入成功")
}
4.2.2、WriteAt()方法

WriteAt()方法用于在指定位置开始写入[]byte类型的信息,其定义如下:

func (file *File)WriteAt (b []byte,off int64)(n int,err Error)

该方法表示从基本输入源的偏移量off处开始,将Ien§个字节读取到p中。它返回读取的字节数n(0≤n≤len§,以及任何遇到的错误。其使用示例如下。

import (
	"fmt"
	"os"
)

func main() {
	file, err := os.Create("writeAt.txt")
	if err != nil {
		fmt.Println(err)
	}
	file.WriteString("kldsfjsdlkfjsdklf")
	n, err := file.WriteAt([]byte("hello world"), 10)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(n)
}
4.2.3、WriteString()方法

WriteString()方法用于将字符串写入文件,其定义如下:

func (file *File)Writestring(s string)(ret int,err Error)

其中参数s为string类型的字符串。该方法的使用示例如下。

import (
	"fmt"
	"os"
)

func main() {
	file, err := os.Create("writeString.txt")
	if err != nil {
		fmt.Println(err)
	}
	file.WriteString("hello!")
}

WriteString()方法的本质上是对Write()方法的调用。WriteString()方法的返回值就是Write()方法的返回值。

WriteString()的方法体如下:

func (f *File)Writestring(s string)(n int,err error){
	return f.Write([]byte(s))
}

WriteString()方法和Write()方法的区别是参数的形式:WriteString()方法的参数是字符串,
Write()方法的参数是[]byte(s)。WriteString()方法和Write()方法的使用示例如下。

import (
	"fmt"
	"os"
)

func main() {
	fout, err := os.Create("./write4.txt")
	if err != nil {
		fmt.Println(err)
	}
	for i := 0; i < 5; i++ {
		outstr := fmt.Sprintf("%s:%d\r\n", "hello go", i)
		//写入文件
		fout.WriteString(outstr) //stinrg
		fout.Write([]byte(outstr))
	}
}

5、移动与重命名文件

Go语言的移动和重命名可以通过Rename()函数实现,其参数既可以是目录,也可以是文件。其定义如下:

func Rename (oldpath,newpath string) error

其中,参数oldpath为旧的目录或文件,参数newpath为移动与重命名后的目录或文件。

Rename()函数的使用示例如下。

import (
	"fmt"
	"os"
)

func main() {
	_, err := os.Create("./rename.txt") //如果文件已经存在,则清空文件
	if err != nil {
		fmt.Println(err)
	}
	//创建一个名为rename的目录,权限为0777
	err = os.Mkdir("rename", 0777)
	//将rename.txt移动到rename文件夹下,并将其重命名为rename_new.txt
	err = os.Rename("./rename.txt", "./rename/rename_new.txt")
	if err != nil {
		fmt.Println(err)
	}
}

6、删除文件

和删除目录一样,在Go语言中删除文件也可以通过Remove()函数和RemoveAll()函数来实现。

6.1、Remove()函数

Remove()函数用于删除指定的文件或目录。如果出错,则返回*PathError类型的错误。其定义如下:

func.Remove (name string) error

6.2、RemoveAll()函数

RemoveAll()函数用于删除指定的文件或目录及它的所有下级对象。它会尝试删除所有内容,除非遇到错误并返回。如果参数path指定的对象不存在,则RemoveAll()函数会返回nil,而不返回错误。其定义如下:

func RemoveAll(path string) error

用Remove()函数及RemoveAll)(函数删除文件的示例如下:

func main() {
	//创建test_rename目录
	err := os.Mkdir("test_remove", 0777)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("created dir:test_remove")
	//创建test_remove.txt
	_, err = os.Create("./test_remove/test_remove1.txt")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("created file:test_remove1.txt")
	_, err = os.Create("./test_remove/test_remove2.txt")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("created file:test_remove2.txt")
	_, err = os.Create("./test_remove/test_remove3.txt")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("created file:test_remove3.txt")

	err = os.RemoveAll("./test_remove")
	if err != nil {
		fmt.Println("remove all fail:", err)
	}
	fmt.Println("removed all files:./test_remove")
}

7、复制文件

在Go语言中,可以使用io包的Copy()函数来实现文件复制功能。其定义如下:

func Copy(dst Writer,src Reader)(written int64,err error)

其中,参数dst为源文件指针,参数srC为目标文件指针。

import (
	"fmt"
	"io"
	"os"
)

func main() {
	_, err := os.Create("./test_copy1.zip")
	if err != nil {
		fmt.Println(err)
	}
	//打开文件,获取文件指针
	srcFile, err := os.Open("./test_copy1.zip")
	if err != nil {
		fmt.Println(err)
	}

	//打开目的文件,获取文件指针
	dstFile, err := os.OpenFile("./test_copy2.zip", os.O_WRONLY|os.O_CREATE, 0755)
	if err != nil {
		fmt.Println(err)
	}

	//通过copy()复制文件
	result, err := io.Copy(dstFile, srcFile)
	if err == nil {
		fmt.Println("复制成功:", result)
	}
}

除此之外,我们还可以自己封装一个函数:先通过使用os包中的os.Open()和os.Create()函数获取文件句柄(文件指针),然后通过文件句柄(文件指针)的Read()和Write()方法,按照字的节读取和写入来实现复制文件的功能。

在项目开发中,可以把复制文件封装成一个公共函数,以便在以后每次需要用到该功能时直接调用封装好的函数。对于较大文件,可以自定义一个名为DoCopy()的函数,示例如下。

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

func DoCopy(srcFileName string, dstFileName string) {
	srcFile, err := os.Open(srcFileName)
	if err != nil {
		log.Fatalf("源文件获取失败,err:%v\n", err)
	}
	distFile, err := os.Create(dstFileName)
	if err != nil {
		log.Fatalf("目标文件创建失败,err:%v\n", err)
	}

	//定义指定长度的字节切片,每次最多读取指定长度
	var tmp = make([]byte, 1024*4)
	//循环读取并写入
	for {
		n, err := srcFile.Read(tmp)
		n, _ = distFile.Write(tmp[:n])
		if err != nil {
			if err == io.EOF {
				return
			} else {
				log.Fatalf("赋值过程中发生错误,err:%v\n", err)
			}
		}
	}
}

func main() {
	_, err := os.Create("./test.zip")
	if err != nil {
		fmt.Println(err)
	}
	DoCopy("./test.zip", "./test2.zip")
}

8、修改文件权限

8.1、Linux中的文件权限

8.1.1、Liux中的文件权限有以下设定
  • 文件的权限类型一般包括读、写、执行(对应字母为r、w、×)。
  • 权限的属组有拥有者、群组、其他组这3种。每个文件都可以针对这3个属组(粒度),设置不同的r、w、x(读、写、执行)权限。
  • 通常情况下,一个文件只能归属于一个用户和组。如果其他的用户想具有这个文件的权限,则可以将该用户加入具备权限的群组。一个用户可以同时归属于多个组。
8.1.2、十位二进制表示法

在Liux中,常用十位二进制表示法来表示一个文件的权限,形式如下:

-rwxrwxrwx (777)

以上权限表示所有用户(拥有者、所在群组的用户、其他组的用户)都有这个文件的读、写、执行权限。

①在十位二进制表示法中,第1位表示的是文件的类型,类型可以是下面几个中的一个:

  • d:目录(directory);
  • -:文件(regular file);
  • s:套字文件(socket);
  • p:管道文件(pipe)或命名管道文件(named pipe);
  • l:符号链接文件(symbolic link);
  • b:该文件是面向块的设备文件(block-oriented device file):
  • c:该文件是面向字符的设备文件(character-oriented device file)。

②在十位二进制表示法中,后9位每个位置的意义(代表某个属组的某个权限)都是固定的。如果我们将各个位置权限的有无用二进制数1和0来代替,则只读、只写、只执行权限可以用3位二进制数表示:

r-- = 100
-w-= 010
--x = 001
--- = 000

转换成八进制数,则为=4,w=2,x=1,-=0(这也就是在用数字设置权限时,为何4代表读,2代表写,1代表执行)。

可以将所有的权限用二进制形式表现出来,并进一步转变成八进制数字:

rwx = 111 = 7
rw- = 110 = 6
r-x = 101 = 5
r-- = 100 = 4
-wx = 011 = 3
-w- = 101 = 2
--x = 001 = 1
--- = 000 = 0 

由上可以看出,每个属组的所有的权限都可以用1位八进制数表示,每个数字都代表不同的权限(权值)。如最高的权限为是7,则代表可读、可写、可执行。

8.2、修改文件权限

在Go语言中,可使用os.Chmod()方法来修改文件的权限。该方法是对操作系统权限控制的一种封装,其定义如下:

func (f *File)Chmod(mode FileMode)error

其中参数f为文件指针。如果出错,则返回底层错误类型*PathError。用Chmod()方法修改文件权限的示例如下。

import (
	"fmt"
	"os"
)

func main() {
	_, err := os.Create("./chmod.txt") 
	if err != nil {
		fmt.Println(err)
	}
	fileInfo, err := os.Stat("./chmod.txt")
	fileMode := fileInfo.Mode()
	fmt.Println(fileMode) //-rw-r--r--

	//重新赋值权限
	os.Chmod("./chmod.txt", 0777)
	fileInfo, err = os.Stat("./chmod.txt")
	fileMode = fileInfo.Mode()
	fmt.Println(fileMode)//-rwxrwxrwx
}

9、文件链接

9.1、硬链接

Go语言支持生成文件的软链接和硬链接。生成硬链接使用Lik(0函数,在Go1.4以后版本中,增加了对本地Windows系统中硬链接的支持。其定义如下:

func Link(oldname,newname string)error

其中,参数oldname为l旧文件名字,参数newname为新文件名字。

9.2、软链接

Go语言中,生成软链接使用Symlink(0函数。其定义如下:

func Symlink(oldname,newname string) error
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值