61396-Go语言程序设计项目化教程(微课版)5.1 反射与文件.pptx
反射与文件反射与文件reflect反射基本概念文件操作反射修改变量压缩归档文件操作01.03.02.04.目录01reflect反射基本概念反射定义TypeValue1reflectreflect反射基本概念反射基本概念反射是指在程序运行期间对程序本身进行访问和修改的能力。一般地,程序在编译时,变量会被转换为内存地址,但变量名不会被编译器写入到可执行部分。因此在运行程序时,程序无法获取自身的信息。支持反射的语言则可以在程序编译期将变量的反射信息,如字段名称、类型信息、结构体信息等整合到可执行文件中,并给程序提供接口访问反射信息,这样就可以在程序运行期获取类型的反射信息,并且有能力修改它们。Go语言提供了一种机制在运行时更新和检查变量的值、调用变量的方法和变量支持的内在操作,但是在编译时并不知道这些变量的具体类型,这种机制被称为反射。反射也可以让我们将类型本身作为第一类的值类型处理。Go程序在运行期使用reflect包访问程序的反射信息;主要涉及到Type和Value这两个基本概念。反射定义1reflectreflect反射基本概念反射基本概念reflect.TypeOf(varname).Kind()反射获取变量类型的详细信息reflect.TypeOf(varname).Kind()=reflect.Type反射类型详细信息和基本类型比较注:reflect.Type的Type表示数据变量类型,比如int、float64、string等。reflect.TypeOf(varname)反射获取变量类型package mainimport(fmt reflect)func main()var a int fmt.Println(reflect.TypeOf(a).Name()fmt.Println(reflect.TypeOf(a).Kind()fmt.Println(reflect.TypeOf(a).Align()fmt.Println(reflect.TypeOf(a).Kind()=reflect.Float32)运行结果为:intint8false1reflectreflect反射基本概念反射基本概念reflect.ValueOf(&varname)反射获取指向变量的指针注:&varname表示传入变量地址。需要注意的是,Go语言中不能直接对指针进行运算符或者修改操作,因此通常会使用Elem()函数获取指针指向的值,方便后续对该值进行操作。reflect.ValueOf(varname)反射获取变量值package mainimport(fmt reflect)func main()var a int a=10 fmt.Println(reflect.ValueOf(a)fmt.Println(reflect.ValueOf(&a)fmt.Println(reflect.ValueOf(&a).Elem()运行结果为:100 xc00000a09810reflect.ValueOf(&varname).Elem()反射获取指针地址所指向的值1reflectreflect反射基本概念反射基本概念package mainimport(fmt reflect)type Person struct Name string Age intfunc main()p:=&Person Name:Go,Age:20,fmt.Println(reflect.ValueOf(&p)fmt.Println(reflect.ValueOf(p).Elem()fmt.Println(reflect.ValueOf(p).Type()fmt.Println(reflect.ValueOf(p).Kind()fmt.Println(reflect.TypeOf(p)fmt.Println(reflect.TypeOf(p).Elem()fmt.Println(reflect.TypeOf(p).Name()fmt.Println(reflect.TypeOf(p).Kind()fmt.Println(reflect.TypeOf(p).Size()运行结果为:0 xc000006028Go 20*main.Personptr*main.Personmain.Personptr802反射修改变量反射修改变量反射修改切片反射修改切片索引值2反射修改变量反射修改变量在使用reflect.ValueOf()的Elem()函数时,如果ValueOf()传入的是变量的地址,那么就可以通过反射去修改变量的值。注:SetType()中的Type表示具体的数据类型,比如SetString()、SetInt()等。reflect.ValueOf(&x).Elem().Set()反射修改变量reflect.ValueOf(&x).Elem().SetType()反射修改变量类型package mainimport(fmt reflect)func main()var a int a=10 var b int=5 reflect.ValueOf(&a).Elem().Set(reflect.ValueOf(b)fmt.Println(a)reflect.ValueOf(&a).Elem().SetInt(20)fmt.Println(a)运行结果为:5202反射修改变量反射修改变量intSliceElemValue:=reflect.ValueOf(&intSlice).Elem()newValue:=reflect.ValueOf(newSliceValue)intSliceElemValue.Set(newValue)反射修改整个切片注:首先使用 reflect.ValueOf 传入要修改的切片的地址,并且使用 Elem 获取指针信息;接着使用 reflect.ValueOf 传入一个新的切片;最后使用Set 方法传入新的切片的 Value 信息,完成对原切片值的修改。intSliceValue:=reflect.ValueOf(intSlice)e:=intSliceValue.Index(index_size)e.SetInt(newvarname)反射修改切片索引值注:在Go语言中,如果通过反射的reflect.ValueOf()获得反射的对象信息是结构体类型,则可以通过Elem()函数来修改字段值。package mainimport(fmt reflect)func main()var intSlice=int1,2,3,4 intSliceElemValue:=reflect.ValueOf(&intSlice).Elem()if intSliceElemValue.CanSet()newSliceValue:=int11,12,13,14 newVale:=reflect.ValueOf(newSliceValue)intSliceElemValue.Set(newVale)fmt.Println(NewSliceVal=,intSlice)运行结果为:NewSliceVal=11 12 13 142反射修改变量反射修改变量利用反射去修改整个切片函数CanSet()用于判断指针指向的对象是否可以被修改package mainimport(fmt reflect)func main()var intSlice=int1,2,3,4 intSliceValue:=reflect.ValueOf(intSlice)e:=intSliceValue.Index(0)if e.CanSet()e.SetInt(11)fmt.Println(NewVal=,intSliceValue)运行结果为:NewVal=11 2 3 42反射修改变量反射修改变量利用反射去修改切片索引值函数Index()用于获取所需要修改索引处的值信息2反射修改变量反射修改变量personNameValue:=reflect.ValueOf(&struct.name)personNameValue.Elem().SetString(newvarname)反射修改结构体字段值注:&struct.name表示获取结构体中字段名的地址,newvarname为修改后的字段值。package mainimport(fmt reflect)type Person struct Name string Age intfunc main()p:=Person Name:GO,Age:20,personNameValue:=reflect.ValueOf(&p.Name)personAgeValue:=reflect.ValueOf(&p.Age)personNameValue.Elem().SetString(golang)personAgeValue.Elem().SetInt(18)fmt.Println(p)运行结果为:golang 1803文件操作创建文件打开文件写入文件读取文件拷贝文件关闭文件3文件操作文件操作注:name为文件名,返回值为打开文件的句柄,失败则返回error错误信息,否则返回nil。func Open(name string)(*File,error)func(file*File)Close()error打开文件函数关闭文件函数注:file为打开的文件,失败则返回error错误信息,否则返回nil。注:Create采用模式0666(任何人都可读写,不可执行)创建一个名为name的文件。如果文件已存在会截断它(为空文件)。创建成功则返回的文件对象可用于I/O;对应的文件描述符具有O_RDWR模式。创建失败则返回错误信息,错误底层类型是*PathError。func Create(name string)(file*File,err error)创建文件函数3文件操作文件操作文件读取ioutil.ReadFile()file.Read()bufio.NewReader()ioutil.ReadAll()func ReadFile(filename string)(byte,error)ioutil.ReadFile()注:上述函数不需要手动打开与手动关闭文件,其中filename表示文件名,返回值byte代表文件内容,该函数会以字节数组形式读取文件内容。func ReadAll(file io.Reader)(byte,error)ioutil.ReadAll()注:使用上述函数之前,需要先行手动打开文件获得文件句柄,然后通过文件句柄来读取文件,其中file表示文件句柄。3文件操作文件操作func(f*File)Read(b byte)(n int,err error)file.Read()注:使用上述函数之前,需要先行手动打开文件获得文件句柄,然后通过文件句柄调用该函数来读取文件内容。其中f表示打开的句柄,b表示读取文件内容存放的指针,n表示读取到的字节数。fileData:=bufio.NewReader(file)n,err:=fileData.Read(buf)bufio.NewReader()注:使用上述函数之前,需要先行手动打开文件获得文件句柄,然后通过文件句柄来读取文件。file表示文件句柄,buf表示读取数据后存放的缓存区域,n表示读取到的长度。3文件操作文件操作文件写入io.WriteString()ioutil.WriteFile()file.Write()writer.WriteString()func(f*File)Write(b byte)(n int,err error)file.Write()注:f是要操作的文件,b是要写入到文件里的内容。该语句在写入成功的情况下,会返回成功写入的字节数n,如果写入失败,则会返回err错误信息。3文件操作文件操作func WriteFile(filename string,data byte,perm os.FileMode)error ioutil.WriteFile()注:filename表示文件名,data是一个byte类型的数组,代表要写入到文件里的内容,perm代表的是文件的权限。func(b*Writer)WriteString(p byte)(n int,err error)bufio.WriteString()注:b是要写入的文件,p代表要写的内容。该语句在写入成功的情况下,会返回成功写入的字节数n,如果写入失败,则会返回err错误信息。func WriteString(w Writer,s string)(n int,err error)io.WriteString()注:w是一个Writer类型的接口,代表的是要写入信息的文件,s代表的是需要写入文件的内容。package mainimport fmtimport osfunc main()path:=“E:/Write.txt”/调用函数,传入路径 WriteFile(path)func WriteFile(path string)file01,err:=os.Create(path)/根据路径,创建文件 if err!=nil fmt.Println(err=,err)return defer file01.Close()/关闭文件 /对文件中的内容操作 var str string for i:=0;i 10;i+str=fmt.Sprintf(i=%drn,i)/构造i=数字的字符串 data01,err:=file01.WriteString(str)/以字符串的方式写入文件,返回data01和err if err!=nil fmt.Println(err=,err)return else fmt.Println(data01=,data01)将数据写入文件3文件操作文件操作package mainimportfmtimportioimportosfunc main()ReadFile(E:/Write.txt)func ReadFile(path string)file01,err:=os.Open(path)/根据路径,返回文件名和err if err!=nil fmt.Println(err=,err)return defer file01.Close()/关闭文件 s1:=make(byte,2048)long,err:=file01.Read(s1)/以切片的方式读文件,返回读的长度和err if err!=nil&err!=io.EOF fmt.Println(err=,err)return else fmt.Println(string(s10:long)/以字符串的方式输出 读取文件中的数据运行结果为:i=0i=1i=2i=3i=4i=5i=6i=7i=8i=93文件操作文件操作3文件操作文件操作文件拷贝io.CopyN()io.Copy()读写func CopyN(dst Writer,src Reader,n int64)(written int64,err error)io.CopyN()注:从源文件里复制n字节(或者遇到错误中断)到目标文件,并返到实际复制的节数。只有err为nil时,written才会等于n。3文件操作文件操作func Copy(dst Writer,src Reader)(written int64,err error)io.Copy()注:Copy函数可以实现从源到目标文件的复制,直到读到源的EOF或者出现其它的错误,它返回所复制的字节数及复制过程出现的第一个错误。如果成功复制,Copy返回的err的值为nil,因为Copy被定义为从源复制直到遇到EOF,它不把EOF当作一个错误。将原文件的内容读出来,再写到另一个文件中去,完成文件的复制。读写package mainimportfmtimportioimportosfunc main()CopyFile(os.Args1,os.Args2)/os.Args1为目标文件,os.Args2为源文件 fmt.Println(复制完成)func CopyFile(dstName,srcName string)(written int64,err error)src,err:=os.Open(srcName)if err!=nil return defer src.Close()dst,err:=os.OpenFile(dstName,os.O_WRONLY|os.O_CREATE,0644)if err!=nil return defer dst.Close()return io.Copy(dst,src)3文件操作文件操作04压缩归档文件操作Zip格式Tar格式4压缩归档文件操作压缩归档文件操作buf:=new(bytes.Buffer)zw=zip.NewWriter(buf)zr:=zip.OpenReader(file.zip)创建zip归档文件读取 zip 归档文件注:变量buf为一个存放文档数据的缓存区,zw为zip压缩格式的存档。4压缩归档文件操作压缩归档文件操作package mainimport(archive/zip bytes fmt os)func main()/创建一个缓冲区保存压缩文件内容 buf:=new(bytes.Buffer)/创建一个压缩文档 w:=zip.NewWriter(buf)/将文件加入压缩文档 var files=struct Name,Body string Zip.txt,创建zip压缩文件,for _,file:=range files f,err:=w.Create(file.Name)if err!=nil fmt.Println(err)_,err=f.Write(byte(file.Body)if err!=nil fmt.Println(err)/关闭压缩文档 err:=w.Close()if err!=nil fmt.Println(err)/将压缩文档内容写入文件 f,err:=os.OpenFile(file.zip,os.O_CREATE|os.O_WRONLY,0666)if err!=nil fmt.Println(err)buf.WriteTo(f)4压缩归档文件操作压缩归档文件操作package mainimport(archive/zip fmt io os)func main()/打开一个zip格式文件 r,err:=zip.OpenReader(file.zip)if err!=nil fmt.Printf(err.Error()defer r.Close()/迭代压缩文件中的文件,打印出文件中的内容 for _,f:=range r.File fmt.Printf(文件名:%sn,f.Name)rc,err:=f.Open()if err!=nil fmt.Printf(err.Error()_,err=io.CopyN(os.Stdout,rc,int64(f.UncompressedSize64)if err!=nil fmt.Printf(err.Error()rc.Close()运行结果为:文件名:Zip.txt创建zip压缩文件4压缩归档文件操作压缩归档文件操作buf:=new(bytes.Buffer)tw:=tar.NewWriter(buf)f:=os.Open(output.tar)r:=tar.NewReader(f)创建tar归档文件解压 tar 归档文件注:变量buf为一个存放文档数据的缓存区,tw为tar压缩格式的存档。4压缩归档文件操作压缩归档文件操作package mainimport(archive/tar fmt io os)func main()f,err:=os.Create(E:/output.tar)/创建一个 tar 文件 if err!=nil fmt.Println(err)return defer f.Close()tw:=tar.NewWriter(f)defer tw.Close()fileinfo,err:=os.Stat(E:/Write.txt)/获取文件信息,确保文件存在 if err!=nil fmt.Println(err)hdr,err:=tar.FileInfoHeader(fileinfo,)if err!=nil fmt.Println(err)err=tw.WriteHeader(hdr)/写入头文件信息 if err!=nil fmt.Println(err)f1,err:=os.Open(E:/Write.txt)if err!=nil fmt.Println(err)return m,err:=io.Copy(tw,f1)/将文件写入到tar文件中 if err!=nil fmt.Println(err)fmt.Println(m)4压缩归档文件操作压缩归档文件操作package mainimport(archive/tar fmt io os)func main()f,err:=os.Open(E:/output.tar)if err!=nil fmt.Println(文件打开失败,err)return defer f.Close()r:=tar.NewReader(f)for hdr,err:=r.Next();err!=io.EOF;hdr,err=r.Next()if err!=nil fmt.Println(err)return fileinfo:=hdr.FileInfo()fmt.Println(fileinfo.Name()f,err:=os.Create(output.tar的解压+fileinfo.Name()if err!=nil fmt.Println(err)defer f.Close()_,err=io.Copy(f,r)if err!=nil fmt.Println(err)谢谢观看谢谢观看