当前位置: 首页 > news >正文

Go语言入门:目录与链接

目录与链接

17.2 创建和删除目录

在os包中,以下两个函数都可以用于创建新目录。

func Mkdir(name string, perm FileMode) error
func MkdirAll(path string, perm FileMode) error

这两个函数的区别在于:如果要创建多级目录,Mkdir函数单次调用只能创建一级目录;MkdirAll函数可以一次性创建多级目录。
例如,要创建目录fd01/fd02,如果使用Mkdir函数,则需要调用两次。第一次调用创建fd01目录,第二次调用创建fd01/fd02目录。

err := os.Mkdir("fd01", 0644)
if err != nil {fmt.Println(err)
}
err = os.Mkdir("fd01/fd02", 0644)
......

如果使用的是MkdirAll函数,那么只要调用一次即可。

err := os.MkdirAll("fd01/fd02", 0644)

MkdirMkdirAll函数的第二个参数均用于为新目录设置权限。在上述代码中,权限码0644(八进制)的含义为:目录所有者具有读写权限,用户所在的组和其他用户仅具有读的权限。

删除目录也有两个相关的函数。

func Remove(name string) error
func RemoveAll(path string) error

这两个函数不仅可以删除目录,也可以用于删除文件,这取决于传递的参数。如果被删除的目标是文件,那么被删除的对象是文件;如果被删除的目标是目录,那么被删除的对象是目录。
Remove函数每次只能删除一个对象。假设有以下目录结构。

DR01
└─DR02└─hot

其中,DR01DR02 是目录,hot 是文件。若要使用 Remove 函数将 DR01 删除,就需要调用三次:第一次删除 DR01/DR02/hot 文件,第二次删除 DR01/DR02 目录,第三次删除 DR01 目录。

err := os.Remove("DR01/DR02/hot")
if err != nil {// 处理错误
}
err = os.Remove("DR01/DR02")
if err != nil {// 处理错误
}
err = os.Remove("DR01")
if err != nil {// 处理错误
}

RemoveAll 函数在调用时,如果被删除的目标是目录,会连同其包含的文件、子目录,以及子目录中的内容一起被删除。也就是说,RemoveAll 函数会删除目标路径中的所有内容。

例如,上面例子中的 DR01/DR02/hot 路径,调用 RemoveAll 函数时只要指定目标路径为 DR01,就可以将 DR01 目录以及其子级的所有内容删除。

err := os.RemoveAll("DR01")

17.3 硬链接与符号链接

链接允许为一个文件创建一个或多个文件名(或者称为访问点),访问任意一个链接均可以访问到原始文件。链接可分为硬链接和符号链接。

17.3.1 硬链接

硬链接就是让原始文件拥有一个或多个文件名,这些文件名都指向原始文件索引文件系统为每个文件分配的唯一编号,标识文件在硬盘中的数据区域)。实际上,当用户创建一个文件时,这个新文件至少存在一个硬链接——因为文件至少得有一个文件名才能被访问。

硬链接具有以下特点:

  1. 原始文件创建新的硬链接,实际上没有产生新的文件。硬链接的文件索引原始文件相同。所以,硬链接仅仅是多增加一个文件名罢了。
  2. 指向同一文件的硬链接可以位于同一目录下(文件名不相同),也可以位于不同目录中。
  3. 可以以一个硬链接为源头创建新的硬链接,新链接依然指向原始文件
  4. 删除一个硬链接对其他硬链接原始文件无任何影响。
  5. 当指向同一个文件的最后一个硬链接被删除后,文件就会被删除。假设文件A(A是原始文件的名字,也属于硬链接)产生了B、C两个硬链接。此时若将A删除,文件仍然存在,因为它还有B、C两个文件名,若将B删除,文件就剩下一个文件名C,把C也删除,此时文件的链接计数为0,所以文件就会被删除。
  6. 重命名硬链接后,它所指向的文件不受影响。

在下面的代码中,先创建F1文件并写入一些内容,随后调用os.Link函数创建硬链接F2,再从F2创建硬链接F3。

// 创建F1文件
myfile, err := os.Create("F1")
if err != nil {fmt.Println(err)return
}
// 写入文件内容
myfile.WriteString("This is a file.\n")
// 关闭文件
myfile.Close()// 创建硬链接F2
err = os.Link("F1", "F2")
if err != nil {fmt.Println(err)return
}
// 创建硬链接F3
err = os.Link("F2", "F3")
if err != nil {fmt.Println(err)return
}

Link函数用于创建硬链接,其定义如下:

func os.Link(oldname string, newname string) error

参数oldname表示旧的链接(文件名),参数newname表示新的链接(文件名)。若硬链接创建成功,函数返回nil,否则返回一个指向LinkError实例的指针,包含错误信息。

上述代码执行后,会产生F1、F2、F3三个文件。此时无论访问哪个文件,读到的内容都相同。例如:

