Some things I have done recently have used a lot of content related to file operations in golang, such as creation, deletion, traversal, compression, etc. I will sort them out here. I hope I can master a little bit about the system and put them into practice. Clarify the ambiguities.
Basic operation
File creation
When creating a file, you must pay attention to permission issues. Generally, the default file permission is 0666. About permissions Content, please refer to Uncle Bird p141 for details. Let’s review again. The file attributes r w x r w x r w #os.CreateIt seems that only the form 0xxx can be used when creating a file. For example, 0666 means that a normal file has been created. The permissions of the file owner, the permissions of the user group to which the file belongs, and the permissions of other people on the file are all 110, which means it can be read, written, and not executable.
err:=os.Remove(filename) to perform it . Of course, if you want to remove the entire folder, just use the RemoveAll(path string) operation. You can take a look at the internal implementation of the RemoveAll function. The overall operation process is traversal and recursive. Other similar file operations can be implemented using similar templates. The following uses the RemoveAll function as a template to conduct a specific analysis. Pay attention to the following. Various situations:
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
}File statusWriting content from the fileThis part involves more I/O related operations, and the system introduction is here In the I/O part, there are generally three ways to read and write content to files: 1. When using f, err := os.Open(file_path) After opening the file, use f.read() f.write() combined with the custom buffer to read/read fixed content from the file each time
info:=bufio.NewReader(f), implement the io.Reader interface. After the instance is loaded, you can use info.ReadLine() to read a whole line at a time until the err information is io.EOF, and the reading ends.
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()
}Advanced OperationsFile packaging, file decompression, file traversal, these related operations can basically be performed by referring to the RemoveAll method, which is a recursive plus traversal method. The following is an implementation of file compression:
//将文件夹中的内容打包成 .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")
} To add You may not have noticed the difference between the OpenFile function and the Open function before. The Openfile function can specify the permissions of the returned file descriptor. Controlled through O_RDONLY, O_WRONLY, O_RDWR, etc. The Open function calls the OpenFile function internally. The default permission is O_RDONLY. If you only use the Open function to return the file descriptor and then write to the file, a bad file descriptor error will be returned. This should still be the case. Pay more attention and work out the details carefully. Essentially, it is a problem with the file descriptors in the OS. Add file copy operationrefer to this:https://www.socketloop.com/tutorials/golang-copy-directory-including-sub-directories-filesReprinted in: https://www.cnblogs.com/Goden/p/4533908.htmlFor more golang related technical articles, please visit The above is the detailed content of About the organization of Golang file operations. For more information, please follow other related articles on the PHP Chinese website!
Solve the problem of inconsistent Go toolchain architectureAug 26, 2025 am 10:39 AMThis article aims to answer the problem of inconsistent toolchain architecture encountered when building Go programs for ARM architecture. We will analyze why some Go tools (such as cgo, gofix, gofmt) will be built as ARM architecture, while others are still x86-64 architecture, and explain the limitations of cgo on the linux/arm platform and its future development direction.
Several ways to remove characters at the end of a string in GolangAug 26, 2025 am 10:36 AMThis article introduces several common methods to remove the end of a string in Golang, focusing on how to determine whether the end of a string is a specific character, and select the appropriate removal method based on the judgment results. A variety of implementation solutions are provided, including direct manipulation of string slices, using strings.TrimRight function, and custom TrimSuffix function, and accompanied by detailed code examples and output results for easy understanding and application by readers.
Ignore errors in Google App Engine Datastore queryAug 26, 2025 am 10:30 AMThis article describes how to gracefully handle ErrFieldMismatch errors when using Datastore queries in Google App Engine (GAE). Due to the flexibility of Datastore, entities of different structures are allowed to be stored with the same name, but may result in errors due to type mismatch or missing values when retrieving. This article will guide you on how to modify the query method and how to use datastore.Map to avoid problems caused by PropertyList, so as to retrieve data safely.
Solve the problem that the App Engine Go development server cannot find the template packageAug 26, 2025 am 10:18 AMThis article provides a detailed solution to the common "template package cannot be found" problem in App Engine Go development. By analyzing the causes of errors and combining actual code examples, we explain how to correctly initialize the template and how to use parameters in the template, help developers successfully complete the development of App Engine Go applications.
C-to-Go language code conversion tools and practicesAug 26, 2025 am 10:12 AMThe conversion of C code to Go is a complex engineering challenge aimed at leveraging the modern features and concurrency advantages of Go. This article will explore how existing automation tools, such as rc/c2go, can assist this process and analyze key challenges such as structure, memory management, and type mapping that may be encountered during the conversion process. Although automation tools can provide preliminary code, it still requires a lot of manual optimization to eventually generate code that meets Go language habits and high performance requirements.
Go language concurrent programming: mastering the synchronization mechanism of sync.WaitGroupAug 26, 2025 am 10:06 AMsync.WaitGroup is an important tool for coroutine synchronization in Go language. It allows the main coroutine to wait for a group of child coroutines to complete execution. By adding the counter, Done reduces the counter, and Wait blocking until the counter is zeroed, WaitGroup ensures the orderly completion of concurrent tasks, which is the key to building robust concurrent applications.
Computing SHA-256 intermediate state hash in GoAug 26, 2025 am 09:57 AMThis article introduces how to calculate the intermediate state of SHA-256 hash in Go, which is of great significance in scenarios such as Bitcoin mining. Due to the particularity of the Bitcoin protocol, specific endianness conversion of the data is required. This article will explain in detail how to handle these transformations and provide steps to modify the Go standard library to obtain intermediate state hashings, as well as corresponding code examples and considerations to help developers understand and implement this feature.
A practical guide to converting ANSI encoded text to UTF-8 strings in GoAug 26, 2025 am 09:48 AMThe strings in Go language are UTF-8 encoding by default, which means that when you need to process "ANSI" encoded text from outside, your byte sequence is actually correctly decoded from specific non-UTF-8 encodings (such as GBK, Windows-1252, etc.) into Unicode characters, and then represented in UTF-8 form by Go. This article will introduce in detail how to use the golang.org/x/text/encoding package to implement this transformation process, and provide practical code examples and precautions.


Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

WebStorm Mac version
Useful JavaScript development tools

SecLists
SecLists is the ultimate security tester's companion. It is a collection of various types of lists that are frequently used during security assessments, all in one place. SecLists helps make security testing more efficient and productive by conveniently providing all the lists a security tester might need. List types include usernames, passwords, URLs, fuzzing payloads, sensitive data patterns, web shells, and more. The tester can simply pull this repository onto a new test machine and he will have access to every type of list he needs.

SAP NetWeaver Server Adapter for Eclipse
Integrate Eclipse with SAP NetWeaver application server.

Dreamweaver Mac version
Visual web development tools

ZendStudio 13.5.1 Mac
Powerful PHP integrated development environment







