文件操作
作为后端语言,Go 通过os 包提供了对文件的操作。
同时,使用bufio 与ioutil 也可以进行文件操作,三者均有自身的优劣势结合不同的需求使用不同的包来进行操作,将会让你的事半功倍。
文件分为普通文件和二进制文件,使用二进制文件时应该按照byte 进行读取。
OpenFile
在os 包中,有一个方法名为OpenFile() ,它可以用指定模式来打开一个文件对象,并且会返回一个文件句柄。
func OpenFile(name string,flag int,perm FileMode) (*File,error) {
...
}
name:文件路径
flag:打开文件的模式
perm:权限,一个八进制数。r(读)04,w(写)02,x(执行)01。
下表是flag 所支持的模式选项,如果要添加多种模式,使用| 进行分割。
模式 |
含义 |
os.O_WRONLY |
只写 |
os.O_CREATE |
创建文件 |
os.O_RDONLY |
只读 |
os.O_RDWR |
读写 |
os.O_TRUNC |
清空 |
os.O_APPEND |
追加 |
读取文件
内容准备
下面有一个test.txt 文件,里面存储了一些歌曲名称,专辑名称,作者名称等信息。
海阔天空 | Words & Music Final Live | Beyond
红豆 | 唱游 | 王菲
我可以抱你吗 | 重拾女人心 | 张惠妹
味道 | 味道 | 辛晓琪
独角戏 | 如果云知道 | 许茹芸
打开文件时,可以使用os.Open() 方法进行打开,它其实是基于os.OpenFile() 的一个封装。
默认是以只读的方式进行打开。返回一个文件句柄与错误对象。
func Open(name string) (*File,error) {
return OpenFile(name,O_RDONLY,0)
}
file.Read
当获取到文件句柄后,可使用Read() 方法对其进行读取。
func (f *File) Read(b []byte) (n int,err error) {
if err := f.checkValid("read"); err != nil {
return 0,err
}
n,e := f.read(b)
return n,f.wrapErr("read",e)
}
这是一个文件句柄的方法,接收一个byte 的切片,返回一个int 与error ,其中int 是已读取的字节数。
以下是基本使用:
package main
import (
"fmt"
"io"
"os"
)
func readTxt() {
// 打开文件,只读方式
file,err := os.Open("./file.txt")
if err != nil {
fmt.Println("打开文件出错:",err)
return
}
defer file.Close() // 关闭文件
var content []byte
var temp = make([]byte,128) // 创建容纳读取文件的一个变量,byte()类型
for {
// n 以读取的字节数
n,err := file.Read(temp) // 使用文件句柄,开始读取。 读取的内容放入temp变量中
if err == io.EOF { // 抛出EOF错误代表文件读取完毕
fmt.Println("文件读取完毕")
break
}
if err != nil {
fmt.Println("读取文件出错:",err)
return
}
content = append(content,temp[:n]...) // 使用展开语法,将其内容进行展开
}
fmt.Println(string(content)) // []byte转换为string
}
func main() {
readTxt()
}
bufio
bufio 是一个第三方的包,基于file 做了一层封装,支持更多的功能。
并且它具有缓冲区,能够让读写更加迅速。
使用NewReader() 方法,放入文件句柄,返回一个读取对象,然后再进行指定的方法读取该对象。
提供的读取方法如下:
方法 |
描述 |
Read |
接收一个byte切片,返回以读取字节数 |
ReadSlice |
返回一个切片,byte类型 |
ReadByte |
返回byte字符串 |
ReadBytes |
返回一个切片,byte类型 |
ReadRune |
返回一个rune字符串 |
ReadString |
返回一个string的字符串 |
ReadLine |
以行进行读取,返回一个byte切片,并且会返回一个布尔值判断是否读取完毕 |
其实用ReadString 就能满足大部分需求了。
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func readTxt() {
// 打开文件,只读方式
file,err)
return
}
defer file.Close() // 关闭文件
var content string
reader := bufio.NewReader(file) // 放入文件句柄,返回读取对象
for {
line,err := reader.ReadString('n') // 以字符 n 作为分割,即每次读取一行
if err == io.EOF {
fmt.Println("文件读取完毕")
break
}
if err != nil {
fmt.Println("读取文件时出错")
return
}
content += line
}
fmt.Println(content) // 拼接内容
}
func main() {
readTxt()
}
ioutil
该包位于os/ioutil 中,使用其ReadFile() 可快速的读取完整个文件。
package main
import (
"fmt"
"io/ioutil"
)
func readTxt() {
content,err := ioutil.ReadFile("./file.txt")
if err != nil {
fmt.Println("读取文件错误:",err)
return
}
fmt.Println(string(content))
}
func main() {
readTxt()
}
写入文件
write&writeString
write() 接收一个byte 切片,返回一个以读取字节数的int 和error 。
writeString() 则接收一个string 字符串,返回的内容同上。
package main
import (
"fmt"
"os"
)
func writeTxt() {
// 创建文件,只写
file,err := os.OpenFile("newFile.txt",os.O_CREATE|os.O_WRONLY,0666)
if err != nil {
fmt.Println("打开文件时出错",err)
return
}
defer file.Close()
// 写入文件
str := "第一行内容n"
file.Write([]byte(str)) // 写入字节切片
file.WriteString("第二行内容n")
}
func main() {
writeTxt()
}
bufio.NewWriter
bufio 具有缓冲区,所以读写更加迅速。
下面是基本使用,其实关于写入对象的写入文件的方法还有很多,这里不再一一例举。
package main
import (
"bufio"
"fmt"
"os"
)
func writeTxt() {
// 创建文件,只写,清空
file,os.O_CREATE|os.O_WRONLY|os.O_TRUNC,err)
return
}
defer file.Close()
// 写入文件
writer := bufio.NewWriter(file) // 放入文件句柄,获得一个写入对象
writer.WriteString("一行新数据")
writer.Flush() // 缓存刷新到磁盘
}
func main() {
writeTxt()
}
ioutil.WriteFile
该方法接收一个byte 的切片,我们可以直接放入byte 切片然后进行写入。
package main
import (
"fmt"
"io/ioutil"
)
func writeTxt() {
str := "新数据哦"
// 直接写入,清空之前的,会创建新文件
err := ioutil.WriteFile("./newFile.txt",[]byte(str),0666)
if err != nil {
fmt.Println("write file failed,err:",err)
return
}
}
func main() {
writeTxt()
}
指针偏移
type Seeker interface {
Seek(offset int64,whence int) (int64,error)
}
Seeker接口用于包装基本的移位方法。
Seek方法设定下一次读写的位置:偏移量为offset,校准点由whence确定:0表示相对于文件起始;1表示相对于当前位置;2表示相对于文件结尾。Seek方法返回新的位置以及可能遇到的错误。
移动到一个绝对偏移量为负数的位置会导致错误。移动到任何偏移量为正数的位置都是合法的,但其下一次I/O操作的具体行为则要看底层的实现。
以下是一个操纵示例,将最后一行内容进行覆盖修改。
海阔天空 | Words & Music Final Live | Beyond
红豆 | 唱游 | 王菲
我可以抱你吗 | 重拾女人心 | 张惠妹
味道 | 味道 | 辛晓琪
独角戏 | 如果云知道 | 许茹芸
操纵过程:
package main
import (
"fmt"
"os"
)
func writeTxt() {
// 创建文件,只写
file,err := os.OpenFile("file.txt",os.O_WRONLY,err)
return
}
defer file.Close()
// 设置指针移动
file.Seek(-40,2)
// 写入文件
str := "全新歌曲 | 全新专辑 | 新歌手n"
file.Write([]byte(str)) // 写入字节切片
}
func main() {
writeTxt()
}
最后结果:
海阔天空 | Words & Music Final Live | Beyond
红豆 | 唱游 | 王菲
我可以抱你吗 | 重拾女人心 | 张惠妹
味道 | 味道 | 辛晓琪
全新歌曲 | 全新专辑 | 新歌手 // 进行覆盖
拷贝文件
借助io.Copy() 实现一个拷贝文件函数。
// CopyFile 拷贝文件函数
func CopyFile(dstName,srcName string) (written int64,err error) {
// 以读方式打开源文件
src,err := os.Open(srcName)
if err != nil {
fmt.Printf("open %s failed,err:%v.n",srcName,err)
return
}
defer src.Close()
// 以写|创建的方式打开目标文件
dst,err := os.OpenFile(dstName,os.O_WRONLY|os.O_CREATE,0644)
if err != nil {
fmt.Printf("open %s failed,dstName,err)
return
}
defer dst.Close()
return io.Copy(dst,src) //调用io.Copy()拷贝内容
}
func main() {
_,err := CopyFile("dst.txt","src.txt")
if err != nil {
fmt.Println("copy file failed,err)
return
}
fmt.Println("copy done!")
}
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|