myfile, _ := os.Open("F3")
fmt.Println("F3的内容:")
bf := new(bytes.Buffer)
io.Copy(bf, myfile)
fmt.Printf("%s\n", string(bf.Bytes()))

从F3中读到的内容依然是“This is a file.”。

接下来尝试通过F2去修改文件,在文件内容的末尾追加文本。

myfile, _ := os.OpenFile("F2", os.O_WRONLY|os.O_APPEND, 0644)
myfile.WriteString("This is a text file.\n")
myfile.Close()

然后通过F1来读取文件内容。

myfile, _ := os.Open("F1")
bf.Reset()  // 清空缓冲区中的数据
fmt.Println("F1的内容:")
io.Copy(bf, myfile)
fmt.Printf("%s\n", string(bf.Bytes()))

读出来的结果为:

This is a file.
This is a text file.

由于F1、F2、F3指向同一个文件,所以通过F2修改文件后,从F1中也能读取到文件的最新内容,毕竟读写的都是同一个文件,只是文件名不同而已。

17.3.2 符号链接

符号链接(也称为软链接)类似于 Windows 系统中的快捷方式,通过一种特殊的文件类型来保存对原始文件路径的引用。符号链接具有自己的文件索引号,简而言之就是符号链接是用一个文件来保存另一个文件的路径,这一点与硬链接不同。硬链接只是为文件多创建一个文件名,不会产生新的文件。当原始文件被删除后,符号链接将无法使用。

创建符号链接使用 Symlink 函数,其使用方法与 Link 函数相同。

下面的示例先创建文件 Srcfile,并写入 5 字节,然后调用 Symlink 函数为 Srcfile 文件创建符号链接

// 创建新文件
file, err := os.Create("Srcfile")
if err != nil {fmt.Println(err)return
}
// 写入内容
var data = []byte{1, 2, 3, 4, 5}
file.Write(data)
// 关闭文件
file.Close()// 创建符号链接
err = os.Symlink("Srcfile", "myLink")
if err != nil {fmt.Println(err)return
}

17.4 WriteFile函数与ReadFile函数

这两个函数位于io/ioutil包中,WriteFile函数封装了os.OpenFile函数和os.File.Write方法的调用,ReadFile函数封装了os.Open函数的调用。在读写文件的时候使用这两个函数可以化繁为简,提高编码效率。

ReadFile函数的签名如下:

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

此函数会读取文件中的所有内容并以[]byte类型返回。

WriteFile函数的签名如下:

func WriteFile(filename string, data []byte, perm os.FileMode) error

此函数会把data参数指定的数据一次性写入文件。要注意的是,同一个文件如果要分多次写入,就不能调用WriteFile函数。因为该函数每次调用时都会将现有的文件内容清空。例如下面的例子,调用了三次WriteFile函数向demo.txt文件写入内容,执行完代码后,打开demo.txt文件查看,其内容只有“KLMN”,前两次写入的内容都会被清空。

ioutil.WriteFile("demo.txt", []byte("ABCD"), 0644)
ioutil.WriteFile("demo.txt", []byte("OPQRS"), 0644)
ioutil.WriteFile("demo.txt", []byte("KLMN"), 0644)

下面的示例使用WriteFile函数向文件写入若干字节,然后使用ReadFile函数将文件内容读出来。

var bts = []byte{0xa6, 0x57, 0xc5, 0xf3, 0xe9, 0x12}
// 将内容写入文件
ioutil.WriteFile("CKData", bts, 0666)
// 从文件中读取内容
var cnt, _ = ioutil.ReadFile("CKData")
fmt.Printf("从文件中读到的内容:% #x\n", cnt)

屏幕输出的文件内容如下:

从文件中读到的内容:0xa657c5f3e912

17.5 临时文件

在io/ioutil包中有两个与临时文件有关的函数:

func TempDir(dir, pattern string) (name string, err error)
func TempFile(dir, pattern string) (f *os.File, err error)

TempDir函数调用成功后会在dir参数指定的目录中创建临时目录,并返回临时目录的路径;TempFile函数则会在dir参数指定的目录下创建临时文件,然后返回可用于读写临时文件的File对象。

