sunwenfei
  • 关于我
  • Golang
    • Goglang基础教程【译】
      • 介绍
        • 安装
        • Hello World
      • 变量、基本类型以及常量
        • 变量
        • 基本类型
        • 常量
      • 函数和包
        • 函数
        • 包
      • 条件、循环流程控制语句
        • if else条件语句
        • switch语句
        • 循环语句
      • 数组、切片、变参函数
        • 数组(Array)
        • 切片(Slice)
        • 变参函数
      • 其他数据类型
        • 映射(Map)
        • 字符串
      • 指针、结构体和方法
        • 指针
        • 结构体
        • 方法
      • 面向对象编程
        • 结构体 vs 类
        • 组合 vs 继承
        • 接口
        • 多态
      • 并发
        • 并发介绍
        • 协程(goroutine)
        • 管道(channel)
        • 带缓存的管道(buffered channel)
        • 协程池
        • 管道选择器(select)
        • 互斥锁(Mutex)
      • Defer
      • 一等公民函数
      • 反射
      • 错误
        • 错误处理
        • 自定义错误类型
        • panic和recover
      • 文件读写
        • 读文件
        • 写文件
    • Golang面向对象编程
    • Golang函数式编程
    • Golang并发编程
    • Golang web服务编程
    • Golang数据结构与算法
  • Shell编程
    • Find命令
  • JavaScript
    • browser
    • Node.JS
    • Deno
  • TypeScript
  • HTTP
    • 【译】通过信鸽理解HTTPS交互原理
  • React
    • React16
      • Hooks
        • 使用React Hooks拉取数据
  • 移动端开发
    • 原生
    • Flutter
    • ReactNative
    • 小程序
  • 前端测试
Powered by GitBook
On this page

Was this helpful?

  1. Golang
  2. Goglang基础教程【译】
  3. 文件读写

写文件

写入字符串

经常会遇到向文件中写入字符串的需求,实现起来很简单,包括如下两步:

  1. 创建文件

  2. 将字符串写入创建的文件

package main

import (
    "fmt"
    "os"
)

func main() {
    f, err := os.Create("test.txt")
    if err != nil {
        fmt.Println(err)
        return
    }
    l, err := f.WriteString("Hello World 你好 世界")
    if err != nil {
        fmt.Println(err)
        f.Close()
        return
    }
    fmt.Println(l, "bytes written successfully")
    err = f.Close()
    if err != nil {
        fmt.Println(err)
        return
    }
}

通过os.Create函数,创建了文件test.txt,该函数返回了创建的文件的文件描述符。注意,如果要创建的文件名称已存在,存在的文件会被删除。我们通过WriteString方法向文件中写入了字符串Hello World 你好 世界,该方法返回写入的字符串的字节数。最后注意通过f.Close()关闭文件。该程序执行输出:

25 bytes written successfully

同时生成一个文件test.txt,包含文本Hello World 你好 世界。

写入字节

向文件中写入字节跟写入字符串类似。使用Write方法即可。下面的程序将一个切片的字节写入到文件中。

package main

import (
    "fmt"
    "os"
)

func main() {
    f, err := os.Create("bytes.txt")
    if err != nil {
        fmt.Println(err)
        return
    }
    d2 := []byte{104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100}
    n2, err := f.Write(d2)
    if err != nil {
        fmt.Println(err)
        f.Close()
        return
    }
    fmt.Println(n2, "bytes written successfully")
    err = f.Close()
    if err != nil {
        fmt.Println(err)
        return
    }
}

这里我们打开文件后,通过Write方法将一个切片的字节写入文件。该程序执行输出:

11 bytes written successfully

同时创建了文件bytes.txt,包含文本hello world。

按行写入字符串

下面我们将如下几行字符串按行写入文件。

Welcome to the world of Go.
Go is a compiled language.
It is easy to learn Go.
package main

import (
    "fmt"
    "os"
)

func main() {
    f, err := os.Create("lines.txt")
    if err != nil {
        fmt.Println(err)
        f.Close()
        return
    }
    d := []string{"Welcome to the world of Go1.", "Go is a compiled language.", "It is easy to learn Go."}

    for _, v := range d {
        fmt.Fprintln(f, v)
        if err != nil {
            fmt.Println(err)
            return
        }
    }
    err = f.Close()
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println("file written successfully")
}

这里我们还是通过os.Create()来创建了一个文件。接着通过Fprintln函数将一行一行的字符串写入到了文件中。最后关闭了文件。该程序执行输出:

file written successfully

同时创建了文件lines.txt,包含了三行文本。

追加写入字符串

下面我们将下面这行文本追加写入到前面创建的文件lines.txt中。

File handling is easy

要追加写入一个文件,该文件必须以追加模式打开。OpenFile函数的参数可配置以哪种模式打开文件。

package main

import (
    "fmt"
    "os"
)

func main() {
    f, err := os.OpenFile("lines.txt", os.O_APPEND|os.O_WRONLY, 0644)
    if err != nil {
        fmt.Println(err)
        return
    }
    newLine := "File handling is easy."
    _, err = fmt.Fprintln(f, newLine)
    if err != nil {
        fmt.Println(err)
        f.Close()
        return
    }
    err = f.Close()
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println("file appended successfully")
}

这里我们给函数OpenFile传入了os.O_APPEND|os.O_WRONLY表示追加+仅写模式。该程序执行输出:

file appended successfully

同时在文件lines.txt最后追加了一行文本File handling is easy.。

并发写文件

如果多个goroutine并发的向同一个文件写入,会出现竞态问题。这种情况下我们需要通过channel,来将所有goroutine要写入的数据做一个顺序化,跟排队类似。这本质上其实也是生产消费模型。

下面我们创建100个goroutine,在每个goroutine中并发的生成一个随机数,然后放入到channel中。在channel的接收端会收到来自各个goroutine要写入的数据,然后依次无冲突的写入到文件中。

package main

import (
    "fmt"
    "math/rand"
    "os"
    "sync"
)

func produce(data chan int, wg *sync.WaitGroup) {
    n := rand.Intn(999)
    data <- n
    wg.Done()
}

func consume(data chan int, done chan bool) {
    f, err := os.Create("concurrent.txt")
    if err != nil {
        fmt.Println(err)
        return
    }
    for d := range data {
        _, err = fmt.Fprintln(f, d)
        if err != nil {
            fmt.Println(err)
            f.Close()
            done <- false
            return
        }
    }
    err = f.Close()
    if err != nil {
        fmt.Println(err)
        done <- false
        return
    }
    done <- true
}

func main() {
    data := make(chan int)
    done := make(chan bool)
    wg := sync.WaitGroup{}
    for i := 0; i < 100; i++ {
        wg.Add(1)
        go produce(data, &wg)
    }
    go consume(data, done)
    go func() {
        wg.Wait()
        close(data)
    }()
    d := <-done
    if d == true {
        fmt.Println("File written successfully")
    } else {
        fmt.Println("File writing failed")
    }
}

这里的核心思想就是生产、消费模型,produce协程函数用来生产数据,consume协程用来消费数据。这里我们通过wg.Wait()在所有生产者完成生产后调用close关闭了channel。同时我们在consume协程中不断读取channel中的数据,直到channel被关闭。consume协程完成按序写后调用f.Close()关闭了文件。该程序执行输出为:

File written successfully

同时创建了文件concurrent.txt,包含100行随机数字。

Previous读文件NextGolang面向对象编程

Last updated 5 years ago

Was this helpful?