读取整个文件
- 整个文件读取到内存是最基本的文件操作之一。这需要使用
ioutil
包中的ReadFile
函数。
package main
import (
"flag"
"fmt"
"io/ioutil"
)
func main() {
fptr := flag.String("path", "test.txt", "待读取文件的路径")
flag.Parse()
data, err := ioutil.ReadFile(*fptr)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(data))
}
- 以上使用的是运行时指定参数
-path=test1.txt
来指定读取的文件,也可以使用文件的绝对路径。
分块读取文件
- 当文件非常大时,尤其在内存不足的情况下,把整个文件都读入内存是没有意义的。
- 更好的方法是分块读取文件。这可以使用
bufio
包来完成。 - 利用
bufio
包的'NewReader()'函数实现,其中Read
方法可以读取文件内容到缓冲的字节数组中去。
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main() {
// 打开文件
f, err := os.Open("test.txt")
if err != nil {
fmt.Println(err)
}
// 延迟关闭文件
defer func() {
if err := f.Close(); err != nil {
fmt.Println(err)
}
}()
// 文件读取器
r := bufio.NewReader(f)
buf := make([]byte, 3) // 便于演示 设置的比较小
str := ""
for {
_, err := r.Read(buf)
if err != nil {
if err == io.EOF {
fmt.Println("文件读取完毕!")
} else {
fmt.Println(err)
}
break
}
fmt.Println(string(buf))
str += string(buf)
}
fmt.Println("完整结果如下:\n", str)
}
逐行读取文件
- 当文件比较大时还可以采用逐行读取的方式实现。
- 利用
bufio
包的'NewScanner()'函数实现,其中Scan
方法可以判断是否还有下一行,
Text
方法可以获取当前行,Err
方法可以获取错误信息。
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
// 打开文件
f, err := os.Open("test.txt")
if err != nil {
fmt.Println(err)
}
// 延迟关闭文件
defer func() {
if err := f.Close(); err != nil {
fmt.Println(err)
}
}()
// 文件读取器
s := bufio.NewScanner(f)
str := ""
for s.Scan() {
fmt.Println(s.Text(), "\n-------分隔符--------")
str += s.Text()
}
if s.Err() != nil {
fmt.Println(s.Err().Error())
}
fmt.Println("完整结果如下:\n", str)
}
字符串写入文件
- 使用 create 创建一个指定名字的文件。
如果这个文件已经存在,那么 create 函数将截断这个文件。该函数返回一个文件描述符。
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Create("123.txt")
if err != nil {
fmt.Println(err)
}
defer func() {
if err = f.Close(); err != nil {
fmt.Println(err)
}
}()
_, err = f.WriteString("Hello World!")
if err != nil {
fmt.Println(err)
}
fmt.Println("文件写入成功!")
}
字节写入文件
- 使用
Write
方法可以写入字节数组数据。一般为字符对应的UTF-8的10进制编码。
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Create("123.txt")
if err != nil {
fmt.Println(err)
}
defer func() {
if err = f.Close(); err != nil {
fmt.Println(err)
}
}()
bytes := []byte{104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100}
_, err = f.Write(bytes)
if err != nil {
fmt.Println(err)
}
fmt.Println("文件写入完成")
}
逐行写入文件
- 使用
fmt.Fprintln
函数实现文件的逐行写入。
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Create("123.txt")
if err != nil {
fmt.Println(err)
}
defer func() {
if err = f.Close(); err != nil {
fmt.Println(err)
}
}()
lines := []string{"Hello", "GoLang", "World"}
for _, v := range lines {
_, err = fmt.Fprintln(f, v)
if err != nil {
fmt.Println(err)
}
}
fmt.Println("文件写入完成.")
}
追加文件内容
os.OpenFile(name string, flag int, perm FileMode) (*File, error)
函数可以指定文件操作方式。
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.OpenFile("123.txt", os.O_APPEND|os.O_RDONLY, 0644)
if err != nil {
fmt.Println(err)
}
defer func() {
if err = f.Close(); err != nil {
fmt.Println(err)
}
}()
lines := []string{"123", "abc", "!@#"}
for _, v := range lines {
_, err = fmt.Fprintln(f, v)
if err != nil {
fmt.Println(err)
}
}
fmt.Println("文件追加写入完成.")
}
并发写文件
- 注意文件写入时的竞态条件。
package main
import (
"fmt"
"math/rand"
"os"
"sync"
)
func main() {
chNum := make(chan int)
chExit := make(chan bool)
wg := sync.WaitGroup{}
// 生产者
for i := 0; i < 100; i++ {
wg.Add(1)
go makeRandom(chNum, &wg)
}
// 消费者
go writeFile(chNum, chExit)
wg.Wait()
close(chNum)
if <-chExit {
fmt.Println("文件写入成功.")
} else {
fmt.Println("文件写入失败.")
}
}
func makeRandom(chNum chan int, wg *sync.WaitGroup) {
chNum <- rand.Intn(1000)
wg.Done()
}
func writeFile(chNum chan int, chExit chan bool) {
f, err := os.Create("123.txt")
if err != nil {
fmt.Println(err)
}
defer func() {
if err = f.Close(); err != nil {
fmt.Println(err)
}
}()
for val := range chNum {
_, err = fmt.Fprintln(f, val)
if err != nil {
fmt.Println(err)
}
}
chExit <- true
}