package main import ( "bufio" "fmt" "io" "os" ) func main() { var inFile, outFile *os.File if inFile, err := os.Open("in.txt"); inFile == nil { //inFile 是指针类型可以赋值nil (1) fmt.Println(err.Error()) inFile = os.Stdin } defer inFile.Close() if outFile, err := os.OpenFile("out.txt", os.O_RDWR, 0766); err != nil { fmt.Println(outFile) ////这里必须用一下outFile , 否则go编译器扯淡报错outFile未使用过,或者也可以象(1)那样反过来不判断err而判断另一个不空 fmt.Println(err.Error()) outFile = os.Stdout } defer outFile.Close() reader, writer := bufio.NewReader(inFile), bufio.NewWriter(outFile) var s bytes.Buffer for { line, err := reader.ReadString('\n') //nil 只能赋值给指针和引用类型,报错 can not convert nil to string if err != nil && err != io.EOF { //真出错了,而不是到结尾了 break } //bytes.Buffer 类似于 java 中的 StringBuilder 处理大量字符串连接非常好 s.WriteString(line) //字符串是值类型不能有其他值,也不能用空字符串标识到了文件结尾,这会和空行混淆 if err == io.EOF { //到结尾了 break } } /* //另一种感觉更清晰的写法 for line, err := reader.ReadString('\n'); err == nil || err == io.EOF; line, err = reader.ReadString('\n') { s.WriteString(line) if err == io.EOF { break } } */ if _, err := writer.WriteString(s); err == nil { writer.Flush() } else { fmt.Println(err.Error()) } }