谈谈对Golang IO读写的困惑
Go指南10-谈谈对Golang IO读写的困惑
前言
Golang的IO读写提供了很多种方式,目前本人知道的有io库、os库、ioutil库、bufio库、bytes/strings库等
# 只列举了核心的目录及文件
src:
- bufio
- bufio.go
- bytes
- buffer.go
- reader.go
- io
- ioutil
- ioutil.go
- io.go
- os
- file.go
- strings
- reader.go
1. io库属于底层接口定义库,其作用是是定义一些基本接口和一些基本常量,并对这些接口的作用给出说明,常见的接口有Reader、Writer等。一般用这个库只是为了调用它的一些常量,比如io.EOF。
2. ioutil库包含在io目录下,它的主要作用是作为一个工具包,里面有一些比较实用的函数,比如 ReadAll(从某个源读取数据)、ReadFile(读取文件内容)、WriteFile(将数据写入文件)、ReadDir(获取目录)
3. os库主要是跟操作系统打交道,所以文件操作基本都会跟os库挂钩,比如创建文件、打开一个文件等。这个库往往会和ioutil库、bufio库等配合使用
4. bufio库可以理解为在io库上再封装一层,加上了缓存功能。它可能会和ioutil库和bytes.Buffer搞混。
4.1 bufio VS ioutil库:两者都提供了对文件的读写功能,唯一的不同就是bufio多了一层缓存的功能,这个优势主要体现读取大文件的时候(ioutil.ReadFile是一次性将内容加载到内存,如果内容过大,很容易爆内存)
4.2 bufio VS bytes.Buffer:两者都提供一层缓存功能,它们的不同主要在于 bufio 针对的是文件到内存的缓存,而 bytes.Buffer 的针对的是内存到内存的缓存(个人感觉有点像channel,你也可以发现 bytes.Buffer 并没有提供接口将数据写到文件)。
5. bytes和strings库:这两个库有点迷,首先它们都实现了Reader接口,所以它们的不同主要在于针对的对象不同,bytes针对的是字节,strings针对的是字符串(它们的方法实现原理很相似)。另一个区别就是 bytes还带有Buffer的功能,但是 strings没提供。
注:关于Reader和Writer接口,可以简单理解为读取源和写入源,即只要实现Reader里面的Read方法,这个东西就可以作为一个读取源,里面可以包含数据并被我们读取;Writer亦是如此。
窥探 io 库
io库比较常用的接口有三个,分别是Reader,Writer和Close。
// Read方法会接收一个字节数组p,并将读取到的数据存进该数组,最后返回读取的字节数n。
// 注意n不一定等于读取的数据长度,比如字节数组p的容量太小,n会等于数组的长度
type Reader interface {
Read(p []byte) (n int, err error)
}
// Write 方法同样接收一个字节数组p,并将接收的数据保存至文件或者标准输出等,返回的n表示写入的数据长度。
// 当n不等于len(p)时,返回一个错误。
type Writer interface {
Write(p []byte) (n int, err error)
}
// 关闭操作
type Closer interface {
Close() error
}
strings库中的Reader是个结构体,以及Read方法的实现 :
// 定义一个Reader接口体
type Reader struct {
s string
i int64 // current reading index
prevRune int // index of previous rune; or < 0
}
// 通过NewReader方法得到 reader 对象,这里有个关键的地方是传入的字符串被赋值到 s 变量中
func NewReader(s string) *Reader {
return &Reader{s, 0, -1}
}
// Read方法: 核心是 copy 方法,参数b虽然是切片,但是copy方法会影响到它的底层数组
func (r *Reader) Read(b []byte) (n int, err error) {
if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
r.prevRune = -1
// 核心方法
n = copy(b, r.s[r.i:])
r.i += int64(n)
return
}
窥探 ioutil 库
上面提到,ioutil 库就是一个工具包,里面主要是比较实用的函数,比如ReadFile、WriteFile等,唯一需要注意的是它们都是一次性读取和一次性写入,所以当读取的时候注意文件不能过大。
//ReadAll 从 r 读取,直到出错或 EOF 并返回它读取的数据。
func ReadAll(r io.Reader) ([]byte, error)
// ReadFile 读取文件中的所有数据,返回读取的数据和遇到的错误。
func ReadFile(filename string) ([]byte, error)
// WriteFile 向文件中写入数据,写入前会清空文件。如果文件不存在,则会以指定的权限创建该文件。
func WriteFile(filename string, data []byte, perm os.FileMode) error
//ReadDir 读取指定目录中的所有目录和文件(不包括子目录)。
func ReadDir(dirname string) ([]os.FileInfo, error)
从文件读取数据:
func readByFile() {
data, err := ioutil.ReadFile( "./lab8_io/file/test.txt")
if err != nil {
log.Fatal("err:", err)
return
}
fmt.Println("data", string(data)) // hello world!
}
把数据写入到文件:
func writeFile() {
err := ioutil.WriteFile("./lab8_io/file/write_test.txt", []byte("hello world!"), 0644)
if err != nil {
panic(err)
return
}
}
遍历目录的操作
func allDir(path string) {
fileInfos, err := ioutil.ReadDir(path)
if err != nil{
fmt.Println(err)
return
}
for _,f := range fileInfos{
if !f.IsDir(){
fmt.Println("file ",f.Name())
return
}
fmt.Println("dir ",f.Name())
allDir(path+"/"+f.Name())
}
}
Readall
r := strings.NewReader("Go is a general-purpose language designed with systems programming in mind.")
b, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", b)
窥探bufio库
1、Reader类型
type Reader struct {
buf []byte
rd io.Reader // reader provided by the client
r, w int // buf read and write positions
err error
lastByte int
lastRuneSize int
}
func NewReader(rd io.Reader) *Reader
func NewReader(rd io.Reader) *Reader
从一个普通的 reader 变成一个具有缓冲的 reader,默认的缓冲大小是 4096
bufio 里的 reader 适合大文本大数据的具有缓冲的读取(缓冲的分配也很有意思),它原有的方法都比较底层,包装为 Scanner 后可以对大文本进行自定义的切割扫描
func (*Reader) Read
func (b *Reader) Read(p []byte) (n int, err error)
Read读取数据写入p。本方法返回写入p的字节数。本方法一次调用最多会调用下层Reader接口一次Read方法,因此返回值n可能小于len(p)。读取到达结尾时,返回值n将为0而err将为io.EOF。
func (*Reader) ReadLine
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)
ReadLine是一个低水平的行数据读取原语。大多数调用者应使用ReadBytes('\n')或ReadString('\n')代替,或者使用Scanner。
ReadLine尝试返回一行数据,不包括行尾标志的字节。如果行太长超过了缓冲,返回值isPrefix会被设为true,并返回行的前面一部分。该行剩下的部分将在之后的调用中返回。返回值isPrefix会在返回该行最后一个片段时才设为false。返回切片是缓冲的子切片,只在下一次读取操作之前有效。ReadLine要么返回一个非nil的line,要么返回一个非nil的err,两个返回值至少一个非nil。
返回的文本不包含行尾的标志字节("\r\n"或"\n")。如果输入流结束时没有行尾标志字节,方法不会出错,也不会指出这一情况。在调用ReadLine之后调用UnreadByte会总是吐出最后一个读取的字节(很可能是该行的行尾标志字节),即使该字节不是ReadLine返回值的一部分。
func (*Reader) ReadBytes
func (b *Reader) ReadBytes(delim byte) (line []byte, err error)
ReadBytes读取直到第一次遇到delim字节,返回一个包含已读取的数据和delim字节的切片。如果ReadBytes方法在读取到delim之前遇到了错误,它会返回在错误之前读取的数据以及该错误(一般是io.EOF)。当且仅当ReadBytes方法返回的切片不以delim结尾时,会返回一个非nil的错误。
func (*Reader) ReadString
func (b *Reader) ReadString(delim byte) (line string, err error)
ReadString读取直到第一次遇到delim字节,返回一个包含已读取的数据和delim字节的字符串。如果ReadString方法在读取到delim之前遇到了错误,它会返回在错误之前读取的数据以及该错误(一般是io.EOF)。当且仅当ReadString方法返回的切片不以delim结尾时,会返回一个非nil的错误。
func (*Reader) WriteTo
func (b *Reader) WriteTo(w io.Writer) (n int64, err error)
WriteTo方法实现了io.WriterTo接口。
2、Writer类型
// Writer 实现了带缓存的 io.Writer 对象
// 如果在向 Writer 中写入数据的过程中遇到错误
// 则 Writer 不会再接受任何数据
// 而且后续的写入操作都将返回错误信息
type Writer struct {
err error
buf []byte
n int
wr io.Writer
}
example:
w := bufio.NewWriter(os.Stdout) fmt.Fprint(w, "Hello, ") fmt.Fprint(w, "world!") w.Flush() // Don't forget to flush!
func NewWriter
func NewWriter(w io.Writer) *Writer
NewWriter创建一个具有默认大小缓冲、写入w的*Writer对象。从一个普通的 writer 变成一个具有缓冲的 writer
func (*Writer) Write
func (b *Writer) Write(p []byte) (nn int, err error)
Write将p的内容写入缓冲。返回写入的字节数。如果返回值nn < len(p),还会返回一个错误说明原因。
func (*Writer) WriteString
func (b *Writer) WriteString(s string) (int, error)
WriteString写入一个字符串。返回写入的字节数。如果返回值nn < len(s),还会返回一个错误说明原因。
func (*Writer) Flush
func (b *Writer) Flush() error
Flush方法将缓冲中的数据写入下层的io.Writer接口。
窥探bytes
bytes.Buffer 是一个实现了读写方法的可变大小的字节缓冲。本类型的零值是一个空的可用于读写的缓冲
// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
// The zero value for Buffer is an empty buffer ready to use.
type Buffer struct {
buf []byte // contents are the bytes buf[off : len(buf)]
off int // read at &buf[off], write at &buf[len(buf)]
lastRead readOp // last read operation, so that Unread* can work correctly.
}
NewBuffer
func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }
- NewBuffer使用buf作为参数初始化Buffer,
- Buffer既可以被读也可以被写
- 如果是读Buffer,buf需填充一定的数据
- 如果是写,buf需有一定的容量(capacity),当然也可以通过new(Buffer)来初始化Buffer。另外一个方法NewBufferString用一个string来初始化可读Buffer,并用string的内容填充Buffer.
NewBufferString
- 方法NewBufferString用一个string来初始化可读Buffer,并用string的内容填充Buffer.
- 用法和NewBuffer没有太大区别
func NewBufferString(s string) *Buffer {
return &Buffer{buf: []byte(s)}
}
创建 Buffer缓冲器
var b bytes.Buffer //直接定义一个 Buffer 变量,而不用初始化
b.Writer([]byte("Hello ")) // 可以直接使用
b1 := new(bytes.Buffer) //直接使用 new 初始化,可以直接使用
fmt.Println("===========以下buf2,buf3,buf5等效=========")
buf2:= bytes.NewBuffer([]byte("swift"))
buf3:= bytes.NewBufferString("swift")
buf5:= bytes.NewBuffer([]byte{'s','w','i','f','t'})
fmt.Println("buf2:", buf2)
fmt.Println("===========以下创建空的缓冲器等效=========")
buf1:= bytes.NewBuffer([]byte{})
buf7:= bytes.NewBufferString("")
向 Buffer 中写入数据
Write 把字节切片 p 写入到buffer缓冲区的尾部。
func (b *Buffer) Write(p []byte) (n int, err error)
WriteString 使用WriteString方法,将一个字符串放到缓冲器的尾部
func (b *Buffer) WriteString(s string) (n int, err error)
WriteByte 将一个byte类型的数据放到缓冲器的尾部
func (b *Buffer) WriteByte(c byte) error
WriteRune 将一个rune类型的数据放到缓冲器的尾部
func (b *Buffer) WriteRune(r rune) (n int, err error)
完整的例子
1 package main 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 ) 8 9 func main() { 10 //newBuffer 整形转换成字节 11 var n int = 10000 12 intToBytes := IntToBytes(n) 13 fmt.Println("==========int to bytes========") 14 fmt.Println(intToBytes) 15 //NewBufferString 16 TestBufferString() 17 //write 18 BufferWrite() 19 //WriteString 20 BufferWriteString() 21 //WriteByte 22 BufferWriteByte() 23 //WriteRune 24 BufferWriteRune() 25 26 } 27 28 29 func IntToBytes(n int) []byte { 30 x := int32(n) 31 //创建一个内容是[]byte的slice的缓冲器 32 //与bytes.NewBufferString("")等效 33 bytesBuffer := bytes.NewBuffer([]byte{}) 34 binary.Write(bytesBuffer, binary.BigEndian, x) 35 return bytesBuffer.Bytes() 36 } 37 38 func TestBufferString(){ 39 buf1:=bytes.NewBufferString("swift") 40 buf2:=bytes.NewBuffer([]byte("swift")) 41 buf3:=bytes.NewBuffer([]byte{'s','w','i','f','t'}) 42 fmt.Println("===========以下buf1,buf2,buf3等效=========") 43 fmt.Println("buf1:", buf1) 44 fmt.Println("buf2:", buf2) 45 fmt.Println("buf3:", buf3) 46 fmt.Println("===========以下创建空的缓冲器等效=========") 47 buf4:=bytes.NewBufferString("") 48 buf5:=bytes.NewBuffer([]byte{}) 49 fmt.Println("buf4:", buf4) 50 fmt.Println("buf5:", buf5) 51 } 52 53 func BufferWrite(){ 54 fmt.Println("===========以下通过Write把swift写入Learning缓冲器尾部=========") 55 newBytes := []byte("swift") 56 //创建一个内容Learning的缓冲器 57 buf := bytes.NewBuffer([]byte("Learning")) 58 //打印为Learning 59 fmt.Println(buf.String()) 60 //将newBytes这个slice写到buf的尾部 61 buf.Write(newBytes) 62 fmt.Println(buf.String()) 63 } 64 65 func BufferWriteString(){ 66 fmt.Println("===========以下通过Write把swift写入Learning缓冲器尾部=========") 67 newString := "swift" 68 //创建一个string内容Learning的缓冲器 69 buf := bytes.NewBufferString("Learning") 70 //打印为Learning 71 fmt.Println(buf.String()) 72 //将newString这个string写到buf的尾部 73 buf.WriteString(newString) 74 fmt.Println(buf.String()) 75 } 76 77 func BufferWriteByte(){ 78 fmt.Println("===========以下通过WriteByte把swift写入Learning缓冲器尾部=========") 79 var newByte byte = '!' 80 //创建一个string内容Learning的缓冲器 81 buf := bytes.NewBufferString("Learning") 82 //打印为Learning 83 fmt.Println(buf.String()) 84 //将newString这个string写到buf的尾部 85 buf.WriteByte(newByte) 86 fmt.Println(buf.String()) 87 } 88 89 func BufferWriteRune(){ 90 fmt.Println("===========以下通过WriteRune把\"好\"写入Learning缓冲器尾部=========") 91 var newRune = '好' 92 //创建一个string内容Learning的缓冲器 93 buf := bytes.NewBufferString("Learning") 94 //打印为Learning 95 fmt.Println(buf.String()) 96 //将newString这个string写到buf的尾部 97 buf.WriteRune(newRune) 98 fmt.Println(buf.String()) 99 }
向 Buffer 中读取数据
Read 给Read方法一个容器p,读完后,p就满了,缓冲器内容相应的减少了,只保留剩余的未读的字符,返回的n为成功读的数量
func (b *Buffer) Read(p []byte) (n int, err error) {}
ReadByte 返回缓冲器头部的第一个byte,缓冲器头部第一个byte被拿掉
func (b *Buffer) ReadByte() (c byte, err error)
ReadRune ReadRune和ReadByte很像 返回缓冲器头部的第一个rune,缓冲器头部第一个rune被拿掉
func (b *Buffer) ReadRune() (r rune, size int, err error)
ReadBytes
ReadBytes需要一个byte作为分隔符,读的时候从缓冲器里找第一个出现的分隔符(delim),找到后,把从缓冲器头部开始到分隔符之间的所有byte进行返回,作为byte类型的slice,返回后,缓冲器也会空掉一部分
func (b *Buffer) ReadBytes(delim byte) (line []byte, err error)
ReadString
ReadString需要一个byte作为分隔符,读的时候从缓冲器里找第一个出现的分隔符(delim),找到后,把从缓冲器头部开始到分隔符之间的所有byte进行返回,作为字符串,返回后,缓冲器也会空掉一部分 和ReadBytes类似
func (b *Buffer) ReadString(delim byte) (line string, err error)
string
将未读取的数据返回成 string
func (b *Buffer) String() string {}
Reset
将数据清空,没有数据可读
func (b *Buffer) Reset() { b.Truncate(0)}
完整的例子
1 func Read(){ 2 bufs := bytes.NewBufferString("Learning swift.") 3 fmt.Println(bufs.String()) 4 5 //声明一个空的slice,容量为8 6 l := make([]byte, 8) 7 //把bufs的内容读入到l内,因为l容量为8,所以只读了8个过来 8 bufs.Read(l) 9 fmt.Println("::bufs缓冲器内容::") 10 fmt.Println(bufs.String()) 11 //空的l被写入了8个字符,所以为 Learning 12 fmt.Println("::l的slice内容::") 13 fmt.Println(string(l)) 14 //把bufs的内容读入到l内,原来的l的内容被覆盖了 15 bufs.Read(l) 16 fmt.Println("::bufs缓冲器被第二次读取后剩余的内容::") 17 fmt.Println(bufs.String()) 18 fmt.Println("::l的slice内容被覆盖,由于bufs只有7个了,因此最后一个g被留下来了::") 19 fmt.Println(string(l)) 20 21 } 22 23 func ReadByte(){ 24 bufs := bytes.NewBufferString("Learning swift.") 25 fmt.Println(bufs.String()) 26 //读取第一个byte,赋值给b 27 b, _ := bufs.ReadByte() 28 fmt.Println(bufs.String()) 29 fmt.Println(string(b)) 30 } 31 32 func ReadRune(){ 33 bufs := bytes.NewBufferString("学swift.") 34 fmt.Println(bufs.String()) 35 36 //读取第一个rune,赋值给r 37 r,z,_ := bufs.ReadRune() 38 //打印中文"学",缓冲器头部第一个被拿走 39 fmt.Println(bufs.String()) 40 //打印"学","学"作为utf8储存占3个byte 41 fmt.Println("r=",string(r),",z=",z) 42 43 } 44 45 func ReadBytes(){ 46 bufs := bytes.NewBufferString("现在开始 Learning swift.") 47 fmt.Println(bufs.String()) 48 49 var delim byte = 'L' 50 line, _ := bufs.ReadBytes(delim) 51 fmt.Println(bufs.String()) 52 fmt.Println(string(line)) 53 } 54 func Reset(){ 55 bufs := bytes.NewBufferString("现在开始 Learning swift.") 56 fmt.Println(bufs.String()) 57 58 bufs.Reset() 59 fmt.Println("::已经清空了bufs的缓冲内容::") 60 fmt.Println(bufs.String()) 61 }
转自:https://blog.csdn.net/txj236/article/details/52130439?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2.control
os File 文件的操作
首先,file 类是在 os 包中的,封装了底层的文件描述符和相关信息,同时封装了 Read 和 Write 的实现
1. FileInfo 接口
FileInfo 接口中定义了 File 信息相关的方法。
type FileInfo interface {
Name() string // base name of the file 文件名.扩展名 aa.txt
Size() int64 // 文件大小,字节数 12540
Mode() FileMode // 文件权限 -rw-rw-rw-
ModTime() time.Time // 修改时间 2020-09-23 16:30:53 +0800 CST
IsDir() bool // 是否文件夹
Sys() interface{} // 基础数据源接口(can return nil)
}
2. File 操作
os.File类型拥有的都是指针方法,它的指针实现了很多io包中的接口。
对于io包中最核心的3个简单接口io.Reader、io.Writer和io.Closer,*os.File类型都实现了它们
要操作文件,首先要获取一个os.File类型的指针值,简称File值。在os包中,有如下几个函数:
- Create
- NewFile
- Open
- OpenFile
type File //File代表一个打开的文件对象。 func Create(name string) (file *File, err error) //Create采用模式0666(任何人都可读写,不可执行)创建一个名为name的文件,如果文件已存在会截断它(为空文件)。如果成功,返回的文件对象可用于I/O;对应的文件描述符具有O_RDWR模式。如果出错,错误底层类型是*PathError。 func Open(name string) (file *File, err error) //Open打开一个文件只读用于读取。如果操作成功,返回的文件对象的方法可用于读取数据;对应的文件描述符具有O_RDONLY模式。如果出错,错误底层类型是*PathError。 func OpenFile(name string, flag int, perm FileMode) (file *File, err error) //OpenFile是一个更一般性的文件打开函数,大多数调用者都应用Open或Create代替本函数。它会使用指定的选项(如O_RDONLY等)、指定的模式(如0666等)打开指定名称的文件。如果操作成功,返回的文件对象可用于I/O。如果出错,错误底层类型是*PathError。
第二个参数: 针对File值的操作模式主要有:
- 只读模式:os.O_RNONLY
- 只写模式:os.O_WRONLY
- 读写模式:os.O_RDWR
另外,还可以再设置额外的操作模式,选项如下:
- os.O_APPEND : 写入时追加到现有内容的后边
- os.O_CREARE : 当文件不存在是,创建一个新文件
- os.O_EXCL : 需要与os.O_CREATE一同使用,表示给定的路径不能是一个已存在的文件。(就是指定的文件必须不存在,然后创建文件)
- os.O_SYNC : 在打开的文件之上实施同步I/O。它会保证读写的内容总会与硬盘上的数据保持同步
- os.O_TRUNC : 如果文件已存在,并且是常规文件,就先清空其中的内容。(就是创建文件,如果文件存在则新建并覆盖)
第三个参数,访问模式有:
os.ModePerm= 0777 或者手动指定 0666
func NewFile(fd uintptr, name string) *File //NewFile使用给出的Unix文件描述符和名称创建一个文件。 func Pipe() (r *File, w *File, err error) //Pipe返回一对关联的文件对象。从r的读取将返回写入w的数据。本函数会返回两个文件对象和可能的错误。 func (f *File) Name() string //Name方法返回(提供给Open/Create等方法的)文件名称。 func (f *File) Stat() (fi FileInfo, err error) //Stat返回描述文件f的FileInfo类型值。如果出错,错误底层类型是*PathError。 func (f *File) Close() error //Close关闭文件f,使文件不能用于读写。它返回可能出现的错误。
func (f *File) Read 、 Write、WriteString 等
filepath 和 os 目录的操作:
os.Stat 获取文件相关信息
filepath 是 path包的二级包
filepath.IsAbs() 判断是不是绝对路径
filepath.Rel() 返回一个相对路径
filepath.Abs() 返回一个绝对路径
filepath.Join()
创建一个目录 os.Mkdir
建立多重目录:os.MkdirAll
os.Create()创建文件 返回指针
os.Open() 打开一个文件 只读
os.Remove(file) 删除空目录(只有此目录下没有文件时) 和 删除单文件
os.RemoveAll(file) 删除目录强制删除
文件操作实例:
1 package main 2 3 import ( 4 "fmt" 5 "path/filepath" 6 "path" 7 "os" 8 ) 9 10 func main() { 11 /* 12 文件操作: 13 1.路径: 14 相对路径:relative 15 ab.txt 16 相对于当前工程 17 绝对路径:absolute 18 /Users/ruby/Documents/pro/a/aa.txt 19 20 .当前目录 21 ..上一层 22 2.创建文件夹,如果文件夹存在,创建失败 23 os.MkDir(),创建一层 24 os.MkDirAll(),可以创建多层 25 26 3.创建文件,Create采用模式0666(任何人都可读写,不可执行)创建一个名为name的文件,如果文件已存在会截断它(为空文件) 27 os.Create(),创建文件 28 29 4.打开文件:让当前的程序,和指定的文件之间建立一个连接 30 os.Open(filename) 31 os.OpenFile(filename,mode,perm) 32 33 5.关闭文件:程序和文件之间的链接断开。 34 file.Close() 35 36 5.删除文件或目录:慎用,慎用,再慎用 37 os.Remove(),删除文件和空目录 38 os.RemoveAll(),删除所有 39 */ 40 //1.路径 41 fileName1:="/Users/ruby/Documents/pro/a/aa.txt" 42 fileName2:="bb.txt" 43 fmt.Println(filepath.IsAbs(fileName1)) //true 44 fmt.Println(filepath.IsAbs(fileName2)) //false 45 fmt.Println(filepath.Abs(fileName1)) 46 fmt.Println(filepath.Abs(fileName2)) // /Users/ruby/go/src/l_file/bb.txt 47 48 fmt.Println("获取父目录:",path.Join(fileName1,"..")) 49 50 //2.创建目录 51 //err := os.Mkdir("/Users/ruby/Documents/pro/a/bb",os.ModePerm) 52 //if err != nil{ 53 // fmt.Println("err:",err) 54 // return 55 //} 56 //fmt.Println("文件夹创建成功。。") 57 //err :=os.MkdirAll("/Users/ruby/Documents/pro/a/cc/dd/ee",os.ModePerm) 58 //if err != nil{ 59 // fmt.Println("err:",err) 60 // return 61 //} 62 //fmt.Println("多层文件夹创建成功") 63 64 //3.创建文件:Create采用模式0666(任何人都可读写,不可执行)创建一个名为name的文件,如果文件已存在会截断它(为空文件) 65 //file1,err :=os.Create("/Users/ruby/Documents/pro/a/ab.txt") 66 //if err != nil{ 67 // fmt.Println("err:",err) 68 // return 69 //} 70 //fmt.Println(file1) 71 72 //file2,err := os.Create(fileName2)//创建相对路径的文件,是以当前工程为参照的 73 //if err != nil{ 74 // fmt.Println("err :",err) 75 // return 76 //} 77 //fmt.Println(file2) 78 79 //4.打开文件: 80 //file3 ,err := os.Open(fileName1) //只读的 81 //if err != nil{ 82 // fmt.Println("err:",err) 83 // return 84 //} 85 //fmt.Println(file3) 86 /* 87 第一个参数:文件名称 88 第二个参数:文件的打开方式 89 const ( 90 // Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified. 91 O_RDONLY int = syscall.O_RDONLY // open the file read-only. 92 O_WRONLY int = syscall.O_WRONLY // open the file write-only. 93 O_RDWR int = syscall.O_RDWR // open the file read-write. 94 // The remaining values may be or'ed in to control behavior. 95 O_APPEND int = syscall.O_APPEND // append data to the file when writing. 96 O_CREATE int = syscall.O_CREAT // create a new file if none exists. 97 O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist. 98 O_SYNC int = syscall.O_SYNC // open for synchronous I/O. 99 O_TRUNC int = syscall.O_TRUNC // truncate regular writable file when opened. 100 ) 101 第三个参数:文件的权限:文件不存在创建文件,需要指定权限 102 */ 103 //file4,err := os.OpenFile(fileName1,os.O_RDONLY|os.O_WRONLY,os.ModePerm) 104 //if err != nil{ 105 // fmt.Println("err:",err) 106 // return 107 //} 108 //fmt.Println(file4) 109 110 //5关闭文件, 111 //file4.Close() 112 113 //6.删除文件或文件夹: 114 //删除文件 115 //err := os.Remove("/Users/ruby/Documents/pro/a/aa.txt") 116 //if err != nil{ 117 // fmt.Println("err:",err) 118 // return 119 //} 120 //fmt.Println("删除文件成功。。") 121 //删除目录 122 err := os.RemoveAll("/Users/ruby/Documents/pro/a/cc") 123 if err != nil{ 124 fmt.Println("err:",err) 125 return 126 } 127 fmt.Println("删除目录成功。。") 128 }
判断文件是否存在
Golang 判断文件或文件夹是否存在的方法为使用 os.Stat() 函数返回的错误值进行判断。
- 如果返回的错误为 nil,说明文件或文件夹存在
- 如果返回的错误类型使用 os.IsNotExist() 判断为 true,说明文件或文件夹不存在
package main
import (
"log"
"os"
)
func main() {
fileInfo,err:=os.Stat("/Users/ruby/Documents/pro/a/aa.txt")
if err!=nil{
if os.IsNotExist(err){
log.Fatalln("file does not exist")
}
}
log.Println("file does exist. file information:")
log.Println(fileInfo)
}
Golang 超大文件读取
func ReadBigFile(fileName string, handle func([]byte)) error {
f, err := os.Open(fileName)
if err != nil {
fmt.Println("can't opened this file")
return err
}
defer f.Close()
s := make([]byte, 4096)
for {
switch nr, err := f.Read(s[:]); true {
case nr < 0:
fmt.Fprintf(os.Stderr, "cat: error reading: %s\n", err.Error())
os.Exit(1)
case nr == 0: // EOF
return nil
case nr > 0:
handle(s[0:nr])
}
}
return nil
}
参考:
https://learnku.com/articles/23559/two-schemes-for-reading-golang-super-large-files
https://juejin.cn/post/6844904047212757005
https://juejin.cn/post/6864886461746855949
https://blog.csdn.net/weiyuefei/article/details/50186131?utm_source=blogxgwz4&utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-7
https://blog.csdn.net/weixin_39653200/article/details/84670687
https://blog.51cto.com/steed/2348936#h1

浙公网安备 33010602011771号