최근에 한 일 중에는 생성, 삭제, 순회, 압축 등 golang의 파일 작업과 관련된 내용이 많이 사용되었습니다. 여기서 정리하겠습니다. 시스템을 구축하고 모호한 부분을 정리합니다.
파일 생성 시 권한 문제에 주의해야 합니다. 일반적으로 기본 파일 권한은 0666입니다. 권한에 대한 자세한 내용은 Uncle Bird p141을 참조하세요. 파일 속성. r w x r w x r w x, 첫 번째 숫자는 파일 속성입니다. 일반적으로 사용되는 "-"는 일반 파일을 나타내고 "d"는 os.Create
만 사용할 수 있는 것 같습니다. golang에 0xxx 형식으로 파일을 만듭니다. 예를 들어 0666은 파일 소유자, 파일이 속한 사용자 그룹, 파일에 대한 다른 사람의 권한이 모두 110이므로 읽기, 쓰기가 가능하다는 의미입니다. , 실행 가능하지 않습니다. os.Create
创建文件的时候貌似只能使用0xxx的形式。比如0666就表示创建了一个普通文件,文件所有者的权限,文件所属用户组的权限,以及其他人对此文件的权限都是110表示可读可写,不可执行。
文件删除的时候,不管是普通文件还是目录文件,都可以用err:=os.Remove(filename)
这样的操作来执行。当然要是想移除整个文件夹,直接使用RemoveAll(path string)
操作即可。可以看一下RemoveAll函数的内部实现,整体上就是遍历,递归的操作过程,其他的类似的文件操作都可以用类似的模板来实现,下面以RemoveAll函数为模板,进行一下具体的分析,注意考虑到各种情况:
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 }
这一部分较多的涉及I/O的相关操作,系统的介绍放在I/O那部分来整理,大体上向文件中读写内容的时候有三种方式:
1、在使用f, err := os.Open(file_path)
打开文件之后直接使用 f.read() f.write()
结合自定义的buffer每次从文件中读入/读出固定的内容
2、使用ioutl的readFile和writeFile方法
3、使用bufio采用带有缓存的方式进行读写,比如通过info:=bufio.NewReader(f)
파일 삭제 시 일반 파일이든 디렉터리 파일이든 err:=os.Remove(filename)</ 등의 작업을 사용할 수 있습니다. 코드> 구현. 물론 전체 폴더를 제거하려면 <code>RemoveAll(path string)
작업을 사용하면 됩니다. RemoveAll 함수의 내부 구현을 살펴볼 수 있습니다. 전체 작업 프로세스는 순회 및 반복적이며, 유사한 템플릿을 사용하여 다른 유사한 파일 작업을 구현할 수 있습니다. 다음은 특정 분석을 수행하는 템플릿으로 사용됩니다. 다음 사항에 주의하세요.
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() }
1 f, err := os.Open (file_path)</을 사용하는 경우 code>파일을 연 후 <code>f.read() f.write()
를 직접 사용하여 매번 사용자 정의 버퍼와 함께 파일에서 고정 콘텐츠를 읽거나 읽습니다
info:=bufio.NewReader(f)
를 통해 io.Reader 인터페이스가 구현됩니다. 인스턴스가 로드되면 info.ReadLine()을 사용하여 한 번에 한 줄 전체를 읽을 수 있습니다. 오류 정보가 io.EOF이면 읽기가 종료됩니다이 블로그의 세 가지 파일 작업의 읽기 속도를 비교해 보면 알 수 있습니다. 대용량 파일을 읽을 때 ioutil이 더 효율적입니다. 각 방법마다 적용 가능한 상황이 다릅니다. 다음은 세 가지 방법으로 읽는 작업의 예입니다. 파일 쓰기 작업은 읽기 작업을 참조하세요. //将文件夹中的内容打包成 .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") }
다음은 파일 압축 구현입니다. rrreeeTo add 이전에는 OpenFile 함수와 Open 함수의 차이점을 눈치채지 못했을 수도 있습니다. Openfile 함수는 O_RDONLY를 통해 제어되는 반환된 파일 설명자의 권한을 지정할 수 있습니다. , O_WRONLY, O_RDWR 등. Open 함수는 내부적으로 OpenFile 함수를 호출합니다. 기본 권한은 O_RDONLY입니다. Open 함수만 사용하여 파일 설명자를 반환한 다음 파일에 쓰면 잘못된 파일 설명자 오류가 반환됩니다. 더 주의를 기울이고 세부 사항을 신중하게 처리하십시오. 본질적으로 이는 OS의 파일 설명자에 대한 문제입니다.
🎜파일 복사 작업 추가🎜🎜참조: https://www.socketloop.com/tutorials/golang-copy-directory-include-sub-directories-files🎜🎜재인쇄: https://www.cnblogs . com/Goden/p/4533908.html🎜🎜더 많은 golang 관련 기술 기사를 보려면 🎜🎜golang🎜🎜튜토리얼 칼럼을 방문하세요! 🎜위 내용은 Golang 파일 작업 구성 정보의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!