谈谈对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 }
View Code

向 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 }
View Code

转自: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 }
View Code

判断文件是否存在

Golang 判断文件或文件夹是否存在的方法为使用 os.Stat() 函数返回的错误值进行判断。

  1. 如果返回的错误为 nil,说明文件或文件夹存在
  2. 如果返回的错误类型使用 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

https://www.jianshu.com/p/779cdb86999f

posted @ 2021-01-20 14:49  故穿庭树作飞花  阅读(933)  评论(0)    收藏  举报