面试题答案
一键面试设计思路
- 使用defer关键字:在Go语言中,
defer
语句用于注册一个延迟执行的函数,该函数会在包含它的函数返回前执行。在打开文件后,立即使用defer
来注册关闭文件的操作,这样无论函数是正常返回还是因为错误提前返回,文件都会被关闭。 - 错误处理:在文件读取过程中,对每一个可能返回错误的操作进行检查。如果发生错误,通过
error
类型返回错误信息,调用方可以据此进行处理。 - 使用WaitGroup:因为是多协程操作,使用
sync.WaitGroup
来等待所有协程完成任务,确保在程序退出前所有文件操作都已完成。
关键代码片段
package main
import (
"fmt"
"io/ioutil"
"sync"
)
func processFile(filePath string, wg *sync.WaitGroup) {
defer wg.Done()
data, err := ioutil.ReadFile(filePath)
if err != nil {
fmt.Printf("Error reading file %s: %v\n", filePath, err)
return
}
// 处理文件内容
fmt.Printf("Processed file %s: %s\n", filePath, data)
}
func main() {
var wg sync.WaitGroup
filePaths := []string{"file1.txt", "file2.txt", "file3.txt"}
for _, filePath := range filePaths {
wg.Add(1)
go processFile(filePath, &wg)
}
wg.Wait()
fmt.Println("All files processed.")
}
在上述代码中:
processFile
函数负责单个文件的读取和处理。在函数开始处使用defer wg.Done()
确保协程完成时WaitGroup
计数减一。ioutil.ReadFile
用于读取文件内容,若读取失败,会打印错误信息并返回。- 在
main
函数中,通过wg.Add(1)
为每个协程增加计数,并使用go
关键字启动协程。最后通过wg.Wait()
等待所有协程完成。
如果需要更底层的文件操作(如使用os.Open
和file.Read
),代码如下:
package main
import (
"fmt"
"os"
"sync"
)
func processFile(filePath string, wg *sync.WaitGroup) {
defer wg.Done()
file, err := os.Open(filePath)
if err != nil {
fmt.Printf("Error opening file %s: %v\n", filePath, err)
return
}
defer file.Close()
var buf [1024]byte
for {
n, err := file.Read(buf[:])
if n > 0 {
// 处理读取到的数据
fmt.Printf("Read from %s: %s\n", filePath, buf[:n])
}
if err != nil {
break
}
}
}
func main() {
var wg sync.WaitGroup
filePaths := []string{"file1.txt", "file2.txt", "file3.txt"}
for _, filePath := range filePaths {
wg.Add(1)
go processFile(filePath, &wg)
}
wg.Wait()
fmt.Println("All files processed.")
}
在这个版本中:
- 使用
os.Open
打开文件,并立即使用defer file.Close()
确保文件关闭。 - 通过
file.Read
循环读取文件内容,处理读取到的数据,并在读取错误时跳出循环。