go 文件处理 07
fmt
fmt包实现了类似C语言printf和scanf的格式化I/O。主要分为向外输出内容和获取输入内容两大部分。
Print系列函数会将内容输出到系统的标准输出,区别在于Print函数直接输出内容,Printf函数支持格式化输出字符串,Println函数会在输出内容的结尾添加一个换行符
在go中提供了 print、println 用于打印信息,而go本身也提供了一个fmt标准的输出对象位于 go\src\fmt\print.go
func Print(a ...interface{}) (n int, err error)
func Printf(format string, a ...interface{}) (n int, err error)
func Println(a ...interface{}) (n int, err error)
Printf占位符
通用占位符
占位符 | 说明 |
---|---|
%v | 值的默认格式表示 |
%+v | 类似%v,但输出结构体时会添加字段名 |
%#v | 值的Go语法表示 |
%T | 打印值的类型 |
%% | 百分号 |
布尔型
占位符 | 说明 |
---|---|
%t | true或false |
整型
占位符 | 说明 |
---|---|
%b | 表示二进制 |
%c | 该值对应的unicode编码 |
%d | 表示为十进制 |
%o | 表示为八进制 |
%x | 表示为十六进制,使用a-f |
%X | 表示为十六进制,使用A-F |
%U | 表示为Unicode格式,U+1234,等价于“U+%o4X” |
%q | 该值对应的单引号括起来的go语法字符串面值,必要时会采用安全的转义表示 |
浮点数与复数
占位符 | 说明 |
---|---|
%b | 无小数部分、二进制指数的科学计数法,如-123456p-78 |
%e | 科学计数法,如-1234.456e+78 |
%E | 科学计数法,如-1234.456E+78 |
%f | 有小数部分但无指数部分,如123.456 |
%F | 等价于%f |
%g | 根据实际情况采用%e或%f格式(以获得更简洁、精确的输出) |
%G | 根据实际情况采用%E或%F格式(以获得更简洁、精确的输出) |
字符串和[]byte
占位符 | 说明 |
---|---|
%s | 直接输出字符串或者[]byte |
%q | 该值对应的双引号括起来的go语法字符串面值,必要时会采用安全的转义表示 |
%x | 每个字节用两字符十六进制数表示(用a-f) |
% X | 每个字节用两字符十六进制数表示(用A-F) |
指针
占位符 | 说明 |
---|---|
%p | 表示为十六进制,并加上前导的ox |
%f | 默认宽度,默认精度 |
%9f | 宽度9,默认精度 |
%.2f | 默认宽度,精度2 |
%9.2f | 宽度9,精度2 |
%9.f | 宽度9,精度0 |
其他falg
占位符 | 说明 |
---|
Printf
Fprint系列函数会将内容输出到一个io.Writer接口类型的变量w中,我们通常用这个函数往文件中写入内容。
func Fprint(w io.Writer, a ...interface{}) (n int, err error)
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)
func Fprintln(w io.Writer, a ...interface{}) (n int, err error)
栗子:
// 向标准输出写入内容
fmt.Fprintln(os.Stdout, "向标准输出写入内容")
fileObj, err := os.OpenFile("D:\\phpStudy\\PHPTutorial\\WWW\\go\\src\\shineyork\\07\\xx.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
fmt.Println("打开文件出错,err:", err)
return
}
name := "shineyork"
// 向打开的文件句柄中写入内容
fmt.Fprintf(fileObj, "往文件中写如信息:%s", name)
Sprint
Sprint系列函数会把传入的数据生成并返回一个字符串
func Sprint(a ...interface{}) string
func Sprintf(format string, a ...interface{}) string
func Sprintln(a ...interface{}) string
简单的示例代码如下:
s1 := fmt.Sprint("shineyork")
name := "shineyork"
age := 18
s2 := fmt.Sprintf("name:%s,age:%d", name, age)
s3 := fmt.Sprintln("shineyork")
fmt.Println(s1, s2, s3)
获取输入
Go语言fmt包下有fmt.Scan、fmt.Scanf、fmt.Scanln三个函数,可以在程序运行过程中从标准输入获取用户的输入
fmt.Scan
函数定签名如下:
func Scan(a ...interface{}) (n int, err error)
- Scan从标准输入扫描文本,读取由空白符分隔的值保存到传递给本函数的参数中,换行符视为空白符。
- 本函数返回成功扫描的数据个数和遇到的任何错误。如果读取的数据个数比提供的参数少,会返回一个错误报告原因。
栗子:
var (
name string
age int
married bool
)
fmt.Println("请输入name:")
fmt.Scan(&name)
fmt.Println("请输入age:")
fmt.Scan(&age)
fmt.Println("请输入married:")
fmt.Scan(&married)
fmt.Printf("扫描结果 name:%s age:%d married:%t \n", name, age, married)
请输入name:
hah
请输入age:
12
请输入married:
555
扫描结果 name:hah age:12 married:false
数据格式
数据结构要在网络中传输或保存到文件,就必须对其编码和解码;目前存在很多编码格式:JSON,XML,gob,Google 缓冲协议等等
结构可能包含二进制数据,如果将其作为文本打印,那么可读性是很差的。另外结构内部可能包含匿名字段,而不清楚数据的用意
通过把数据转换成纯文本,使用命名的字段来标注,让其具有可读性。这样的数据格式可以通过网络传输,而且是与平台无关的,任何类型的应用都能够读取和输出,不与操作系统和编程语言的类型相关
下面是一些术语说明:
- 数据结构 → 指定格式 = 序列化 或 编码(传输之前)
- 指定格式 → 数据格式 = 反序列化 或 解码(传输之后)
json
json & type
序列化是在内存中把数据转换成指定格式(data -> string),反之亦然(string -> data structure)
{
"Person": {
"class": "go-class",
"name": "shineyork"
}
}
- json使用go语言内置的encoding/json 标准库
- 编码json使用json.Marshal()函数可以对一组数据进行JSON格式的编码
func Marshal(v interface{}) ([]byte, error)
示例过结构体生成json
package main
import (
"encoding/json"
"fmt"
"os"
)
type Person struct {
Name string
Age int
Address []*Address
}
type Address struct {
Type string
City string
Country string
}
func main() {
a1 := &Address{"a1", "北京", "中国"}
a2 := &Address{"a2", "长沙", "中国"}
p := Person{"shineyork", 18, []*Address{a1, a2}}
// 编码json
b, _ := json.Marshal(p)
fmt.Println(string(b))
// 格式输出
b, _ = json.MarshalIndent(p, "", " ")
fmt.Println(string(b))
// 写入文件中
file, _ := os.OpenFile("D:\\phpstudy_pro\\WWW\\fans\\person.json", os.O_CREATE|os.O_WRONLY, 0666)
defer file.Close()
enc := json.NewEncoder(file)
enc.Encode(p)
}
{"Name":"shineyork","Age":18,"Address":[{"Type":"a1","City":"北京","Country":"中国"},{"Type":"a2","City":"长沙","Country":"中国"}]}
{
"Name": "shineyork",
"Age": 18,
"Address": [
{
"Type": "a1",
"City": "北京",
"Country": "中国"
},
{
"Type": "a2",
"City": "长沙",
"Country": "中国"
}
]
}
json 转 type
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Address []*Address `json:"Address"`
}
type Address struct {
Type string
City string
Country string
}
func main() {
// array - json => type
b := []byte(`{"Name":"shineyork","Age":18,"Address":[{"Type":"a1","City":"北京","Country":"中国"},{"Type":"a2","City":"长
沙","Country":"中国"}]}`)
var p Person
json.Unmarshal(b, &p)
fmt.Printf("%#v\n", p)
}
main.Person{Name:"", Age:0, Address:[]*main.Address(nil)}
结构体标签(Tag)
Tag是结构体的元信息,可以在运行的时候通过反射的机制读取出来。
Tag在结构体字段的后方定义,由一对反引号包裹起来,具体的格式如下:
`key1:"value1" key2:"value2"`
结构体标签由一个或多个键值对组成。键与值使用冒号分隔,值用双引号括起来。键值对之间使用一个空格分隔。 注意事项: 为结构体编写Tag时,必须严格遵守键值对的规则。结构体标签的解析代码的容错能力很差,一旦格式写错,编译和运行时都不会提示任何错误,通过反射也无法正确取值。例如不要在key和value之间添加空格。
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Address []*Address
}
type Address struct {
Type string
City string
Country string
}
func main() {
// array - json => type
b := []byte(`{"Name":"shineyork","Age":18,"Address":[{"Type":"a1","City":"北京","Country":"中国"},{"Type":"a2","City":"长
沙","Country":"中国"}]}`)
var p Person
json.Unmarshal(b, &p)
fmt.Printf("%#v\n", p)
}
main.Person{Name:"", Age:0, Address:[]*main.Address(nil)}
示例解析到interface
// array - json => type
b := []byte(`{"Name":"shineyork","Age":18,"Address":[{"Type":"a1","City":"北京","Country":"中国"},{"Type":"a2","City":"长沙","Country":"中
国"}]}`)
var i interface{}
json.Unmarshal(b, &i)
// 可以判断类型
m := i.(map[string]interface{})
for k, v := range m {
switch vv := v.(type) {
case float64:
fmt.Println(k, "是float64类型", vv)
case string:
fmt.Println(k, "是string类型", vv)
default:
fmt.Println(k, "其他", vv)
}
}
json & map
// map => json
s := make(map[string]interface{})
s["name"] = "shineyork"
s["age"] = 18
s["sex"] = "man"
js, _ := json.Marshal(s)
fmt.Println(string(js))
xml
- 是可扩展标记语言,包含声明、根标签、子元素和属性
- 应用场景:配置文件以及webService
<Person>
<FirstName>Laura</FirstName>
<LastName>Lynn</LastName>
</Person>
如同 json 包一样,也有 Marshal() 和 UnMarshal() 从 XML 中编码和解码数据;但这个更通用,可以从文件中读取和写入(或者任何实现了 io.Reader 和 io.Writer 接口的类型)
和 JSON 的方式一样,XML 数据可以序列化为结构,或者从结构反序列化为 XML 数据;这些可以在例子 15.8(twitter_status.go)中看到。
encoding/xml 包实现了一个简单的 XML 解析器(SAX),用来解析 XML 数据内容。下面的例子说明如何使用解析器
package main
import (
"encoding/xml"
"fmt"
"io/ioutil"
)
// 抽取单个server对象
type Server struct {
ServerName string `xml:"serverName"`
ServerIP string `xml:"serverIP"`
}
type Servers struct {
Name xml.Name `xml:"servers"`
Version int `xml:"version"`
Servers []Server `xml:"server"`
}
func main() {
data, err := ioutil.ReadFile("D:/my.xml")
对应的xml内容
<?xml version="1.0" encoding="UTF-8" ?>
<servers version="1">
<server>
<serverName>Shanghai_VPN</serverName>
<serverIP>127.0.0.1</serverIP>
</server>
<server>
<serverName>Beijing_VPN</serverName>
<serverIP>127.0.0.2</serverIP>
</server>
</servers>
使用gob传输数据
Gob 是 Go 自己的以二进制形式序列化和反序列化程序数据的格式;可以在 encoding 包中找到。这种格式的数据简称为 Gob (即 Go binary 的缩写)。类似于Python 的 “pickle” 和 Java 的 “Serialization”
Gob 通常用于远程方法调用参数和结果的传输,以及应用程序和机器之间的数据传输。 它和 JSON 或 XML 有什么不同呢?Gob 特定地用于纯 Go 的环境中,例如,两个用 Go 写的服务之间的通信。这样的话服务可以被实现得更加高效和优化。 Gob 不是可外部定义,语言无关的编码方式。因此它的首选格式是二进制,而不是像 JSON 和 XML 那样的文本格式。 Gob 并不是一种不同于 Go 的语言,而是在编码和解码过程中用到了 Go 的反射。
package main
import (
"bytes"
"encoding/gob"
"fmt"
"log"
)
type P struct {
X, Y, Z int
Name string
}
type Q struct {
X, Y *int32
Name string
}
func main() {
gobPQ()
}
func gobPQ() {
// Initialize the encoder and decoder. Normally enc and dec would be
// bound to network connections and the encoder and decoder would
// run in different processes.
var network bytes.Buffer // Stand-in for a network connection
enc := gob.NewEncoder(&network) // Will write to network.
dec := gob.NewDecoder(&network) // Will read from network.
// Encode (send) the value.
err := enc.Encode(P{3, 4, 5, "Pythagoras"})
if err != nil {
log.Fatal("encode error:", err)
}
// Decode (receive) the value.
var q Q
err = dec.Decode(&q)
if err != nil {
log.Fatal("decode error:", err)
}
fmt.Printf("%q: {%d,%d}\n", q.Name, *q.X, *q.Y)
}
encode/decode 接口类型的值是如何操作的。与其他常规的类型(比如结构体)最大的不同在于:需要注册一个明确的实现该接口的类型
package main
import (
"bytes"
"encoding/gob"
"fmt"
"log"
"math"
)
type Point struct {
X, Y int
}
func (p Point) Hypotenuse() float64 {
// Hypot returns Sqrt(p*p + q*q)
return math.Hypot(float64(p.X), float64(p.Y))
}
type Pythagoras interface {
Hypotenuse() float64
}
func main() {
GobInterface()
}
// 这个例子展示了如何 encode/decode 一个接口类型(interface{})的值
// 与其他常规的类型(比如结构体)最大的不同在于:
// 需要注册一个明确的实现该接口的类型
func GobInterface() {
// 我们必须要对encoder和decoder注册具体的类型,
// 因为通常来说,decoder和encoder是在不同的机器上的。
// 经过“注册”,解析引擎才能知道实现这一接口的具体类型是什么
// (因为同一个接口可以有多种不同的实现)
gob.Register(Point{})
p1 := Point{X: 3, Y: 4}
fmt.Println(p1.Hypotenuse()) // 5
// 编码,再解码,观察解码后返回的结果是否一致
b, _ := encode(p1)
p2, _ := decode(b)
fmt.Println(p2.Hypotenuse()) // 5
}
// 编码,把结构体数据编码成字节流数据
func encode(p Pythagoras) ([]byte, error) {
var buf bytes.Buffer
encoder := gob.NewEncoder(&buf) // 构造编码器,并把数据写进buf中
if err := encoder.Encode(&p); err != nil {
log.Printf("encode error: %v\n", err)
return nil, err
}
return buf.Bytes(), nil
}
// 解码,把字节流数据解析成结构体数据
func decode(b []byte) (Pythagoras, error) {
//var buf bytes.Buffer
bufPtr := bytes.NewBuffer(b) // 返回的类型是 *Buffer,而不是 Buffer。注意一下
decoder := gob.NewDecoder(bufPtr) // 从 bufPtr 中获取数据
var p Pythagoras
if err := decoder.Decode(&p); err != nil { // 将数据写进变量 p 中
return Point{}, err
}
return p, nil
}
使用buffer读取文件
go在提供了io包的同时也提供了bufio包来实现有缓存的读写操作以提高读写性能。为什么bufio性能比io 高呢?
go-bugio
缓冲读
//默认缓冲区大小
const (
defaultBufsize = 4096
)
//最小缓冲区大小自定义小于次阈值将会被覆盖
const minReadBuffersize = 16
//使用默认缓冲区大小
bufio . NewReader(rd io. Reader)
//使用自定义缓冲区大小
bufio. NewReaderSize(rd io. Reader, size int)
缓冲读的大致过程如下,设定好缓冲区大小buf_ size后, 读取的字节数为rn,缓冲的字节数为bn:
- 如果缓冲区为空,且rn >= buf_ size, 则直接从文件读取,不启用缓冲。
- 如果缓冲区为空,且rn < buf_ size,则从文件读取buf_ size字节的内容到缓冲区,程序再从缓冲区中读取rn字节的内容,此时缓冲区剩余bn = buf_ size ? - rn字节。
- 如果缓冲区不为空, rn < bn, 则从缓冲区读取rn字节的内容,不发生文件I0。
- 如果缓冲区不为空, rn >= bn,则从缓冲区读取bn字节的内容,不发生文件Io,缓冲区置为空,回归1/2步骤。
代码:
package main
import (
"bufio"
"fmt"
"strings"
)
func main() {
read()
}
func read() {
//用strings. Reader 模拟一个 文件I0对象
strReader := strings.NewReader("12345678901234567890123456789012345678901234567890")
// go的缓冲区最小为16 byte, 我们用最小值比较容易演示
bufReader := bufio.NewReaderSize(strReader, 16)
// bn= 0但rn >= buf_ size 缓冲区不启用发生文件I0
tmpStr := make([]byte, 16)
n, _ := bufReader.Read(tmpStr)
// bufReader buffered: 0, content: 1234567890123456
fmt.Printf("bufReader buffered: %d, content:%s\n", bufReader.Buffered(), tmpStr[:n])
//bn=0 rn < buf_size缓冲区启用
// 缓冲区从文件读取 buf_size 字节发生文件I0
// 程序从缓冲区读取 rn字节
//缓冲区剩余bn=buf_size一rn字节
tmpStr = make([]byte, 15)
n, _ = bufReader.Read(tmpStr)
// bufReader buffered: 1, content:789012345678901
fmt.Printf("bufReader buffered: %d, content: %s\n", bufReader.Buffered(), tmpStr[:n])
// bn=1 rn>bn
// 程序从缓冲区读取 bn字节缓冲区置空 不发生文件I0
//注意这里只能读到一个字节
tmpStr = make([]byte, 10)
n, _ = bufReader.Read(tmpStr)
// bufReader buffered: 0, content: 2
fmt.Printf("bufReader buffered: %d, content: %s\n", bufReader.Buffered(), tmpStr[:n])
// bn = 0 rn < buf_ size 启用缓冲读发生文件I0
// 缓冲区从文件读取 buf_ size 字节
// 程序从缓冲区读取 rn字节
//缓冲区剩余bn=buf_size一rn字节
tmpStr = make([]byte, 10)
n, _ = bufReader.Read(tmpStr)
fmt.Printf("bufReader buffered: %d, content: %s\n", bufReader.Buffered(), tmpStr[:n])
//bn=6 rn<=bn
//则程序冲缓冲区读取rn字节不发生文件I0
tmpStr = make([]byte, 3)
n, _ = bufReader.Read(tmpStr)
fmt.Printf("bufReader buffered: %d, content: %s\n", bufReader.Buffered(), tmpStr[:n])
//bn=3rn<=bn
//则程序冲缓冲区读取rn字节不发生文件I0
tmpStr = make([]byte, 3)
n, _ = bufReader.Read(tmpStr)
// bufReader buffered: 0, content: 678
fmt.Printf("bufReader buffered: %d, content: %s\n", bufReader.Buffered(), tmpStr[:n])
}
要注意的是当缓冲区中有内容时,程序的此次读取都会从缓冲区读,而不会发生文件I0。只有当缓冲区 为空时,才会发生文件I0。如果缓冲区的大小足够,则启用缓冲读,先将内容载入填满缓冲区,程博 从缓冲区中读取。如果缓冲区过小,则会直接从文件读取,而不使用缓冲读。
缓冲写
//使用defaultBufsize大小
func NewWriter(W io. Writer)
//如果size <= 0则使用 defaul tBufsize
func NewWritersize(W io.writer, size int)
缓冲写的大致过程如下,设定好缓冲区大小buf_size后,写入的字节数为wn,缓冲的字节数为bn:
- 如果缓冲区为空,且wn >= buf_size, 则直接写入文件,不启用缓冲,发生文件I0。
- 如果缓冲区为空,且wn < buf_size, 则程序将内容写入缓中区,不发生文件IO。
- 如果缓冲区不为空, wn + bn < buf_ size, 则程序将内容写入缓冲区,不发生文件IO。
- 如果缓冲区不为空, wn + bn >= buf_ size, 则缓冲区将buf_ size字节内容写入文件,缓冲区wn + bn - buf_ size的剩余内容。
简单说就是要写入的内容先缓冲着,缓冲不下了则将缓冲区内容写入文件。
代码
package main
import (
"bufio"
"fmt"
"io"
"strings"
)
//自定义一个io.writer 对象
type StringWriter struct{}
func (s StringWriter) Write(p []byte) (n int, err error) {
fmt.Printf("io write: %s\n", p)
return len(p), nil
}
func main() {
write()
}
func write() {
strReader := strings.NewReader("12345678901234567890")
bufReader := bufio.NewReader(strReader)
//自定义的 io.Writer对象
var stringwriter io.Writer
stringwriter = StringWriter{}
// 写缓冲大小为6为了更好的演示我们自定义了- .个io. writer
// bufwriter := bufio.Newritersize(stringWriter, 6)
bufWriter := bufio.NewWriterSize(stringwriter, 6)
tmpstr := make([]byte, 8)
for true {
rn, err := bufReader.Read(tmpstr)
if nil != err && io.EOF == err {
break
}
_, err = bufWriter.Write(tmpstr[:rn])
fmt.Printf("\n read and write: %s\n", tmpstr[:rn])
fmt.Printf("bufWriter buffered: %d, ava:%d, size:%d \n", bufWriter.Buffered(), bufWriter.Available(), bufWriter.Size())
}
bufWriter.Flush()
}
文件的写入,追加,读取,复制操作
在 Go 语言中,文件使用指向 os.File 类型的指针来表示的,也叫做文件句柄。我们在前面章节使用到过标准输入 os.Stdin 和标准输出 os.Stdout,他们的类型都是*os.File。
os.Stdin:标准输入的文件实例,类型为File
os.Stdout:标准输出的文件实例,类型为File
os.Stderr:标准错误输出的文件实例,类型为*File
方法列表:
- func Create(name string) (file *File, err Error) 根据提供的文件名创建新的文件,返回一个文件对象,默认权限是0666
- func NewFile(fd uintptr, name string) *File 根据文件描述符创建相应的文件,返回一个文件对象
- func Open(name string) (file *File, err Error) 只读方式打开一个名称为name的文件
- func OpenFile(name string, flag int, perm uint32) (file *File, err Error) 打开名称为name的文件,flag是打开的方式,只读、读写等,perm是权限
- func (file *File) Write(b []byte) (n int, err Error) 写入byte类型的信息到文件
- func (file *File) WriteAt(b []byte, off int64) (n int, err Error) 在指定位置开始写入byte类型的信息
- func (file *File) WriteString(s string) (ret int, err Error) 写入string信息到文件
- func (file *File) Read(b []byte) (n int, err Error) 读取数据到b中
- func (file *File) ReadAt(b []byte, off int64) (n int, err Error) 从off开始读取数据到b中
- func Remove(name string) Error 删除文件名为name的文件
文件的写入
创建文件并写入
file, _ := os.Create("D:\\phpStudy\\PHPTutorial\\WWW\\go\\src\\shineyork\\07\\log.txt")
defer file.Close()
file.WriteString("shineyork \n")
file.Write([]byte("byte"))
打开文件写入
func write() {
f := "D:\\phpStudy\\PHPTutorial\\WWW\\go\\src\\shineyork\\07\\log.txt"
file, _ := os.OpenFile(f, os.O_WRONLY, 0666)
defer file.Close()
file.WriteString("优秀啊 \n")
}
OpenFile 方法参数
func OpenFile(name string, flag int, perm FileMode) (*File, error)
可以看到,OpenFile 函数有三个参数:文件名、一个或多个标志(使用逻辑运算符“|”连接),使用的文件权限
我们通常会用到以下标志:
- os.O_RDONLY:只读
- os.O_WRONLY:只写
- os.O_CREATE:创建:如果指定文件不存在,就创建该文件。
- os.O_TRUNC:截断:如果指定文件已存在,就将该文件的长度截为0。
在读文件的时候,文件的权限是被忽略的,所以在使用 OpenFile 时传入的第三个参数可以用0。而在写文件时,不管是 Unix 还是 Windows,都需要使用 0666如果内容比较多我们可以配合缓冲一起
f := "D:\\phpStudy\\PHPTutorial\\WWW\\go\\src\\shineyork\\07\\log.txt"
file, _ := os.OpenFile(f, os.O_WRONLY, 0666)
bw := bufio.NewWriter(file)
for i := 0; i < 10; i++ {
bw.WriteString("扣 666 ! \n")
}
defer file.Close()
bw.Flush()
追加
file, _ := os.OpenFile(f, os.O_APPEND|os.O_RDWR, 0666)
读取
f := "D:\\phpStudy\\PHPTutorial\\WWW\\go\\src\\shineyork\\07\\log.txt"
file, _ := os.Open(f)
defer file.Close()
var buf [128]byte // 记录一次读取的量
var content []byte // 整体的数据量
for {
n, err := file.Read(buf[:]) // 根据
if err == io.EOF {
// 读取结束
break
}
if err != nil {
fmt.Println("read file err ", err)
return
}
content = append(content, buf[:n]...)
}
fmt.Println(string(content))
Read根据传进的byte数组,然后读取文件信息并放入到该数组中;在过程中利用for对内容进行循环读取
与bufio对接
f := "D:\\phpStudy\\PHPTutorial\\WWW\\go\\src\\shineyork\\07\\log.txt"
file, _ := os.Open(f)
defer file.Close()
br := bufio.NewReader(file)
context := ""
for {
n, err := br.ReadString('\n')
if err == io.EOF {
break
}
context = context + n
}
fmt.Println(context)
复制操作
实现文件的copy,拷贝一个文件到另一个文件
package main
import (
"fmt"
"io"
"os"
)
func main() {
CopyFile("D:\\phpStudy\\PHPTutorial\\WWW\\go\\src\\shineyork\\07\\target.txt",
"D:\\phpStudy\\PHPTutorial\\WWW\\go\\src\\shineyork\\07\\log.txt")
fmt.Println("Copy done!")
}
func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dst, err := os.Create(dstName)
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src)
}