Maison >développement back-end >Golang >À propos de l'organisation des opérations sur les fichiers Golang
Certaines choses que j'ai faites récemment ont utilisé beaucoup de contenu lié aux opérations sur les fichiers dans Golang, telles que la création, la suppression, le parcours, la compression, etc. peut maîtriser un peu le système et les mettre en pratique. Clarifier les ambiguïtés.
Lors de la création d'un fichier, vous devez faire attention aux problèmes d'autorisation. Généralement, l'autorisation de fichier par défaut est 0666. Concernant les autorisations Contenu, veuillez vous référer à Oncle Bird p141 pour plus de détails. Revoyons les attributs du fichier r w x r w x r w > Il semble que seul le formulaire 0xxx puisse être utilisé lors de la création d'un fichier. Par exemple, 0666 signifie qu'un fichier normal a été créé. Les autorisations du propriétaire du fichier, les autorisations du groupe d'utilisateurs auquel le fichier appartient et les autorisations des autres personnes sur le fichier sont toutes de 110, ce qui signifie qu'il peut être. lu, écrit et non exécutable. os.Create
pour l'effectuer. Bien sûr, si vous souhaitez supprimer l'intégralité du dossier, utilisez simplement l'opération err:=os.Remove(filename)
. Vous pouvez jeter un œil à l'implémentation interne de la fonction RemoveAll. Le processus d'opération global est traversant et récursif. D'autres opérations de fichiers similaires peuvent être implémentées à l'aide de modèles similaires. Ce qui suit utilise la fonction RemoveAll comme modèle pour effectuer une analyse spécifique. attention aux points suivants. Diverses situations : RemoveAll(path string)
func RemoveAll(path string) error { // Simple case: if Remove works, we're done. //先尝试一下remove如果是普通文件 直接删掉 报错 则可能是目录中还有子文件 err := Remove(path) //没错或者路径不存在 直接返回 nil if err == nil || IsNotExist(err) { return nil } // Otherwise, is this a directory we need to recurse into? // 目录里面还有文件 需要递归处理 // 注意Lstat和stat函数的区别,两个都是返回文件的状态信息 //Lstat多了处理Link文件的功能,会返回Linked文件的信息,而state直接返回的是Link文件所指向的文件的信息 dir, serr := Lstat(path) if serr != nil { if serr, ok := serr.(*PathError); ok && (IsNotExist(serr.Err) || serr.Err == syscall.ENOTDIR) { return nil } return serr } //不是目录 if !dir.IsDir() { // Not a directory; return the error from Remove. return err } // Directory. fd, err := Open(path) if err != nil { if IsNotExist(err) { // Race. It was deleted between the Lstat and Open. // Return nil per RemoveAll's docs. return nil } return err } // Remove contents & return first error. err = nil //递归遍历目录中的文件 如果参数n<=0则将全部的信息存入到一个slice中返回 //如果参数n>0则至多返回n个元素的信息存入到slice当中 //还有一个类似的函数是Readdir 这个返回的是 目录中的内容的Fileinfo信息 for { names, err1 := fd.Readdirnames(100) for _, name := range names { err1 := RemoveAll(path + string(PathSeparator) + name) if err == nil { err = err1 } } //遍历到最后一个位置 if err1 == io.EOF { break } // If Readdirnames returned an error, use it. if err == nil { err = err1 } if len(names) == 0 { break } } // Close directory, because windows won't remove opened directory. fd.Close() //递归结束 当前目录下位空 删除当前目录 // Remove directory. err1 := Remove(path) if err1 == nil || IsNotExist(err1) { return nil } if err == nil { err = err1 } return err }État du fichierÉcriture et écriture du contenu du fichierCette partie implique davantage d'opérations liées aux E/S et à l'introduction du système. est ici Organisons la partie E/S De manière générale, il existe trois façons de lire et d'écrire du contenu dans un fichier : 1 Après avoir utilisé
pour ouvrir le fichier, utilisez f, err := os.Open(file_path)
directement après. en le combinant avec un tampon personnalisé. Lire/lire le contenu fixe du fichier à la fois f.read() f.write()
Après avoir chargé l'instance qui implémente l'interface io.Reader, vous pouvez utiliser info.ReadLine() pour lire une ligne entière à la fois jusqu'à ce que les informations d'erreur soient io.EOF et que la lecture se termineinfo:=bufio.NewReader(f)
package main import ( "bufio" "fmt" "io" "io/ioutil" "os" ) func check(e error) { if e != nil { panic(e) } } func main() { //查看当前的工作目录路径 得到测试文件的绝对路径 current_dir, _ := os.Getwd() fmt.Println(current_dir) file_path := current_dir + "/temp.txt" //方式一: //通过ioutil直接通过文件名来加载文件 //一次将整个文件加载进来 粒度较大 err返回为nil的时候 文件会被成功加载 dat, err := ioutil.ReadFile(file_path) //若加载的是一个目录 会返回[]os.FileInfo的信息 //ioutil.ReadDir() check(err) //the type of data is []uint fmt.Println(dat) //将文件内容转化为string输出 fmt.Println(string(dat)) //方式二: //通过os.Open的方式得到 *File 类型的变量 //貌似是一个指向这个文件的指针 通过这个指针 可以对文件进行更细粒度的操作 f, err := os.Open(file_path) check(err) //手工指定固定大小的buffer 每次通过buffer来 进行对应的操作 buffer1 := make([]byte, 5) //从文件f中读取len(buffer1)的信息到buffer1中 返回值n1是读取的byte的长度 n1, err := f.Read(buffer1) check(err) fmt.Printf("%d bytes: %s\n", n1, string(buffer1)) //通过f.seek进行更精细的操作 第一个参数表示offset为6 第二个参数表示文件起始的相对位置 //之后再读就从o2位置开始往后读信息了 o2, err := f.Seek(6, 0) check(err) buffer2 := make([]byte, 2) //读入了n2长度的信息到buffer2中 n2, err := f.Read(buffer2) check(err) fmt.Printf("%d bytes after %d position : %s\n", n2, o2, string(buffer2)) //通过io包种的函数 也可以实现类似的功能 o3, err := f.Seek(6, 0) check(err) buffer3 := make([]byte, 2) n3, err := io.ReadAtLeast(f, buffer3, len(buffer3)) check(err) fmt.Printf("%d bytes after %d position : %s\n", n3, o3, string(buffer3)) //方式三 //通过bufio包来进行读取 bufio中又许多比较有用的函数 比如一次读入一整行的内容 //调整文件指针的起始位置到最开始的地方 _, err = f.Seek(10, 0) check(err) r4 := bufio.NewReader(f) //读出从头开始的5个字节 b4, err := r4.Peek(5) check(err) //fmt.Println(string(b4)) fmt.Printf("5 bytes : %s\n", string(b4)) //调整文件到另一个地方 _, err = f.Seek(0, 0) check(err) r5 := bufio.NewReader(f) //读出从指针所指位置开始的5个字节 b5, err := r5.Peek(5) check(err) //fmt.Println(string(b4)) fmt.Printf("5 bytes : %s\n", string(b5)) //测试bufio的其他函数 for { //读出内容保存为string 每次读到以'\n'为标记的位置 line, err := r5.ReadString('\n') fmt.Print(line) if err == io.EOF { break } } //ReadLine() ReadByte() 的用法都是类似 一般都是当err为io.EOF的时候 //读入内容就结束 //感觉实际用的时候 还是通过方式三比较好 粒度正合适 还有多种处理输入的方式 f.Close() }Opérations avancées
//将文件夹中的内容打包成 .gz.tar 文件 package main import ( "archive/tar" "compress/gzip" "fmt" "io" "os" ) //将fi文件的内容 写入到 dir 目录之下 压缩到tar文件之中 func Filecompress(tw *tar.Writer, dir string, fi os.FileInfo) { //打开文件 open当中是 目录名称/文件名称 构成的组合 filename := dir + "/" + fi.Name() fmt.Println("the last one:", filename) fr, err := os.Open(filename) fmt.Println(fr.Name()) if err != nil { panic(err) } defer fr.Close() hdr, err := tar.FileInfoHeader(fi, "") hdr.Name = fr.Name() if err = tw.WriteHeader(hdr); err != nil { panic(err) } //bad way // //信息头部 生成tar文件的时候要先写入tar结构体 // h := new(tar.Header) // //fmt.Println(reflect.TypeOf(h)) // h.Name = fi.Name() // h.Size = fi.Size() // h.Mode = int64(fi.Mode()) // h.ModTime = fi.ModTime() // //将信息头部的内容写入 // err = tw.WriteHeader(h) // if err != nil { // panic(err) // } //copy(dst Writer,src Reader) _, err = io.Copy(tw, fr) if err != nil { panic(err) } //打印文件名称 fmt.Println("add the file: " + fi.Name()) } //将目录中的内容递归遍历 写入tar 文件中 func Dircompress(tw *tar.Writer, dir string) { fmt.Println(dir) //打开文件夹 dirhandle, err := os.Open(dir + "/") //fmt.Println(dir.Name()) //fmt.Println(reflect.TypeOf(dir)) if err != nil { panic(err) } defer dirhandle.Close() fis, err := dirhandle.Readdir(0) //fis的类型为 []os.FileInfo //也可以通过Readdirnames来读入所有子文件的名称 //但是这样 再次判断是否为文件的时候 需要通过Stat来得到文件的信息 //返回的就是os.File的类型 if err != nil { panic(err) } //遍历文件列表 每一个文件到要写入一个新的*tar.Header //var fi os.FileInfo for _, fi := range fis { fmt.Println(fi.Name()) if fi.IsDir() { newname := dir + "/" + fi.Name() fmt.Println("using dir") fmt.Println(newname) //这个样直接continue就将所有文件写入到了一起 没有层级结构了 //Filecompress(tw, dir, fi) Dircompress(tw, newname) } else { //如果是普通文件 直接写入 dir 后面已经有了 / Filecompress(tw, dir, fi) } } } //在tardir目录中创建一个.tar.gz文件 存放压缩之后的文件 func Dirtotar(sourcedir string, tardir string, tarname string) { //file write 在tardir目录下创建 fw, err := os.Create(tardir + "/" + tarname + ".tar.gz") //type of fw is *os.File // fmt.Println(reflect.TypeOf(fw)) if err != nil { panic(err) } defer fw.Close() //gzip writer gw := gzip.NewWriter(fw) defer gw.Close() //tar write tw := tar.NewWriter(gw) fmt.Println("源目录:", sourcedir) Dircompress(tw, sourcedir) //通过控制写入流 也可以控制 目录结构 比如将当前目录下的Dockerfile文件单独写在最外层 fileinfo, err := os.Stat("tarrepo" + "/" + "testDockerfile") fmt.Println("the file name:", fileinfo.Name()) if err != nil { panic(err) } //比如这里将Dockerfile放在 tar包中的最外层 会注册到tar包中的 /tarrepo/testDockerfile 中 Filecompress(tw, "tarrepo", fileinfo) //Filecompress(tw, "systempdir/test_testwar_tar/", fileinfo) fmt.Println("tar.gz packaging OK") } func main() { // workdir, _ := os.Getwd() // fmt.Println(workdir) Dirtotar("testdir", "tarrepo", "testtar") }
Ajouter une opération de copie de fichier
Réimprimé dans : https://www.cnblogs.com/Goden/p/4533908.html
Pour plus d'articles techniques liés au golang, veuillez visiter
golang Tutoriel colonne!
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!