golang中的文件操作
一、文件的基本介绍
文件是数据源(保存数据的地方)的一种,比如经常使用的word文档,txt文件,excel文件都是文件。文件最主要的作用就是保存数据,它既可以保存一张图片,也可以保持视频,声音等等。
1、输入流和输出流
2、os.File封装了所以文件相关操作,File是一个结构体
type File struct {
// 内含隐藏或非导出字段
}
File代表一个打开的文件对象。
func (f *File) Read(b []byte) (n int, err error)
Read方法从f中读取最多len(b)字节数据并写入b。它返回读取的字节数和可能遇到的任何错误。文件终止标志是读取0个字节且返回值err为io.EOF。
func (f *File) ReadAt(b []byte, off int64) (n int, err error)
ReadAt从指定的位置(相对于文件开始位置)读取len(b)字节数据并写入b。它返回读取的字节数和可能遇到的任何错误。当n<len(b)时,本方法总是会返回错误;如果是因为到达文件结尾,返回值err会是io.EOF。
func (f *File) Write(b []byte) (n int, err error)
Write向文件中写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。
func (f *File) WriteAt(b []byte, off int64) (n int, err error)
WriteAt在指定的位置(相对于文件开始位置)写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。
二、打开文件和关闭文件
func Open(name string) (file *File, err error)
Open打开一个文件用于读取。如果操作成功,返回的文件对象的方法可用于读取数据;对应的文件描述符具有O_RDONLY模式。如果出错,错误底层类型是*PathError。
func (f *File) Close() error
Close关闭文件f,使文件不能用于读写。它返回可能出现的错误。
package main import (
"fmt"
"os"
) func main() {
//打开文件
//file叫做对象、指针或者文件句柄
file, err := os.Open("/Users/test/Desktop/demo/ssh.txt")
if err != nil {
fmt.Println("open fiel err=", err)
}
fmt.Printf("file=%v,%T", *file, file) err = file.Close()
if err != nil {
fmt.Println("close file err=", err)
}
}
三、读写文件操作
读取文件的内容并显示在终端(带缓冲区的方式),使用os.Open,file.Close,bufio.NewReader(),reader.ReadString函数和方法
package main import (
"bufio"
"fmt"
"io"
"os"
) func main() {
//打开文件
//file叫做对象、指针或者文件句柄
file, err := os.Open("/Users/test/Desktop/demo/ssh.txt")
if err != nil {
fmt.Println("open fiel err=", err)
} //当函数退出时,要及时关闭file,否则会有内存泄漏
defer file.Close()
if err != nil {
fmt.Println("close file err=", err)
}
// 创建一个 *Reader ,是带缓冲的
/*
const (
defaultBufSize = 4096 //默认的缓冲区为 4096 )
*/ reader := bufio.NewReader(file) //循环读取文件内容
for {
str, err := reader.ReadString('\n') //读到一个换行就结束
if err == io.EOF { //io.EOF表示文件的末尾
break
}
//输出内容
fmt.Print(str)
}
fmt.Println("文件读取结束...")
}
读取文件的内容并显示在终端(使用ioutil一次将整个文件读入到内存中),这种方式适用于文件不大的情况。相关方法和函数(ioutil.ReadFile)
func ReadFile(filename string) ([]byte, error)
ReadFile 从filename指定的文件中读取数据并返回文件的内容。成功的调用返回的err为nil而非EOF。因为本函数定义为读取整个文件,它不会将读取返回的EOF视为应报告的错误。
package main import (
"fmt"
"io/ioutil"
) func main() {
//使用ioutil.ReadFile一次性将文件读取到位
file := "/Users/test/Desktop/bytedance/ssh.txt" content, err := ioutil.ReadFile(file)
if err != nil {
fmt.Printf("read file err=%v", err)
}
//把读取到的内容显示到终端
fmt.Printf("%v\n", content) //[]byte
fmt.Printf("%v", string(content)) //没有显式的Open文件,也不需要显式Close文件
//文件的Open和Close被封装到ReadFile函数内部
}
os.OpenFile 函数
func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
OpenFile是一个更一般性的文件打开函数,大多数调用者都应用Open或Create代替本函数。它会使用指定的选项(如O_RDONLY等)、指定的模式(如0666等)打开指定名称的文件。如果操作成功,返回的文件对象可用于I/O。如果出错,错误底层类型是*PathError。
第二个参数:文件打开模式(可以组合)
const (
O_RDONLY int = syscall.O_RDONLY // 只读模式打开文件
O_WRONLY int = syscall.O_WRONLY // 只写模式打开文件
O_RDWR int = syscall.O_RDWR // 读写模式打开文件
O_APPEND int = syscall.O_APPEND // 写操作时将数据附加到文件尾部
O_CREATE int = syscall.O_CREAT // 如果不存在将创建一个新文件
O_EXCL int = syscall.O_EXCL // 和O_CREATE配合使用,文件必须不存在
O_SYNC int = syscall.O_SYNC // 打开文件用于同步I/O
O_TRUNC int = syscall.O_TRUNC // 如果可能,打开时清空文件
)
第三个参数:权限控制
r -> 4
w -> 2
x -> 1
package main import (
"bufio"
"fmt"
"os"
) func main() {
filePath := "/Users/test/Desktop/test.txt"
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Printf("open file err=%v\n", err)
return
}
defer file.Close()
str := "hello,world\n"
//写入时使用带缓存的*Writer
writer := bufio.NewWriter(file)
for i := 0; i < len(str); i++ {
writer.WriteString(str)
}
//writer是带缓存的,在调用WriterString方法时,内容是先写入缓存的,
//需要调用Flush方法,将缓冲的数据真正写入到文件中,否则文件中会没有数据
writer.Flush()
}
打开一个存在的文件,将原来的内容覆盖成新的10句话“欢迎来到go的世界”
package main import (
"bufio"
"fmt"
"os"
) func main() {
filePath := "/Users/test/Desktop/test.txt"
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_TRUNC, 0666)
if err != nil {
fmt.Printf("open file err=%v\n", err)
return
}
defer file.Close()
str := "欢迎来到go的世界\n"
//写入时使用带缓存的*Writer
writer := bufio.NewWriter(file)
for i := 0; i < 10; i++ {
writer.WriteString(str)
}
//writer是带缓存的,在调用WriterString方法时,内容是先写入缓存的,
//需要调用Flush方法,将缓冲的数据真正写入到文件中,否则文件中会没有数据
writer.Flush()
}
打开一个存在的文件,在原来的内容后面追加内容“欢天喜地过大年”
package main import (
"bufio"
"fmt"
"os"
) func main() {
filePath := "/Users/test/Desktop/test.txt"
file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_APPEND, 0666)
if err != nil {
fmt.Printf("open file err=%v\n", err)
return
}
defer file.Close()
str := "欢天喜地过大年!\r\n"
//写入时使用带缓存的*Writer
writer := bufio.NewWriter(file)
for i := 0; i < 10; i++ {
writer.WriteString(str)
}
//writer是带缓存的,在调用WriterString方法时,内容是先写入缓存的,
//需要调用Flush方法,将缓冲的数据真正写入到文件中,否则文件中会没有数据
writer.Flush()
}
打开一个存在的文件,将原来的内容读出显示在终端,并且追加 5 句"hello,北京!"
package main import (
"bufio"
"fmt"
"io"
"os"
) func main() {
filePath := "/Users/test/Desktop/test.txt"
file, err := os.OpenFile(filePath, os.O_RDWR|os.O_APPEND, 0666)
if err != nil {
fmt.Printf("open file err=%v\n", err)
return
}
defer file.Close()
//写入时使用带缓存的*Writer
reader := bufio.NewReader(file) for {
str, err := reader.ReadString('\n')
if err == io.EOF {
break
}
fmt.Print(str)
} str := "hello,北京!\r\n"
writer := bufio.NewWriter(file)
for i := 0; i < 10; i++ {
writer.WriteString(str)
}
//writer是带缓存的,在调用WriterString方法时,内容是先写入缓存的,
//需要调用Flush方法,将缓冲的数据真正写入到文件中,否则文件中会没有数据
writer.Flush()
}
编程一个程序,将一个文件的内容,写入到另外一个文件。注:这两个文件已经存在了。使用ioutil.ReadFile/ioutil.WriteFile完成写文件的任务。
package main import (
"fmt"
"io/ioutil"
) func main() {
filePath1 := "/Users/test/Desktop/test.txt"
filePath2 := "/Users/test/Desktop/dest.txt"
data, err := ioutil.ReadFile(filePath1)
if err != nil {
fmt.Printf("read file err=%v\n", err)
return
}
err = ioutil.WriteFile(filePath2, data, 0666)
if err != nil {
fmt.Printf("write file error=%v\n", err)
}
}
判断文件是否存在
golang判断文件或文件夹是否存在的方法为使用os.Stat()函数返回的错误值进行判断:
(1)、如果返回的错误为nil,说明文件或文件夹存在
(2)、如果返回的错误类型使用os.IsNotExist()判断为true,说明文件或文件夹不存在
(3)、如果返回的错误为其它类型,则不确定是否存在
package main import (
"fmt"
"os"
) func PathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
} func main() {
filePath := "/Users/test/Desktop/test.txt"
fmt.Println(PathExists(filePath))
}
拷贝文件
package main import (
"bufio"
"fmt"
"io"
"os"
) func CopyFile(dstFileName string, srcFileName string) (written int64, err error) {
srcFile, err := os.Open(srcFileName)
if err != nil {
fmt.Printf("open file err=%v\n", err)
} defer srcFile.Close() reader := bufio.NewReader(srcFile) dstFile, err := os.OpenFile(dstFileName, os.O_WRONLY|os.O_CREATE, 0666) if err != nil {
fmt.Printf("open file err=%v\n", err)
return
} writer := bufio.NewWriter(dstFile) defer dstFile.Close() return io.Copy(writer, reader)
} func main() {
srcFile := "/Users/bytedance/Desktop/cao.png"
dstFile := "/Users/bytedance/Desktop/dst.png"
_, err := CopyFile(dstFile, srcFile)
if err == nil {
fmt.Printf("文件拷贝完成\n")
} else {
fmt.Printf("文件拷贝出错,err=%v", err)
}
}
统计英文、数字、空格和其他字符数量
package main import (
"bufio"
"fmt"
"io"
"os"
) type CharCount struct {
ChCount int //记录英文个数
NumCount int //记录数字个数
SpaceCount int //记录空格个数
OtherCount int //记录其它字符的个数
} func main() {
fileName := "/Users/bytedance/Desktop/test.txt"
file, err := os.Open(fileName)
if err != nil {
fmt.Printf("open file err=%v\n", err)
return
} defer file.Close() var count CharCount reader := bufio.NewReader(file) for {
s, err := reader.ReadString('\n')
if err == io.EOF {
break
}
//为了兼容中文字符,将str转成[]rune
str := []rune(s) for _, v := range str {
switch {
case v >= 'a' && v <= 'z':
fallthrough //穿透
case v >= 'A' && v <= 'Z':
count.ChCount++
case v == ' ' || v == '\t':
count.SpaceCount++
case v >= '0' && v <= '9':
count.NumCount++
default:
count.OtherCount++
}
}
} fmt.Printf("字符的个数=%v 数字的个数=%v 空格的个数=%v 其它字符个数=%v", count.ChCount, count.NumCount, count.SpaceCount, count.OtherCount)
}
四、命令行参数
os.Args是一个string的切片,用来存储所有的命令行参数。
package main import (
"fmt"
"os"
) func main() {
fmt.Println("命令行参数有", len(os.Args))
//遍历os.Args切片可以得到所有的命令行输入参数值
for i, v := range os.Args {
fmt.Printf("args[%v]=%v\n", i, v)
}
}
flag包解析命令行参数
package main import (
"flag"
"fmt"
) func main() {
//定义变量用于接收命令行参数值
var user string
var pwd string
var host string
var port int flag.StringVar(&user, "u", "", "用户名,默认为空")
flag.StringVar(&pwd, "pwd", "", "密码,默认为空")
flag.StringVar(&host, "h", "localhost", "主机名,默认为localhost")
flag.IntVar(&port, "port", 3306, "端口号,默认为3306") //转换操作,必须调用该方法
flag.Parse() fmt.Printf("user=%v pwd=%v host=%v port=%v\n", user, pwd, host, port)
}
五、json
轻量级的数据交换格式。json易于机器解析和生成,并有效地提升网络传输效率,通常程序在网络传输时先将数据(结构体、map等)序列化成json字符串,到接收方得到json字符串时,在反序列化恢复成原来的数据类型(结构体、map等)。这种方式已然成为各个语言的标准。
1、json的序列化
json序列化是指将有key-value结构的数据类型(比如结构体、map、切片)序列化成json字符串的操作。
package main import (
"encoding/json"
"fmt"
) type Monster struct {
Name string
Age int
Birthday string
Sal float64
Skill string
} //序列化结构体
func testStruct() {
monster := Monster{
Name: "牛魔王",
Age: 500,
Birthday: "2011-11-11",
Sal: 8000.0,
Skill: "牛魔拳",
} //将monster序列化
data, err := json.Marshal(&monster)
if err != nil {
fmt.Printf("序列化错误 err=%v\n", err)
} //输出序列化后的结果
fmt.Printf("monster序列化后=%v\n", string(data))
} //map序列化
func testMap() {
var a map[string]interface{} a = make(map[string]interface{}) a["name"] = "红孩儿"
a["age"] = 30
a["address"] = "洪崖洞" data, err := json.Marshal(a)
if err != nil {
fmt.Printf("序列化错误 err=%v\n", err)
} //输出序列化后的结果
fmt.Printf("map序列化后=%v\n", string(data))
} //切片序列化
func testSlice() {
var slice []map[string]interface{} var m1 map[string]interface{}
m1 = make(map[string]interface{})
m1["name"] = "jack"
m1["age"] = "7"
m1["addresss"] = "北京"
slice = append(slice, m1) var m2 map[string]interface{}
m2 = make(map[string]interface{})
m2["name"] = "tom"
m2["age"] = "20"
m2["address"] = [2]string{"墨西哥", "夏威夷"}
slice = append(slice, m2) data, err := json.Marshal(slice)
if err != nil {
fmt.Printf("序列化错误 err=%v\n", err)
} //输出序列化后的结果
fmt.Printf("slice 序列化后=%v\n", string(data))
} //对基本数据类型序列化,对基本数据类型进行序列化意义不大
func testFloat64() {
var num float64 = 2345.67 data, err := json.Marshal(num) if err != nil {
fmt.Printf("序列化错误 err=%v\n", err)
} //输出序列化后的结果
fmt.Printf("num序列化后=%v\n", string(data))
} func main() {
testStruct()
testMap()
testSlice()
testFloat64()
}
对于结构体的序列化,如果希望序列化后的key的名字重新制定,那么可以给struct指定一个tag标签。
package main import (
"encoding/json"
"fmt"
) type Monster struct {
Name string `json:"monster_name"`
Age int `json:"monster_age"`
Birthday string
Sal float64
Skill string
} //序列化结构体
func testStruct() {
monster := Monster{
Name: "牛魔王",
Age: 500,
Birthday: "2011-11-11",
Sal: 8000.0,
Skill: "牛魔拳",
} //将monster序列化
data, err := json.Marshal(&monster)
if err != nil {
fmt.Printf("序列化错误 err=%v\n", err)
} //输出序列化后的结果
fmt.Printf("monster序列化后=%v\n", string(data))
} func main() {
testStruct()
}
2、json的反序列化
json反序列化是指将json字符串反序列化成对应的数据类型(比如结构体、map、切片)的操作。
package main import (
"encoding/json"
"fmt"
) type Monster struct {
Name string
Age int
Birthday string
Sal float64
Skill string
} //反序列化结构体
func unmarshalStruct() {
str := "{\"Name\":\"牛魔王\",\"Age\":500,\"Birthday\":\"2011-11-11\",\"Sal\":8000,\"Skill\":\"牛魔拳\"}" var monster Monster err := json.Unmarshal([]byte(str), &monster)
if err != nil {
fmt.Printf("unmarshal err=%v\n", err)
} fmt.Printf("反序列化后 monster=%v monster.Name=%v\n", monster, monster.Name)
} //map序列化
func testMap() string {
var a map[string]interface{} a = make(map[string]interface{}) a["name"] = "红孩儿"
a["age"] = 30
a["address"] = "洪崖洞" data, err := json.Marshal(a)
if err != nil {
fmt.Printf("序列化错误 err=%v\n", err)
} //输出序列化后的结果
fmt.Printf("map序列化后=%v\n", string(data))
return string(data)
} //反序列化map
func unmarshalMap() {
str := "{\"address\":\"洪崖洞\",\"age\":30,\"name\":\"红孩儿\"}" var a map[string]interface{} //反序列化map不需要make,因为make操作被封装到Unmarshal函数
err := json.Unmarshal([]byte(str), &a) if err != nil {
fmt.Printf("unmarshal err=%v\n", err)
} fmt.Printf("反序列化后 a=%v\n", a)
} //反序列化map
func unmarshalMap2() {
str := testMap() var a map[string]interface{} //反序列化map不需要make,因为make操作被封装到Unmarshal函数
err := json.Unmarshal([]byte(str), &a) if err != nil {
fmt.Printf("unmarshal err=%v\n", err)
} fmt.Printf("反序列化后 a=%v\n", a)
} //反序列化切片
func unmarshalSlice() {
str := "[{\"address\":\"北京\",\"age\":\"7\",\"name\":\"jack\"}," + "{\"address\":[\"墨西哥\",\"夏威夷\"],\"age\":\"20\",\"name\":\"tom\"}]" var slice []map[string]interface{} err := json.Unmarshal([]byte(str), &slice) if err != nil {
fmt.Printf("unmarshal err=%v\n", err)
} fmt.Printf("反序列化后 slice=%v\n", slice)
}
func main() {
unmarshalStruct()
unmarshalMap()
unmarshalMap2()
unmarshalSlice()
}
在反序列化一个json字符串时,要确保反序列化后的数据类型和原来序列化前的数据类型一致。
如果json字符串是通过程序获取到的,则不需要再对“转义处理。
golang中的文件操作的更多相关文章
- 第32课 Qt中的文件操作
1. Qt的中IO操作 (1)Qt中IO操作的处理方式 ①Qt通过统一的接口简化了文件和外部设备的操作方式 ②Qt中的文件被看作一种特殊的外部设备 ③Qt中的文件操作与外部设备的操作相同 (2)IO操 ...
- 重新想象 Windows 8 Store Apps (24) - 文件系统: Application Data 中的文件操作, Package 中的文件操作, 可移动存储中的文件操作
原文:重新想象 Windows 8 Store Apps (24) - 文件系统: Application Data 中的文件操作, Package 中的文件操作, 可移动存储中的文件操作 [源码下载 ...
- 背水一战 Windows 10 (91) - 文件系统: Application Data 中的文件操作, Application Data 中的“设置”操作, 通过 uri 引用 Application Data 中的媒体
[源码下载] 背水一战 Windows 10 (91) - 文件系统: Application Data 中的文件操作, Application Data 中的“设置”操作, 通过 uri 引用 Ap ...
- 背水一战 Windows 10 (90) - 文件系统: 获取 Package 中的文件, 可移动存储中的文件操作, “库”管理
[源码下载] 背水一战 Windows 10 (90) - 文件系统: 获取 Package 中的文件, 可移动存储中的文件操作, “库”管理 作者:webabcd 介绍背水一战 Windows 10 ...
- Java中的文件操作(一)RandomAccessFile
今天,学到的是java中的文件操作. Java.IO.File Java中操作文件用到RandomAccessFile类,既可以读取文件内容,也可以向文件输出数据,但不同与普通输入/输出流的是Rand ...
- Win 32平台SDK中的文件操作
读取文件: HANDLE hFile ; // 声明文件操作内核对象句柄 hFile = CreateFile(, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL ...
- Golang基础之文件操作
目录 文件读取 os.open文件读取 os.open循环读取 bufio文件读取 bufio循环读取 ioutil读取整个文件 文件写入 os.OpenFile文件写入 bufio.NewWrite ...
- ASP.NET中的文件操作(文件信息,新建,移动,复制,重命名,上传,遍历)(亲测详细)
做了几天的文件操作,现在来总结一下,错误之处,还望指点!以文件为例,如果对文件夹操作,基本上将File换为Directory即可(例:FileInfo file = new FileInfo(Path ...
- 关于Python中的文件操作(转)
总是记不住API.昨晚写的时候用到了这些,但是没记住,于是就索性整理一下吧: python中对文件.文件夹(文件操作函数)的操作需要涉及到os模块和shutil模块. 得到当前工作目录,即当前Pyth ...
随机推荐
- oracle数据库登录
在做以下操作时,要确保你的数据库环境已经正确安装完成.数据库在实际应用中是比较多的,我们测试人员经常会在前台造一些测试数据,在后台数据库进行验证,当然,不局限于此,数据库也可以作为一个专项测试来谈.反 ...
- 解决jquery操作checkbox火狐下第二次无法勾选问题
最近在学习jQuery(版本jquery-1.9.1.js),要求用jQuery实现全选/全不选.反选,在IE(IE8)中没有问题,但在火狐浏览器中调试的时候出现了一些小问题,达不到效果. html代 ...
- Arduino I2C + DS1307实时时钟
主要特性 DS1307是Maxim的串行.I2C实时时钟芯片.主要特性有: 工作电压:主电源电压4.5~5.5V,电池电压2.0~3.5V 功耗:电池供电.备份模式时<500nA 接口:I2C, ...
- 【C#】CLR
CLR是如何工作的 借用维基百科上的一副图来描述CLR的运行流程: 从源代码到应用程序执行CLR主要做了以下工作: 将源代码编译成托管模块 托管模块是一个标准的 32 位 Microsoft Wind ...
- linux内存布局------深入理解计算机系统
- 【03】循序渐进学 docker:基础命令
写在前面的话 之前谈了啥是 docker 和怎么安装 docker,这里就谈谈 docker 命令的使用,当然,这里的使用可能只是局限于 docker 的增删查改. 另外需要注意的是,为了图片的美观, ...
- 用C语言构建一个可执行程序的流程
1.流程图 从用C语言写源代码,然后经过编译器.连接器到最终可执行程序的流程图大致如下图所示. 2.编译流程 首先,我们先用C语言把源代码写好,然后交给C语言编译器.C语言编译器内部分为前端和后端. ...
- day1学python Hello Python
Hello Python 本人使用的是Pycharm编译器 ----------------------------------------------- 1.输出 2.赋值 3.‘’‘/“”“ 多行 ...
- Tomcat类加载机制触发的Too many open files问题分析(转)
https://blog.csdn.net/ctrip_tech/article/details/53337137 说起Too many open files这个报错,想必大家一定不陌生.在Linux ...
- linux系统安全及应用——账号安全(基本安全措施)
不开启桌面可以减少受攻击面 一.系统账号清理 1)非登录用户的shell改为/sbin/nologin ~] #usermod -s /sbin/nologin user1 2)锁定长期不用的账号 锁 ...