golang编程之文件操作
前端之家收集整理的这篇文章主要介绍了
golang编程之文件操作,
前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
http://blog.chinaunix.net/uid-24774106-id-3993609.html
操作文件是任何编程语言都绕不过,要掌握一门语言,知道如何操作文件是必不可少的,今天学习了下golang对文件操作的支持。
golang对文件的支持是在os package里。我无意将本文写成官方文档的模样,我只是想讨论如何利用这些接口操作文件。
OPEN
熟悉文件系统的人都知道,open是整个文件系统中最复杂的接口之一。熟悉C语言的都知道,C语言中有open和creat,接口如下:
- #include<sys/types.h>
- #<sys/stat>
- #<fcntl>
-
- intopen(const char*pathname,intflags);
- ;
-
- intcreat)
对C的open而言,如果flag里面有了O_CREAT,那么必须带上mode参数,制定创建
文件时的perm,如果
文件已经存在了,这个O_CREAT标志就无效了(除非O_EXCL标志被指定。除了O_CREAT,还有很多的标志
@H_
403_82@
O_RDONLY
O_WRONLY
O_RDWR
O_DIRECT
O_APPEND
O_TRUNC
。。。。
这些标志位基本是顾名思义,对于open这种很复杂很综合的
文件操作,golang中对应的是OpenFile
funcOpenFile(namestringint(file*File)
我们看到了也有flag,也有FileMode.比如说我要读写打开一个
文件,如果不存在就创建,如果存在,就追加写,如何写go
代码?
f:=os."test.txt".O_CREATE|os.O_APPEND.O_RDWR)
if(err!=nil{
panicerr)
}
我们看到了,golang中也有这些标志(注意O_CREATE,在C语言中,是O_CREAT),我在上面
代码片段中用了几个标志
const(
O_RDONLY=syscall.O_RDONLY // open the file read-only.
O_WRONLY.O_WRONLY // open the file write.
O_RDWR.O_RDWR // open the file read-write.
O_APPEND.O_APPEND // append data to the file when writing.
O_CREATE.O_CREAT // create a new fileifnone exists.
O_EXCL.O_EXCL // used with O_CREATEnotexist
O_SYNC.O_SYNC // openforsynchronous I/O.
O_TRUNC.O_TRUNC //ifpossible)
C语言中有creat,没有则创建,有则截断写,本质等于O_WRONLY | O_CREAT | O_TRUNC
>
*name)
Ken Thompson大神曾经戏言,漏掉creat系统
调用中的e字母是他设计Unix最后悔的事情,呵呵看起来老爷子接收了教训,没有犯同样的拼写
错误,golang中对应的接口是Create(大神这一次没有拼写错)
func Create)
和C的creat系统
调用相比,少了mode入参,默认是0x666(before umask),同时标志不再是O_WRONLY,而是O_RDWR,仍然带创建标志位,仍然带截断标志。
golang中的Open和C中的open就不能相比了(和C中的open PK那是OpenFile的事儿)接口如下:
func Open)
直白说,就是带O_RDONLY的open,太菜了。
CLOSE
这个接口无甚好说。接口如下
func(f)Close()error
但说接口没啥说的,但是golang提供了defer,这是一个我认为很赞的特点,就是将不得不做的cleanup放到defer去做。
我们写C的人,经常遇到了这种
代码
fd
=open
.(fd
<0
)
{
}
(Failed_1.
close(faile_2}
.
只要打开了
文件,每次异常处理都要想着close,否则句柄泄漏,太烦。所以C语言是一门你要小心伺候的语言。
go提供了defer
解决这种困境,后面不用时刻惦记close,
函数退出前,会执行close。
"open file
Failed"
)
}
defer f.Close)
...
READ和WRITE
read和write是比较重要的
文件操作了,这是C的接口。
<unistd>
ssize_t writeintfd*buf;
ssize_t read)
对于golang,接口如下:
)Read(b[]byte(ninterrerror)
func)ReadAt)
func)Write)
func)WriteAt)WriteString(sstring(ret)
看到
代码片段,学习使用读写接口:
read_buf=make]byte)
var pos int64=0
for{
n=fReadAt(read_bufiferr=nil && err=io.EOF{
panic)
}
ifn==0{
fmt.Printf"\nfinish read\n")
break
}
fmt"%s":n])
pos=pos+(int64(n)
}
在看一个
代码片段:
var buff{
n=fi.Read(buff)
}
=0{
break
}
if_=fo.Write;err=nil{
panic)
}
}
最后,我写了一个完整的
代码,完成简单cp
功能,就叫mycp
manu@manu-hacks~/code/go/self$ cat mycp.go
package main
import"fmt"
import"os"
import"io"
func usage{
fmt"%s %s %s\n".Args[0"filename""newfile"}
func main{
iflen(os=3{
usage)
return
}
filename_in[1]
fi.Open(filename_in}
defer fi)
filename_out[2]
fo.Create(filename_out}
defer fo)
var buff{
n&&.EOF=0{
break
;}
执行结果:
/code/go/self$
/mycp
test.txt
.bak
manu@manu/code/go/self$ diff.bak
manu@manu/code/go/self$ cat.txt
thisistestfile created by go
notexistedthisfile
ifexisted
hello world
参考文献
1 Linux system program
2
golang os package
3 StackOverflow
How to read/write from/to file?
上篇博文学习了go语言的对FILE的基本操作,我突然想到,文件一个很常用的场景是逐行处理,比如我们的linux下的神器awk,比如我之前写的KMean++算法处理NBA后卫的数据。对于C语言而言,fgets就解决了这个问题,看下C语言中fgets的接口:
char*fgets(char*sintsize*stream;
当然了首先要fopen,获得文件描述符,然后可以fgets按行获取。
我给出个C程序,完成基本的cat功能,支持-n选项,带了-n则打印出行号:
/c
/self
/readline$ cat mycat
.c
#include<stdio>
#include<stdlib<<errno>
intnum_flag;
intcat(FILE*file{
char buf[1024{0};
intline_no=1while(fgetsbuf,0)">1024file)!=NULL)
(num_flag{
fprintf(stdout"%5d %s"bufelse
}
line_no}
intmainintargc*argv{
intiintjintfile_exist;
FILENULL(i;i<argc(strcmp(argv[i"-n"{
num_flag;
break(j;j=i)
continue;
file_existfopenargv[j]"rb";
(stderr"%s:err reading from %s:%s\n"
argv[j(errno;
continue}
cat(file_exist{
cat(stdin}
golang怎么办?
golang 提供了package bufio。bufio.NewReader()创建一个默认大小的readbuf,当然,也可以bufio.NewReaderSize
func NewReader(rd io.Reader*Reader
NewReader returns a new Reader whose buffer has the default size(4096).
func NewReaderSize*Reader
NewReaderSize returns a new Reader whose buffer has at least the
specified sizeIfthe argument ioisalready a Reader with large
enough size.
bufio提供
*Reader
)ReadByte
(c
)
ReadByte readsandreturnsa singleIfnobyteis available
returns an error.
func)ReadBytes(delim(line)
ReadBytes reads until the first occurrenceofdeliminthe input
returning a slice containing the data up toandincluding the delimiterIfReadBytes encounters an error before finding a delimiter
the data read before the errorandthe error itself(often io.
ReadBytes returns errandonlyifthe returned data doesnot
endindelimForsimpleusesa Scanner may be more convenient.
func)ReadString(line string)
ReadString reads until the first occurrence
returning a string containing the data up toandincluding the
delimiterIfReadString encounters an error before finding a delimiter
it returns the data read before the error(often
io.ReadString returns errifthe returned data
doesnotendForsimpleuses
convenient ReadByte这个接口,和C语言中fgetc很接近,每次读取一个字节。ReadBytes和ReadString都可以实现逐行读取,只要delim设置为'\n'.
看一下go语言实现的简易mycat:
/self$ cat mycat"io"
import"flag"
import"bufio"
var num_flag=flag.Bool"n"false"num each line")
func usage"%s %s\n"}
func cat(r*bufio{
i=1
/:r.ReadBytes'\nReadString*num_flag.Fprintf.Stdout
i)
i+
else}
return
{
flag.Parse(flag.NArg(bufio.NewReader.Stdinfori<flagfosflagArgiO_RDONLY0660.Stderr"%s err read from %s : %s\n"
os.Arg(0)
continue
catbufioNewReader)
f 单纯考虑逐行读取,line by line, bufio的文档也说
.