最近本人在做一个开源项目 虽然是go语言新手 还是浅浅记录一下
目录
2.使用 os.Stat 函数获取文件的状态信息并判断是否有错
首先源码奉上
func fileIsRDB(aofFilepath string) bool {
fp, err := os.Open(aofFilepath)
if err != nil {
fmt.Printf("Cannot open file %s:%s\n", aofFilepath, err.Error())
os.Exit(1)
}
sb, err := os.Stat(aofFilepath)
if err != nil {
fmt.Printf("cannot stat file: %s\n", aofFilepath)
os.Exit(1)
}
size := sb.Size()
if size == 0 {
fp.Close()
return false
}
if size >= 8 {
sig := make([]byte, 5)
_, err := fp.Read(sig)
if err == nil && string(sig) == "REDIS" {
fp.Close()
return true
}
}
fp.Close()
return false
}
1.首先是使用 os.Open
函数打开文件
将返回的文件指针 fp
以及可能出现的错误存储在变量中。
func Open(name string) (*File, error)
fp, err := os.Open(aofFilepath)
if err != nil {
fmt.Printf("Cannot open file %s:%s\n", aofFilepath, err.Error())
os.Exit(1)
}
如上图所示,我们使用 os.Open
函数打开了一个名为 aofFilepath的文件。如果打开文件时发生错误,我们会在错误处理代码块中打印错误信息并返回。
fp.Close()
return false
和c语言一样在读取完毕的时候需要close以避免资源泄露,除了以上在return上面加fp.close()还可以用go语言使用defer关键字确保函数返回之前关闭文件。
2.使用 os.Stat
函数获取文件的状态信息并判断是否有错
将返回的信息存储在变量 sb
。
func Stat(name string) (FileInfo, error)
name表示文件路径
FileInfo是一个接口 FileInfo 对象用来获取文件的相关属性和信息
sb, err := os.Stat(aofFilepath)
if err != nil {
fmt.Printf("cannot stat file: %s\n", aofFilepath)
os.Exit(1)
}
size := sb.Size()
if size == 0 {
fp.Close()
return false
}
if size >= 8 {
sig := make([]byte, 5)
_, err := fp.Read(sig)
if err == nil && string(sig) == "REDIS" {
fp.Close()
return true
}
}
fp.Close()
return false
如上图所示 这里我只需要检查文件是否为空,而不需要获取详细的文件信息,所以就os.stat后,调用返回回来的sb的size,如果size==0则说明文件为空,返回错误。
FileInfo接口提供了许多用于检索文件信息的方法,例如 Name,size,ISdir 等等。可以根据实际需要选择相应的方法来获取文件的属性和特征。
如下图
fmt.Println("File Name:", fileInfo.Name())
fmt.Println("File Size:", fileInfo.Size())
fmt.Println("File Mode:", fileInfo.Mode())
fmt.Println("Is Directory:", fileInfo.IsDir())
fmt.Println("Last Modified:", fileInfo.ModTime())
3.文件读取
这里介绍两种常见的读取方式 按块读取和按行读取
3.1按块读取
sig := make([]byte, 5)
for{
_, err := fp.Read(sig)
if err == io.EOF {
fp.close()
return false}
if err == nil && string(sig) == "REDIS" {
fp.Close()
return true}
}
func (f *File) Read(b []byte) (n int, err error)
首先创建根据实际情况创建长度 的字节切片 sig。
每次使用 fp.Read(sig)
从文件中读取 5 个字节的数据,并将实际读取的字节数和可能出现的错误存储在变量中。直到找到REDIS退出或者文件末尾退出。
3.2按行读取
reader := bufio.NewReader(fp)
for {
lines, err := reader.ReadString('\n')
if err != nil {
if err == io.EOF {
break
} else {
fmt.Printf("cannot read file: %s\n", aofFilepath)
os.Exit(1)
}
}
if lines[0] == '#' {
continue
} else if lines[:4] == "file" {
is_manifest = true
}
}
fp.Close()
return is_manifest
首先创建一个bufio.NewReader(fp)
对象,它用于从文件指针 fp
中读取数据。
创建 bufio.NewReader(fp)
对象是为了提高文件读取的效率。
用文件指针 fp
进行读取操作。缓冲读取器会自动将读取的内容存储在内部的缓冲区中,并提供诸如 ReadString
、ReadLine
等方法来更方便地读取文件内容。
这样的好处是它会预先读取更多的数据到缓冲区中,当你通过 ReadString
等方法读取数据时,实际上是直接从缓冲区中获取数据,而不需要每次都触发系统调用。
注意我这里调用了缓存区 要注意缓存区也有大小限制 超过缓存区大小则不会读取 如果是太大的文件很可能读不到自己想要的内容
lines, err := reader.ReadString('\n')
if err != nil {
if err == io.EOF {
break
} else {
fmt.Printf("cannot read file: %s\n", aofFilepath)
os.Exit(1)
}
}
在无限循环内部,使用 reader.ReadString('\n')
读取文件中的一行数据,并将其存储在 lines
变量中。之所以它可以读取文件中的一行数据是因为reader.ReadString('\n')
会从缓冲读取器中读取字符,直到遇到 \n
(换行符)为止。
4.close
刚才说了和c语言一样在读取完毕的时候需要close以避免资源泄露,除了以上在return上面加fp.close()还可以用go语言使用defer关键字确保函数返回之前关闭文件。
其他知识
else if lines[:4] == "file" {
is_manifest = true
}
判断前面字符串是否为特定字符串可以用切片的这种方式
或者
else if strings.HasPrefix(line, "file") {
is_manifest = true
}