用戶輸入
fmt.Scanxx
- fmt.Scanln
var s1,s2 string
fmt.Scanln(&s1,&s2)
以上是讀取一行,以空格分隔,直到遇到非空字符。所以如果代碼是這樣的:
var s1,s2 string
fmt.Scanln(&s1)
fmt.Scanln(&s2)
fmt.Printnln(s1,s2)
而輸入了abcd efg那么輸出將會是abcd fg,因為第二個單詞的第一個字符被當作換行處理。但是如果輸入abcd\n,那么第二個字符串將會讀取不到,因為是按行來讀取的,遇到換行直接就讀完了。
- fmt.Scanf()
fmt.Scanf和C語言中的scanf用法一樣:fmt.Scanf("%s%s",&s1,&s2)
- fmt.Scan()
fmt.Scan()不處理換行符,直到傳入的參數(shù)都讀取完畢。如fmt.Scan(&s1,&2),讀取的兩個字符串之間可以有換行符。
fmt.Sscanxxx
遇到S開頭的scan函數(shù),其處理的都是字符串,不會處理用戶輸入。
如:
input := "abcd efg"
fmt.Sscan(input,&s1,&s2)
fmt.Sscanln(input,&s1,&s2)
fmt.Sscanf(input,"%s%s",&s1,&s2)
bufio
利用bufio也可以讀取數(shù)據(jù):
- bufio.NewScanner
inputScanner := bufio.NewScanner(os.Stdin)
inputScanner.Scan()
fmt.Println(inputScanner.Text())
其中inputScanner.Scan()會將讀取的一行數(shù)據(jù)保存在內部的緩沖區(qū)中,使用inputScanner.Text()可以將其讀取出來,注意Scan不會將換行符讀進去,并且類似\n這種字符,他又不會去轉義。
- bufio.NewReader
inputReader := bufio.NewReader(os.Stdin)
input,err := inputReader.ReadString(',')
但是注意,這個函數(shù)和inputScanner不一樣,這個是直接返回讀取的數(shù)據(jù)以及error,其中參數(shù)表示,讀取到對應的字符就停止,并且返回的數(shù)據(jù)包含該字符。所以如果輸入是abcd,,則input的值就是abcd,
不止ReadString可以讀取,ReadBytes也可以讀取,不過ReadBytes返回的是byte類型的切片。byte類型的切片又和string可以互轉,所以基本上是一樣的。
文件讀寫
os.Open和bufio
os.Open("input.txt")用于打開一個文件,文件類型一般是os.*File類型,而os.Stdin也是os.*File類型,所以對于bufio.NewScanner()或bufio.NewReader也可以傳入一個文件。所以文件讀取最簡單的思路就是通過os.Open和bufio包實現(xiàn):
file,err := os.Open("test.go")
if err != nil{
fmt.Println("讀取文件失敗")
}
inputScan := bufio.NewScanner(file)
for inputScan.Scan() {
fmt.Println(inputScan.Text())
}
當然也可以通過bufio.NewReader(file)來實現(xiàn),但是注意,這種方法實現(xiàn)的需要判斷err,如果讀取到文件結尾,將會返回io.EOF,所以讀取整個文件的方式是:
file,err := os.Open("test.go")
if err != nil{
fmt.Println("讀取文件失敗")
}
inputReader := bufio.NewReader(file)
for {
line,err := inputReader.ReadString('\n')
fmt.Printf("%s",line)
if err == io.EOF{
return
}
}
注意返回io.EOF的時候,line變量里也會有值。
ioutil
利用ioutil.ReadXxx的函數(shù)可以讀取文件內容或用戶輸入,如:
file,err := os.Open("test.go")
defer file.Close()
if err != nil{
fmt.Println("讀取錯誤")
}
bytes,err := ioutil.ReadAll(file)
if err != nil{
fmt.Println("讀取又錯誤")
}
fmt.Println(string(bytes))
ioutil.ReadAll傳入的是io.Reader,所以對于os.Open,其剛好返回io.Reader,所以是可以的。
同樣也可以使用ioutil.ReadFile方法,該方法其實就是對上述方法的封裝:
bytes,err := ioutil.ReadFile("test.go")
if err != nil{
fmt.Println("讀取錯誤")
}
fmt.Println(string(bytes))
緩沖讀取
f,err := os.Open("test.go")
if err != nil{
fmt.Println("錯誤")
}
fefer f.Close()
inputReader := bufio.NewReader(f)
buf := make([]byte,1024)
n,err := inputReader.Read(buf)
for n!=0 && err ==nil{
fmt.Println(string(buf))
n,err = inputReader.Read(buf)
}
其中inpuReader.Read方法傳入的就是緩沖的參數(shù),該函數(shù)返回的是n表示讀入的字節(jié)個數(shù)。注意,一定要融會貫通,這樣讀取的方式不僅僅對文件使用,同樣對屏幕輸入適用。
fmt.Fscanxxx
同樣fmt里包含F(xiàn)開頭的一些讀取函數(shù),與fmt.Sscanln``fmt.Sscan``fmt.Sscanf是類似的,不過第一個參數(shù)從傳入字符串,變成了傳入文件。
文件寫入
最簡單的是通過fmt.Fprintf將一個字符串寫入:fmt.Fprintf(file,"some data\n")或fmt.Fprintln(file,"some data")
f,_ := os.Open("test.go")
_,err := fmt.Fprintln(f,"someData")
fmt.Println(err)
這種方式要注意權限,如果沒有權限就會寫入不成功
另一種方法是通過os.OpenFile來打開文件,并且賦予打開的方式,如:
outputFile,err := os.OpenFile("test.go",os.O_WRONLY|os.O_CREATE,0666)
if err != nil{
fmt.Println("錯誤")
}
defer outputFile.Close()
outputFile.WriteString("哈哈哈,我終于寫進來了")
需要注意的是,第二個參數(shù)是打開的模式,可以有只讀模式,以及追加模式等,一般用的模式有:
const (
O_RDONLY int = syscall.O_RDONLY // open the file read-only.
O_WRONLY int = syscall.O_WRONLY // open the file write-only.
O_RDWR int = syscall.O_RDWR // open the file read-write.
O_APPEND int = syscall.O_APPEND // append data to the file when writing.
O_CREATE int = syscall.O_CREAT // create a new file if none exists.
O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist
O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
O_TRUNC int = syscall.O_TRUNC // if possible, truncate file when opened.
)
在寫入文件的時候,第三個參數(shù)必須是0666,而對于讀的時候可以忽略。
如果寫入的內容過多,可以通過bufio來創(chuàng)建一個有緩沖的寫入器:
bufio.NewWriter(outputFile)
文件拷貝
io.Copy(target,source)
但是注意source文件可以通過os.Open讀取,而target文件必須使用os.OpenFile來讀取,并賦予os.O_WRONLY標志或者其他可寫標志。
命令行讀取
命令行讀取可以通過os.Args來獲取命令的參數(shù),同樣可以通過flag包來設置參數(shù)。
比如輸入:./goTest hahaha lalal那么os.Args中存放的就是[./goTest,hahaha,lalal],可以通過os.Args[1]這種方式來取出。
但是如果我想要./goTest -name Mike這種方式來取數(shù)據(jù)怎么辦呢,方法就是通過flag包。
比如:
name := flag.String("name","","輸入你的名字~")
flag.Parse()
fmt.Println(*name)
注意name是一個指針類型,通過flag.Parse()方法可以解析命令行參數(shù),通過*name將輸入取出,flag.String的第一個參數(shù)表示命令行中的參數(shù)名,如輸入./goTest -name "hahah",其中-name就是對應第一個參數(shù),第二個參數(shù)是name的默認值,如果沒有輸入,name的值就是這個默認值,第三個參數(shù)是說明,一般只有在help中出現(xiàn)。
當然不僅僅有flag.String還有flag.Bool等方法。
falg.StringVar跟flag.String一樣,只不過flag.StringVar沒有返回值,而是將name指針傳給了該方法:flag.StringVar(&name,"name","","輸入你的名字~")