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)
O_RDONLY
O_WRONLY
O_RDWR
O_DIRECT
O_APPEND
O_TRUNC
。。。。
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的人,经常遇到了这种代码
只要打开了文件,每次异常处理都要想着close,否则句柄泄漏,太烦。所以C语言是一门你要小心伺候的语言。
go提供了defer解决这种困境,后面不用时刻惦记close,函数退出前,会执行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$/mycptest.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?
当然了首先要fopen,获得文件描述符,然后可以fgets按行获取。
我给出个C程序,完成基本的cat功能,支持-n选项,带了-n则打印出行号:
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提供
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;
我给出个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
*Reader)ReadByte(c)
看一下go语言实现的简易mycat:
/self$ cat mycat"io"
.