pattern参数用于指定临时文件(或临时目录)名称的生成方式,有两种格式可选:

  1. pattern参数所指定的字符串后面加上随机整数。例如,pattern参数的值为“test”,就会生成形如“test342543727”的文件名。
  2. 如果pattern参数中出现“*”(星号)字符,那么会把最后一个“*”(替换为随机整数。例如,pattern参数为“tmp-*-dir”,就会生成形如“tmp-846674147-dir”的名称。

不管是临时文件还是临时目录,其用途都是临时的数据读写,因此,开发人员在编写程序代码时应当注意,当不再需要临时文件(或临时目录)时要将其删除——这项工作不应该留给用户去完成。

在下面的示例中,先调用TempFile创建临时文件,再向临时文件中写入数据。在程序退出前删除临时文件。

// 创建新目录
os.Mkdir("tmp", 0700)
// 创建临时文件
tmpfile, err := ioutil.TempFile("./tmp", "Demo*.tp")
if err != nil {fmt.Println(err)return
}
fmt.Printf("临时文件%s创建完成\n", tmpfile.Name())
tmpfile.WriteString("abc")
tmpfile.Close()
fmt.Print("按任意键继续……")
fmt.Scanln()
// 删除文件
os.Remove(tmpfile.Name())

临时文件创建后,写入了字符串“abc”。随后,程序代码遇到fmt.Scanln函数会暂停(等待输入)。接着按下回车键,程序继续运行,在退出之前调用了Remove函数,临时文件被删除。

17.6 更改程序的工作目录

应用程序在使用相对路径读写文件时,默认会以工作目录为基准,即文件或子目录会存放到工作目录下。程序在启动时,会把程序可执行文件所在的目录设置为工作目录。在程序代码中,可以调用os.Chdir函数来改变工作目录。

下面的代码首先调用Mkdir函数在程序的当前目录下创建名为data的子目录,然后将data目录设置为工作目录。

err := os.Mkdir("data", 0700)
if os.IsNotExist(err) {return
}// 改变工作目录
err = os.Chdir("data")
if err != nil {fmt.Println(err)return
}

使用相对路径创建名为list的文件,并写入数据。

file, err := os.Create("list")
if err != nil {fmt.Println(err)return
}
// 写入测试内容
file.WriteString("demo")
// 关闭文件
file.Close()

此时list文件会存放在data目录下,因为它被设置为工作目录。

【思考】

  1. 创建文件“abc.data”,并写入字符串“Hello, Go”。
  2. 如何创建和删除目录?

分享图片

【答案】

  1. 创建文件“abc.data”,并写入字符串“Hello, Go”
package main
import ("fmt""os"
)func main() {// 创建文件file, err := os.Create("abc.data")if err != nil {fmt.Println("创建文件时出错:", err)return}// 确保文件在函数结束时关闭defer file.Close()// 写入字符串_, err = file.WriteString("Hello, Go")if err != nil {fmt.Println("写入文件时出错:", err)return}fmt.Println("文件写入成功")
}    

代码解释

  • os.Create("abc.data"):创建一个名为 “abc.data” 的文件,若文件已存在则会将其截断。
  • file.WriteString("Hello, Go"):向文件里写入字符串 “Hello, Go”。
  • defer file.Close():保证文件在函数结束时关闭。
  1. 如何创建和删除目录?
package mainimport ("fmt""os"
)func main() {// 创建目录dirName := "testDir"err := os.Mkdir(dirName, 0755)if err != nil {fmt.Println("创建目录时出错:", err)return}fmt.Println("目录创建成功")// 删除目录err = os.Remove(dirName)if err != nil {fmt.Println("删除目录时出错:", err)return}fmt.Println("目录删除成功")
}    

代码解释

  • os.Mkdir(dirName, 0755):创建一个名为 testDir 的目录,权限为 0755。
  • os.Remove(dirName):删除名为 testDir 的目录。需要注意,若目录不为空,os.Remove 会报错,你可以使用 os.RemoveAll 来删除非空目录。

相关文章:

  • make学习三:书写规则
  • 【质量管理】TRIZ(萃智)的工程系统进化法则
  • 交叉编译tcpdump静态编译单个文件
  • DHCP 服务器运行流程图
  • NHANES指标推荐:BUCR
  • uniapp-商城-40-shop 购物车 选好了 进行订单确认4 配送方式3 地址编辑
  • Spring_MVC 中的 JSON 数据处理与 REST 风格开发
  • 图论---最大流(Dinic)
  • Lua 第11部分 小插曲:出现频率最高的单词
  • 《MySQL 技术内幕-innoDB 存储引擎》笔记
  • 顶会招牌idea:机器学习+组合优化 优秀论文合集
  • 博物馆除湿控湿保卫战:M-5J1R 电解除湿科技如何重塑文物守护的未来
  • 服务器数据备份,服务器怎么备份数据呢?
  • 现代多核调度器的本质 调度三重奏
  • 设计模式--桥接模式详解
  • 1.1 道路结构特征
  • 驱动开发硬核特训 · Day 22(上篇): 电源管理体系完整梳理:I2C、Regulator、PMIC与Power-Domain框架
  • c++多线程初识
  • apkpure 谷歌插件 下载的apk包
  • RISC-V MCU定时器架构与低功耗设计
  • 华尔兹转岗与鲁比奥集权:特朗普政府人事震荡背后的深层危机
  • 五一假期多地政府食堂对外开放:部分机关食堂饭菜“秒没”
  • 韩国代总统、国务总理韩德洙宣布辞职
  • “五一”看什么?这里有一份申城视听指南
  • 山西太原一小区发生爆炸,造成1人遇难21人受伤2人失联
  • 深交所修订创业板指数编制方案,引入ESG负面剔除机制