diff --git a/README.md b/README.md index 5386c4c..08c6e23 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ ## 翻译进度 -12.1 [读取用户的输入](eBook/12.1.md) +12.2 [文件读写](eBook/12.2.md) ## 支持本书 diff --git a/README_gc.md b/README_gc.md index 33aee06..27f6b2f 100644 --- a/README_gc.md +++ b/README_gc.md @@ -30,4 +30,4 @@ Golang 编程:245386165 |更新日期 |更新内容 |----------|------------------ -|2015-11-11|12.1 读取用户的输入 +|2015-11-12|12.2 文件读写 diff --git a/TOC.md b/TOC.md index db374a4..b1cb75d 100644 --- a/TOC.md +++ b/TOC.md @@ -106,3 +106,4 @@ - 第三部分:Go 高级编程 - 第12章:[读写数据](12.0.md) - 12.1 [读取用户的输入](12.1.md) + - 12.2 [文件读写](12.2.md) diff --git a/eBook/12.2.md b/eBook/12.2.md index b5c4322..7db9991 100644 --- a/eBook/12.2.md +++ b/eBook/12.2.md @@ -5,6 +5,7 @@ 在 Go 语言中,文件使用指向 `os.File` 类型的指针来表示的,也叫做文件句柄。我们在前面章节使用到过标准输入 `os.Stdin` 和标准输出 `os.Stdout`,他们的类型都是 `*os.File`。让我们来看看下面这个程序: 示例 12.4 [fileinput.go](examples/chapter_12/fileinput.go): + ```go package main import ( @@ -35,7 +36,7 @@ func main() { } ``` -变量 `inputFile` 是 `*os.File` 类型的。该类型是一个结构,表示一个打开文件的描述符(文件句柄)。然后,使用 `os` 包里的 `Open` 函数来打开一个文件。该函数的参数是文件名,类型为 `string`。在上面的程序中,我们以只读模式打开 input.dat 文件。 +变量 `inputFile` 是 `*os.File` 类型的。该类型是一个结构,表示一个打开文件的描述符(文件句柄)。然后,使用 `os` 包里的 `Open` 函数来打开一个文件。该函数的参数是文件名,类型为 `string`。在上面的程序中,我们以只读模式打开 `input.dat` 文件。 如果文件不存在或者程序没有足够的权限打开这个文件,Open函数会返回一个错误:`inputFile, inputError = os.Open("input.dat")`。如果文件打开正常,我们就使用 `defer.Close()` 语句确保在程序退出前关闭该文件。然后,我们使用 `bufio.NewReader` 来获得一个读取器变量。 @@ -54,6 +55,7 @@ func main() { 如果您想这么做,可以使用 `io/ioutil` 包里的 `ioutil.ReadFile()` 方法,该方法第一个返回值的类型是 `[]byte`,里面存放读取到的内容,第二个返回值是错误,如果没有错误发生,第二个返回值为 nil。请看示例 12.5。类似的,函数 `WriteFile()` 可以将 `[]byte` 的值写入文件。 示例 12.5 [read_write_file1.go](examples/chapter_12/read_write_file1.go): + ```go package main import ( @@ -81,12 +83,14 @@ func main() { **2) 带缓冲的读取** 在很多情况下,文件的内容是不按行划分的,或者干脆就是一个二进制文件。在这种情况下,`ReadString()`就无法使用了,我们可以使用 `bufio.Reader` 的 `Read()`,它只接收一个参数: + ```go buf := make([]byte, 1024) ... n, err := inputReader.Read(buf) if (n == 0) { break} ``` + 变量 n 的值表示读取到的字节数. **3) 按列读取文件中的数据** @@ -94,6 +98,7 @@ if (n == 0) { break} 如果数据是按列排列并用空格分隔的,你可以使用 `fmt` 包提供的以 FScan 开头的一系列函数来读取他们。请看以下程序,我们将 3 列的数据分别读入变量 v1、v2 和 v3 内,然后分别把他们添加到切片的尾部。 示例 12.6 [read_file2.go](examples/chapter_12/read_file2.go): + ```go package main import ( @@ -107,7 +112,7 @@ func main() { panic(err) } defer file.Close() - + var col1, col2, col3 []string for { var v1, v2, v3 string @@ -136,6 +141,7 @@ func main() { ``` **注意:** `path` 包里包含一个子包叫 `filepath`,这个子包提供了跨平台的函数,用于处理文件名和路径。例如 Base() 函数用于获得路径中的最后一个元素(不包含后面的分隔符): + ```go import "path/filepath" filename := filepath.Base(path) @@ -144,6 +150,7 @@ filename := filepath.Base(path) **练习 12.3**:[read_csv.go](exercises/chapter_12/read_csv.go) 文件 products.txt 的内容如下: + ``` "The ABC of Go";25.5;1500 "Functional Programming with Go";56;280 @@ -161,6 +168,7 @@ filename := filepath.Base(path) 下面的程序展示了如何读取一个 gzip 文件。 示例 12.7 [gzipped.go](examples/chapter_12/gzipped.go): + ```go package main @@ -203,6 +211,7 @@ func main() { 请看以下程序: 示例 12.8 [fileoutput.go](examples/chapter_12/fileoutput.go): + ```go package main @@ -226,7 +235,7 @@ func main () { outputWriter := bufio.NewWriter(outputFile) outputString := "hello world!\n" - + for i:=0; i<10; i++ { outputWriter.WriteString(outputString) } @@ -244,10 +253,10 @@ outputFile, outputError := os.OpenFile(“output.dat”, os.O_WRONLY|os.O_ CREAT 我们通常会用到以下标志: -`os.O_RDONLY`:只读 -`os.WRONLY`:只写 -`os.O_CREATE`:创建:如果指定文件不存在,就创建该文件。 -`os.O_TRUNC`:截断:如果指定文件已存在,就将该文件的长度截为0。 +- `os.O_RDONLY`:只读 +- `os.WRONLY`:只写 +- `os.O_CREATE`:创建:如果指定文件不存在,就创建该文件。 +- `os.O_TRUNC`:截断:如果指定文件已存在,就将该文件的长度截为0。 在读文件的时候,文件的权限是被忽略的,所以在使用 `OpenFile` 时传入的第三个参数可以用0。而在写文件时,不管是 Unix 还是 Windows,都需要使用 0666。 @@ -266,6 +275,7 @@ outputWriter := bufio.NewWriter(outputFile) 程序 `filewrite.go` 展示了不使用 `fmt.FPrintf` 函数,使用其他函数如何写文件: 示例 12.8 [filewrite.go](examples/chapter_12/filewrite.go): + ```go package main @@ -300,8 +310,7 @@ type Page struct { 请给这个结构编写一个 `save` 方法,将 Title 作为文件名、Body作为文件内容,写入到文本文件中。 -再编写一个 `load` 函数,接收的参数是字符串 title,该函数读取出与 title 对应的文本文件。请使用 *Page 做为参数,因为这个结构可能相当巨大,我们不想在内存中拷贝它。请使用 `ioutil` 包里的函数(参考章节12.2.1)。 - +再编写一个 `load` 函数,接收的参数是字符串 title,该函数读取出与 title 对应的文本文件。请使用 `*Page` 做为参数,因为这个结构可能相当巨大,我们不想在内存中拷贝它。请使用 `ioutil` 包里的函数(参考章节12.2.1)。 ## 链接