Go语言的IO操作建立在几个核心接口上,这些接口构成了灵活而一致的IO模型。
在io
包中定义了几个最基础的接口:
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}
type Closer interface {
Close() error
}
这些简单的接口组合成更复杂的接口,如:
type ReadWriter interface {
Reader
Writer
}
type ReadCloser interface {
Reader
Closer
}
type WriteCloser interface {
Writer
Closer
}
type ReadWriteCloser interface {
Reader
Writer
Closer
}
Go的IO操作遵循一些常见模式:
[]byte
),而非单个字节。io.EOF
错误。defer
和Close()
确保资源正确释放。Go标准库中与IO相关的包有多个,各自负责不同层次的功能:
io
:提供基础的IO接口和函数io/ioutil
:简化常见IO操作(Go 1.16后部分功能迁移到io和os包)os
:提供操作系统功能,包括文件操作bufio
:提供缓冲IO,提高性能bytes
和strings
:提供对字节切片和字符串的类似文件的访问在 Golang 中内置包os
中,打开文件使用 Open
函数(只读)和OpenFile
函数(可切换模式),关闭文件使用 Close
函数,打开文件、关闭文件以及大多数文件操作都涉及到一个很重要的结构体 os.File
结构体。
实现了io.Reader
、io.Writer
、io.Closer
等接口
type File struct {
*file // file 指针
}
type file struct {
//是一个FD结构体类型,是一个文件的唯一标志,每一个被打开的文件在操作系统中,都会有一个文件标志符来唯一标识一个文件
pfd poll.FD
//文件名
name string
//文件的路径信息,也是一个结构体
dirinfo *dirInfo
//是一个 bool 类型,表明该文件是否可以被追加写入内容。
appendMode bool
}
是 error
类型。
根据 reader
接口的说明,在 n > 0
且数据被读完了的情况下,返回的 error
有可能是 EOF
也有可能是 nil
。
var EOF = errors.New("EOF")
使用os.Open
和os.OpenFile
打开文件:
Open 函数接受一个字符串类型的文件名做为参数,如果打开成功,则返回一个 File 结构体的指针,否则就返回error错误信息。
底层使用的是OpenFile(name, O_RDONLY, 0)
,只读
os.Open(name string) (*File, error)
// 打开文件进行读取
file, err := os.Open("input.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close() // 确保文件会被关闭
os.OpenFile(name string, flag int, perm FileMode) (file *File, err error)
//name:文件路径
//flag:文件打开方式,多个可使用|分隔开
//perm:打开文件的模式,即权限,例如0666、0777
// 打开文件进行读写
rwFile, err := os.OpenFile("data.txt", os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
log.Fatal(err)
}
defer rwFile.Close()
打开方式 | 说明 |
---|---|
os.O_RDONLY |
只读方式打开 |
os.O_WRONLY |
只写方式打开 |
os.O_RDWR |
读写方式打开 |
os.O_APPEND |
追加方式打开 |
os.O_CREATE |
不存在,则创建 |
os.O_EXCL |
如果文件存在,且标定了O_CREATE的话,则产生一个错误 |
os.O_TRUNG |
如果文件存在,且它成功地被打开为只写或读写方式,将其长度裁剪唯一。(覆盖) |
os.O_NOCTTY |
如果文件名代表一个终端设备,则不把该设备设为调用进程的控制设备 |
os.O_NONBLOCK |
如果文件名代表一个FIFO,或一个块设备,字符设备文件,则在以后的文件及I/O操作中置为非阻塞模式。 |
os.O_SYNC |
当进行一系列写操作时,每次都要等待上次的I/O操作完成再进行。 |
// 常用标志组合
// 只读模式
file, err := os.OpenFile("file.txt", os.O_RDONLY, 0)
// 只写模式,如果文件不存在则创建
file, err := os.OpenFile("file.txt", os.O_WRONLY|os.O_CREATE, 0666)
// 追加模式,如果文件不存在则创建
file, err := os.OpenFile("file.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
// 读写模式,如果文件不存在则创建
file, err := os.OpenFile("file.txt", os.O_RDWR|os.O_CREATE, 0666)
// 创建新文件,如果文件已存在则截断为空
file, err := os.OpenFile("file.txt", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
使用 File 指针来调用 Close 函数,如果关闭失败会返回 error 错误信息。
一般在构建 File 对象后,使用defer file.Close()
来保证文件关闭。
func (file *File) Close() error
Seek设置下一次读/写的位置。
offset
:为相对偏移量
whence
:决定相对位置:0
为相对文件开头,1
为相对当前位置,2
为相对文件结尾。
它返回新的偏移量(相对开头)和可能的错误。
func (f *File) Seek(offset int64, whence int) (ret int64, err error)
Truncate改变文件的大小,它不会改变I/O的当前位置。 如果截断文件,多出的部分就会被丢弃,也就是从头开始保留size个字节。如果出错,错误底层类型是*PathError
,size = 0
则清空文件。
func (f *File) Truncate(size int64) error
也可以使用os包提供的方法,一样的作用,name
为文件名
func Truncate(name string, size int64) error
type FileInfo interface {
Name() string // 文件的名字
Size() int64 // 普通文件返回值表示其大小;其他文件的返回值含义各系统不同
Mode() FileMode // 文件的模式位 (例-rw-rw-r--)
ModTime() time.Time // 文件的修改时间
IsDir() bool // 等价于Mode().IsDir()
Sys() interface{} // 底层数据来源(可以返回nil)
}
os.fileStat
实现了FileInfo
接口的所有方法,使用os.Stat(path)
函数可以获取name
对应文件的fileStat
实例
func Stat(name string) (FileInfo, error)
示例:
// 获取文件信息
info, err := os.Stat("myfile.txt")
if err != nil {
if os.IsNotExist(err) {
fmt.Println("文件不存在")
} else {
log.Fatal(err)
}
return
}
fmt.Println("名称:", info.Name())
fmt.Println("大小:", info.Size(), "字节")
fmt.Println("权限:", info.Mode())
fmt.Println("修改时间:", info.ModTime())
fmt.Println("是目录:", info.IsDir())
由于os.File
实现了io.Reader
、io.Writer
接口,所以这里实际调用的是File中实现的Read()
和Write()
方法
//读,文件读取结束的标志是返回的 n 等于 0,并且err会返回io.EOF,单次读取的大小和b的大小一样
func (f *File) Read(b []byte) (n int, err error)
//写,以字节数组写入
func (f *File) Write(b []byte) (n int, err error)
//写,以字符串写入
func (f *File) WriteString(s string) (n int, err error)
//复制文件
io.Copy(dst io.Writer, src io.Reader) (written int64, err error)
func (f *File) Read(b []byte) (n int, err error)
,其中b
为保存读到数据的字节切片,n
为读到的字节长度,如果读到文件末尾,方法会返回0,io.EOF
package main
import (
"fmt"
"io"
"os"
)
func main() {
file, err := os.Open("./test.txt")
if err != nil {
fmt.Println(err)
}
defer file.Close()
//定义切片存放每次读取字节
data := make([]byte, 1024)
//声明切片,将每次读到的数据存放起来
var result []byte
for {
i, err := file.Read(data)
if err != nil && err != io.EOF {
fmt.Println(err)
break
}
if i == 0 {
break
}
result = append(result, data[:i]...)
}
fmt.Println(string(result))
}
func (f *File) Write(b []byte) (n int, err error)
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.OpenFile("./test.txt", os.O_RDWR|os.O_CREATE, 0777)
if err != nil {
fmt.Println(err)
}
defer file.Close()
s := "hello world\nhello golang"
//写入文件,将字符串转字节数组,也可以直接使用WriteString
n, err := file.Write([]byte(s))
if err != nil {
fmt.Println(err)
} else {
fmt.Println("write success,byte count =", n)
}
}
func Copy(dst Writer, src Reader) (written int64, err error)
,此处注意,由于File已经实现了Writer、Reader接口,所以可以直接传入File实例
package main
import (
"fmt"
"io"
"os"
)
func main() {
file, err := os.Open("./test.txt")
if err != nil {
fmt.Println(err)
}
defer file.Close()
fileCp, err := os.OpenFile("./testCp.txt", os.O_CREATE|os.O_WRONLY, 0777)
if err != nil {
fmt.Println(err)
}
defer fileCp.Close()
n, err := io.Copy(fileCp, file)
if err != nil {
fmt.Println(err)
}
fmt.Println("copy success,n =", n)
}
**注意:**此包内的方法,在Go 1.16
后,被移动到了io
或os
包内。
//读,由于这两个方法都是一次读取文件全部数据,所以不适合大文件,该方法在 Go1.16 被移动到 os 包
ioutil.ReadFile(filename string) ([]byte, error)
//读,这个方法需要打开一个文件,并将文件句柄传入参数
ioutil.ReadAll(r io.Reader) ([]byte, error)
//读取单层目录下所有文件(夹),返回FileInfo切片
ioutil.ReadDir(dirname string) ([]fs.FileInfo, error)
//写,文件不存在则创建文件,存在则清空文件,FileMode可以直接用0666或者0777
ioutil.WriteFile(filename string, data []byte, perm os.FileMode)
package main
import (
"fmt"
"io/ioutil"
)
func main() {
data, err := ioutil.ReadFile("./test.txt")
if err != nil {
fmt.Println(err)
}
//将字节数组转为string类型
fmt.Println(string(data))
}
package main
import (
"fmt"
"io/ioutil"
)
func main() {
s := "hello world\nhello golang"
err := ioutil.WriteFile("./test.txt", []byte(s), 0777)
if err != nil {
fmt.Println(err)
}
}
bufio 包实现了缓存IO。它包装了 io.Reader
和 io.Writer
对象,创建了另外的Reader和Writer对象,它们也实现了 io.Reader
和 io.Writer
接口,不过它们是有缓存的。
io操作本身的效率并不低,低的是频繁的访问本地磁盘的文件。所以bufio就提供了缓冲区(分配一块内存),读和写都先在缓冲区中,最后再读写文件,来降低访问本地磁盘的次数,从而提高效率。
bufio.Read(p []byte)
相当于每次读取大小len(p)
的内容
len(p)>len(buf)
,即要读取的内容比缓存区还要大,直接去文件读取即可len(p)<len(buf)
,即要读取的内容比缓存区小,缓存区从文件读取内容充满缓存区,并将p填满(此时缓存区有剩余内容,供下一次读取,这样也就减少了下次一读取磁盘io的数据量)bufio.Write(p []byte)
相当于写入len(p)
大小的内容
//NewReader 函数用来返回一个默认大小 buffer 的 Reader 对象(默认大小是 4096)
func NewReader(rd io.Reader) *Reader
//NewReaderSize 返回一个指定大小 buffer(size 最小为 16)的 Reader 对象,如果 io.Reader 参数已经是一个足够大的 Reader,它将返回该 Reader
func NewReaderSize(rd io.Reader, size int) *Reader
//Peek 返回缓存的一个切片,该切片引用缓存中前 n 个字节的数据,该操作不会将数据读出,只是引用
func (b *Reader) Peek(n int) ([]byte, error)
//Read 从 b 中读出数据到 p 中,返回读出的字节数和遇到的错误
func (b *Reader) Read(p []byte) (n int, err error)
//Buffered 返回缓存中未读取的数据的长度
func (b *Reader) Buffered() int
//ReadSlice 从输入中读取,直到遇到第一个界定符(delim)为止,返回一个指向缓存(也就意味着随着缓存改变而改变,所以一般用ReadBytes和ReadString)中字节的 slice,在下次调用读操作(read)时,这些字节会无效,如果在找到界定符之前缓存已经满了,ReadSlice 会返回 bufio.ErrBufferFull 错误
func (b *Reader) ReadSlice(delim byte) (line []byte, err error)
//ReadBytes 和ReadSlice区别就是返回的是当前缓存中字节slice的一个拷贝
func (b *Reader) ReadBytes(delim byte) (line []byte, err error)
//ReadString 和ReadBytes一样,只不过返回的是字符串,底层调用的是ReadBytes
func (b *Reader) ReadString(delim byte) (string, error)
//ReadLine 逐行读取,底层调用的是ReadSlice('\n')
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)
//读取单个UTF-8编码的Unicode字符,并返回字符及其字节大小
func (b *Reader) ReadRune() (r rune, size int, err error)
//返回默认缓冲大小的 Writer 对象(默认是4096),关闭文件前一定要Flush,将缓冲区的数据写入w
func NewWriter(w io.Writer) *Writer
//指定缓冲大小创建一个 Writer 对象,关闭文件前一定要Flush,将缓冲区的数据写入w
func NewWriterSize(w io.Writer, size int) *Writer
//写入单个字节,直接写入文件
func (b *Writer) WriteByte(c byte) error
//写入单个 Unicode 指针返回写入字节数错误信息,直接写入文件
func (b *Writer) WriteRune(r rune) (size int, err error)
//写入字符串并返回写入字节数和错误信息,直接写入文件
func (b *Writer) WriteString(s string) (int, error)
// 创建一个用于逐个读取输入缓冲区的扫描器
func NewScanner(r io.Reader) *Scanner
// 用于读取输入缓冲区中的下一个数据块,并将其保存在内部的缓冲区中。如果读取成功,则返回 true;如果已经读取了所有数据或者发生了错误,则返回 false。
func (s *Scanner) Scan() bool
// 用于获取内部缓冲区中的文本内容,通常与 Scan() 方法一起使用,用于获取读取的数据。
func (s *Scanner) Text() string
// 用于获取内部缓冲区中的字节内容,通常与 Scan() 方法一起使用,用于获取读取的数据。
func (s *Scanner) Bytes() []byte
// 用于获取在读取输入时发生的错误信息,如果读取过程中没有发生错误,则返回 nil;否则,返回一个非 nil 的错误对象。
func (s *Scanner) Err() error
// 用于自定义输入缓冲区大小,接受一个 []byte 类型的参数,用于指定缓冲区的大小。
func (s *Scanner) Buffer(buf []byte, max int)
// 用于指定一个分割函数,将输入分割成多个数据块,接受一个 func([]byte) bool 类型的参数,该函数在每次读取输入时被调用,用于判断是否需要将当前数据块分割成多个小块。通常用于处理非常大的数据块,以避免内存溢出等问题。
func (s *Scanner) Split(split SplitFunc)
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main() {
file, err := os.Open("./test.txt")
if err != nil {
fmt.Println(err)
}
defer file.Close()
fileBuf := bufio.NewReader(file)
data := make([]byte, 1024)
var result []byte
for {
i, err := fileBuf.Read(data)
if err != nil && err != io.EOF {
fmt.Println(err)
break
}
if i == 0 {
break
}
result = append(result, data[:i]...)
}
fmt.Println(string(result))
}
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
file, err := os.OpenFile("./test.txt", os.O_RDWR, 777)
if err != nil {
fmt.Errorf("%+v", err)
}
reader := bufio.NewReader(file)
r, i, err := reader.ReadRune()
for i > 0 && err == nil {
fmt.Print(string(r))
r, i, err = reader.ReadRune()
}
file.Close()
}
file, err := os.Open("data.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text() // 获取当前行文本
// 或者使用scanner.Bytes()获取[]byte
fmt.Println(line)
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
Scanner默认按行分割,但可以自定义分割方式,内置的分割函数:
bufio.ScanLines
:按行分割(默认)bufio.ScanWords
:按单词分割bufio.ScanRunes
:按UTF-8编码的Unicode码点分割bufio.ScanBytes
:按字节分割file, err := os.Open("words.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
// 使用单词分割函数
scanner.Split(bufio.ScanWords)
wordCount := 0
for scanner.Scan() {
word := scanner.Text()
wordCount++
fmt.Printf("单词%d: %s\n", wordCount, word)
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
注意:关闭文件前一定要Flush()
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
file, err := os.OpenFile("./test.txt", os.O_WRONLY|os.O_CREATE, 0777)
if err != nil {
fmt.Println(err)
}
defer file.Close()
fileBuf := bufio.NewWriter(file)
s := "hello world\nhello golang"
fileBuf.Write([]byte(s))
//关闭文件前一定要fulsh,将缓冲区内的数据写入文件
fileBuf.Flush()
}
// Go 1.16前
data, err := ioutil.ReadFile("input.txt")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(data))
// Go 1.16+
data, err := os.ReadFile("input.txt")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(data))
file, err := os.Open("largefile.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
buffer := make([]byte, 1024) // 1KB缓冲区
for {
bytesRead, err := file.Read(buffer)
if err != nil {
if err != io.EOF {
log.Fatal(err)
}
break // 读取完毕
}
// 处理读取的数据
fmt.Print(string(buffer[:bytesRead]))
}
file, err := os.Open("lines.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
// 设置每行最大长度(可选,默认64K)
// scanner.Buffer(make([]byte, 1024), 1024*1024) // 缓冲区和最大容量
lineCount := 0
for scanner.Scan() {
line := scanner.Text()
lineCount++
fmt.Printf("第%d行: %s\n", lineCount, line)
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
file, err := os.Open("data.bin")
if err != nil {
log.Fatal(err)
}
defer file.Close()
// 移动到文件第100个字节
_, err = file.Seek(100, 0)
if err != nil {
log.Fatal(err)
}
// 读取10个字节
data := make([]byte, 10)
count, err := file.Read(data)
if err != nil {
log.Fatal(err)
}
fmt.Printf("读取了%d字节: %v\n", count, data)
// Go 1.16前
data := []byte("Hello, 世界!")
err := ioutil.WriteFile("output.txt", data, 0666)
if err != nil {
log.Fatal(err)
}
// Go 1.16+
data := []byte("Hello, 世界!")
err := os.WriteFile("output.txt", data, 0666)
if err != nil {
log.Fatal(err)
}
file, err := os.Create("output.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
// 多次写入
for i := 0; i < 5; i++ {
data := []byte(fmt.Sprintf("第%d行数据\n", i+1))
_, err := file.Write(data)
if err != nil {
log.Fatal(err)
}
}
file, err := os.Create("buffered.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
writer := bufio.NewWriter(file)
// 写入缓冲区
for i := 0; i < 1000; i++ {
fmt.Fprintf(writer, "第%d行\n", i+1)
}
// 确保缓冲区内容写入文件
err = writer.Flush()
if err != nil {
log.Fatal(err)
}
file, err := os.OpenFile("log.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
log.Fatal(err)
}
defer file.Close()
data := []byte("新的日志条目\n")
if _, err := file.Write(data); err != nil {
log.Fatal(err)
}
//创建
os.Mkdir(name string, perm FileMode) error //创建目录,只创建一层,相当于mkdir
os.MkdirAll(path string, perm FileMode) error //创建多层目录,相当于mkdir -p
os.Create(name string) (file *File, err error) //创建文件,如果存在则覆盖
//移动
os.Rename(oldpath, newpath string) error //重命名、移动文件
//删除
os.Remove(name string) error //删除单个
os.RemoveAll(path string) error //递归删除目录
// 创建单个目录
err := os.Mkdir("newdir", 0755)
if err != nil {
log.Fatal(err)
}
// 创建多级目录
err = os.MkdirAll("path/to/nested/dir", 0755)
if err != nil {
log.Fatal(err)
}
// 删除单个目录(必须为空)
err = os.Remove("emptydir")
if err != nil {
log.Fatal(err)
}
// 删除目录及其内容
err = os.RemoveAll("dir-with-content")
if err != nil {
log.Fatal(err)
}
// 打开目录
dir, err := os.Open(".")
if err != nil {
log.Fatal(err)
}
defer dir.Close()
// 读取目录中的条目
entries, err := dir.ReadDir(-1) // -1表示读取所有条目
if err != nil {
log.Fatal(err)
}
// 遍历条目
for _, entry := range entries {
fmt.Println("名称:", entry.Name())
fmt.Println("是目录:", entry.IsDir())
info, err := entry.Info()
if err == nil {
fmt.Println(" 大小:", info.Size())
fmt.Println(" 修改时间:", info.ModTime())
fmt.Println(" 权限:", info.Mode())
}
fmt.Println()
}
// 使用filepath.Walk遍历目录及其子目录
err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Printf("访问 %s 错误: %v\n", path, err)
return err
}
fmt.Printf("%-50s | %-10d | %s\n", path, info.Size(), info.Mode())
return nil
})
if err != nil {
log.Fatal(err)
}
Go 1.16 新增。
// 使用更高效的filepath.WalkDir
err := filepath.WalkDir(".", func(path string, d fs.DirEntry, err error) error {
if err != nil {
fmt.Printf("访问 %s 错误: %v\n", path, err)
return err
}
// 只处理常规文件
if !d.IsDir() {
fmt.Printf("文件: %s\n", path)
}
return nil
})
if err != nil {
log.Fatal(err)
}
在开发过程中,经常需要创建临时文件和目录来存储中间数据或缓存信息。Go语言的os
包提供了一些函数用于创建和管理临时文件和目录。
Go 1.16
之前在ioutil
包中。
使用os.CreateTemp
函数可以创建一个临时文件。该函数会在指定目录下创建一个具有唯一名称的临时文件,并返回该文件的文件对象和路径。
package main
import (
"fmt"
"os"
)
func main() {
// 创建临时文件
file, err := os.CreateTemp("", "example_*.txt")
if err != nil {
fmt.Println("Error creating temporary file:", err)
return
}
defer os.Remove(file.Name()) // 在使用完后删除临时文件
defer file.Close()
fmt.Println("Temporary file created:", file.Name())
// 向临时文件写入数据
_, err = file.WriteString("Hello, Temporary File!")
if err != nil {
fmt.Println("Error writing to temporary file:", err)
return
}
fmt.Println("Data written to temporary file successfully")
}
上述代码会在系统默认的临时文件目录下创建一个临时文件,并写入一些数据。临时文件的名称具有唯一性,并包含example_
前缀。
使用os.MkdirTemp
函数可以创建一个临时目录。该函数会在指定目录下创建一个具有唯一名称的临时目录,并返回该目录的路径。
package main
import (
"fmt"
"os"
)
func main() {
// 创建临时目录
dir, err := os.MkdirTemp("", "exampledir_*")
if err != nil {
fmt.Println("Error creating temporary directory:", err)
return
}
defer os.RemoveAll(dir) // 在使用完后删除临时目录
fmt.Println("Temporary directory created:", dir)
// 在临时目录中创建一个文件
tempFile := fmt.Sprintf("%s/%s", dir, "tempfile.txt")
file, err := os.Create(tempFile)
if err != nil {
fmt.Println("Error creating file in temporary directory:", err)
return
}
defer file.Close()
// 向文件中写入数据
_, err = file.WriteString("Hello, Temporary Directory!")
if err != nil {
fmt.Println("Error writing to file in temporary directory:", err)
return
}
fmt.Println("Data written to file in temporary directory successfully")
}
上述代码会在系统默认的临时文件目录下创建一个临时目录,并在该目录中创建一个文件并写入一些数据。
在创建临时文件和目录后,记得在使用完毕后进行清理。可以使用os.Remove
和os.RemoveAll
函数分别删除单个文件和目录树:
package main
import (
"fmt"
"os"
)
func main() {
// 创建临时文件
file, err := os.CreateTemp("", "example_*.txt")
if err != nil {
fmt.Println("Error creating temporary file:", err)
return
}
defer file.Close()
// 创建临时目录
dir, err := os.MkdirTemp("", "exampledir_*")
if err != nil {
fmt.Println("Error creating temporary directory:", err)
return
}
// 清理临时文件
err = os.Remove(file.Name())
if err != nil {
fmt.Println("Error removing temporary file:", err)
return
}
fmt.Println("Temporary file removed:", file.Name())
// 清理临时目录
err = os.RemoveAll(dir)
if err != nil {
fmt.Println("Error removing temporary directory:", err)
return
}
fmt.Println("Temporary directory removed:", dir)
}
上述代码会创建一个临时文件和一个临时目录,并在使用完后将其删除。
os.Stdin
:标准输入的文件实例,类型为*File
os.Stdout
:标准输出的文件实例,类型为*File
os.Stderr
:标准错误输出的文件实例,类型为*File
package main
import "os"
func main() {
var buf [16]byte
os.Stdin.Read(buf[:])
os.Stdin.WriteString(string(buf[:]))
}
路径相关的函数有两个包,path
和 path/filepath
,两个包内有一些相同的函数,如IsAbs()
、Join()
、Dir()
,两个包的区别在于:
path
包:提供了一些基本的路径处理功能,如路径拼接、获取文件名、获取文件扩展名等。这些功能适用于简单的路径处理需求。filepath
包:在path
包的基础上,增加了对不同操作系统的兼容性处理,能够自动根据不同的操作系统进行路径转换。因此,如果你有跨平台的需求,建议使用filepath
包。跨平台支持:filepath
包:自动根据不同的操作系统进行路径转换,确保跨平台的兼容性。例如,在Windows系统中,路径分隔符是反斜杠(\
),而在Unix和Linux系统中是正斜杠(/
)。filepath
包能够处理这些差异,使得代码在不同操作系统上都能正常运行。
// 路径拼接
func Join(elem ...string) string
// 判断文件是否是绝对路径
func IsAbs(path string) bool
// 获取目录
func Dir(path string) string
// 获取文件拓展名
func Ext(path string) string
// 获取targpath相对于basepath的相对路径
func Rel(basepath, targpath string) (string, error)
// 获取绝对路径,如果path不是绝对路径,会加入当前工作目录以使之成为绝对路径。
func Abs(path string) (string, error)
// 获取路径中的最后一个元素
func Base(path string) string
// 获取路径中除去最后一个元素后前面的部分
func Dir(path string) string
// 获取文件拓展名
func Ext(path string) string
// 路径拼接
func Join(elem ...string) string
// 将路径拆分为目录和文件名两部分
func Split(path string) (dir, file string)