定制app开发GoLang之读取文件10种的方法

文章目录


一. 定制app开发整个文件读入内存

定制app开发直接将数据直接读取入内存,定制app开发是效率最高的一种方式,定制app开发但此种方式,定制app开发仅适用于小文件,定制app开发对于大文件,则不适合,因为比较浪费内存

1.直接指定文化名读取

在 Go 1.16 开始,ioutil.ReadFile 就等价于 os.ReadFile,二者是完全一致的

1.1使用os.ReadFile函数读取文件

package mainimport (    "fmt"    "os")func main() {   //func ReadFile(name string) ([]byte, error) {}    content, err := os.ReadFile("a.txt")    if err != nil {        panic(err)    }    fmt.Println(string(content))}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

1.2使用ioutil.ReadFile函数读取文件

package mainimport (    "io/ioutil"    "fmt")func main() {    content, err := ioutil.ReadFile("a.txt")    if err != nil {        panic(err)    }    fmt.Println(string(content))}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
// As of Go 1.16, this function simply calls os.ReadFile.func ReadFile(filename string) ([]byte, error) {    return os.ReadFile(filename)}
  • 1
  • 2
  • 3
  • 4

2.先创建句柄再读取

2.1使用os.OpenFile函数只读形式获取句柄

package mainimport ("os""io/ioutil""fmt")func main() {    /*func Open(name string) (*File, error) {	return OpenFile(name, O_RDONLY, 0)     }*/     //Open是一个高级函数,是因为它是只读模式来打开文件     /*也可以直接使用 os.OpenFile,只是要多加两个参数       file, err := os.OpenFile("a.txt", os.O_RDONLY, 0)*/    file, err := os.Open("a.txt")    if err != nil {        panic(err)    }    //func (f *File) Close() error {}    defer file.Close()    //func ReadAll(r io.Reader) ([]byte, error) {}    content, err := ioutil.ReadAll(file)    fmt.Println(string(content))}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

2.2代码讲解

2.2.1os.File结构体

type File struct {	*file // os specific}
  • 1
  • 2
  • 3

2.2.2os.OpenFile函数

func OpenFile(name string, flag int, perm FileMode) (    *File,   error) {}
  • 1
  • 2

2.2.3io.Reader接口

type Reader interface {	Read(p []byte) (n int, err error)}
  • 1
  • 2
  • 3

二.每次只读取一行

一次性读取所有的数据,太耗费内存,因此可以指定每次只读取一行数据,方法有三种:
(1)bufio.读行()
(2)bufio.读取字节("\")
(3)bufio.ReadString(’’)
在 bufio 的源码注释中,曾说道 bufio.ReadLine() 是低级库,不太适合普通用户使用,更推荐用户使用 bufio.ReadBytes和bufio.ReadString 去读取单行数据
因此,这里不再介绍 bufio.读行()

1.使用bufio.Reader结构体的ReadBytes方法读取字节数

ReadBytes读取直到第一次遇到delim字节,返回一个包含已读取的数据和delim字节的切片。如果ReadBytes方法在读取到delim之前遇到了错误,它会返回在错误之前读取的数据以及该错误(一般是io.EOF)。当且仅当ReadBytes方法返回的切片不以delim结尾时,会返回一个非nil的错误

package mainimport (    "bufio"    "fmt"    "io"    "os"    "strings")func main() {    // 创建句柄    fi, err := os.Open("christmas_apple.py")    if err != nil {        panic(err)    }    //func NewReader(rd io.Reader) *Reader {},返回的是bufio.Reader结构体    r := bufio.NewReader(fi)// 创建 Reader    for {    //func (b *Reader) ReadBytes(delim byte) ([]byte, error) {}        lineBytes, err := r.ReadBytes('')        //去掉字符串首尾空白字符,返回字符串        line := strings.TrimSpace(string(lineBytes))        if err != nil && err != io.EOF {            panic(err)        }        if err == io.EOF {            break        }        fmt.Println(line)    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

2.使用bufio.Reader结构体的ReadString方法读取字符串

ReadString读取直到第一次遇到delim字节,返回一个包含已读取的数据和delim字节的字符串。如果ReadString方法在读取到delim之前遇到了错误,它会返回在错误之前读取的数据以及该错误(一般是io.EOF)。当且仅当ReadString方法返回的切片不以delim结尾时,会返回一个非nil的错误

package mainimport (    "bufio"    "fmt"    "io"    "os"    "strings")func main() {    // 创建句柄    fi, err := os.Open("a.txt")    if err != nil {        panic(err)    }    // 创建 Reader    r := bufio.NewReader(fi)    for {    //func (b *Reader) ReadString(delim byte) (string, error) {}        line, err := r.ReadString('')        line = strings.TrimSpace(line)        if err != nil && err != io.EOF {            panic(err)        }        if err == io.EOF {            break        }        fmt.Println(line)    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

3.代码讲解

3.1bufio.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 // last byte read for UnreadByte; -1 means invalid	lastRuneSize int // size of last rune read for UnreadRune; -1 means invalid}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

三.每次只读取固定字节数

每次仅读取一行数据,可以解决内存占用过大的问题,但要注意的是,并不是所有的文件都有换行符 ;
因此对于一些不换行的大文件来说,还得再想想其他办法

1.使用os库

通用的做法是:
先创建一个文件句柄,可以使用 os.Open 或者 os.OpenFile;
然后 bufio.NewReader 创建一个 Reader;
然后在 for 循环里调用 Reader 的 Read 函数,每次仅读取固定字节数量的数据

Read方法读取数据写入p;本方法返回写入p的字节数;本方法一次调用最多会调用下层Reader接口一次Read方法,因此返回值n可能小于len§;读取到达结尾时,返回值n将为0而err将为io.EOF

package mainimport (    "bufio"    "fmt"    "io"    "os")func main() {    // 创建句柄    fi, err := os.Open("a.txt")    if err != nil {        panic(err)    }    // 创建 Reader    r := bufio.NewReader(fi)    // 每次读取 1024 个字节    buf := make([]byte, 1024)    for {        //func (b *Reader) Read(p []byte) (n int, err error) {}        n, err := r.Read(buf)        if err != nil && err != io.EOF {            panic(err)        }        if n == 0 {            break        }        fmt.Println(string(buf[:n]))    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

2.使用 syscall库

os 库本质上也是调用 syscall 库,但由于 syscall 过于底层,如非特殊需要,一般不会使用 syscall;
本篇为了内容的完整度,这里也使用 syscall 来举个例子;
本例中,会每次读取 100 字节的数据,并发送到通道中,由另外一个协程进行读取并打印出来

package mainimport (    "fmt"    "sync"    "syscall")func main() {    fd, err := syscall.Open("christmas_apple.py", syscall.O_RDONLY, 0)    if err != nil {        fmt.Println("Failed on open: ", err)    }    defer syscall.Close(fd)    var wg sync.WaitGroup    wg.Add(2)    dataChan := make(chan []byte)    go func() {        wg.Done()        for {            data := make([]byte, 100)            n, _ := syscall.Read(fd, data)            if n == 0 {                break            }            dataChan <- data        }        close(dataChan)    }()    go func() {        defer wg.Done()        for {            select {            case data, ok := <-dataChan:                if !ok {                    return                }                fmt.Printf(string(data))            default:            }        }    }()    wg.Wait()}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发