go 文件处理 07

fmt

fmt包实现了类似C语言printf和scanf的格式化I/O。主要分为向外输出内容和获取输入内容两大部分。

Print

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打印值的类型
%%百分号

布尔型

占位符说明
%ttrue或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:

  1. 如果缓冲区为空,且rn >= buf_ size, 则直接从文件读取,不启用缓冲。
  2. 如果缓冲区为空,且rn < buf_ size,则从文件读取buf_ size字节的内容到缓冲区,程序再从缓冲区中读取rn字节的内容,此时缓冲区剩余bn = buf_ size ? - rn字节。
  3. 如果缓冲区不为空, rn < bn, 则从缓冲区读取rn字节的内容,不发生文件I0。
  4. 如果缓冲区不为空, 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:

  1. 如果缓冲区为空,且wn >= buf_size, 则直接写入文件,不启用缓冲,发生文件I0。
  2. 如果缓冲区为空,且wn < buf_size, 则程序将内容写入缓中区,不发生文件IO。
  3. 如果缓冲区不为空, wn + bn < buf_ size, 则程序将内容写入缓冲区,不发生文件IO。
  4. 如果缓冲区不为空, 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)
}

下一篇:并发编程 8
上一篇:反射 6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值