OperateFile
本节介绍 Golang 中常用的文件与网络操作封装:CSV 读写、环境变量文件生成、带会话保持的 HTTP 客户端。这些是链上数据落盘、CLI 工具开发中的高频操作。
ReadCSV
读取 CSV 文件的标准流程:os.Open 打开文件 → csv.NewReader 构造读取器 → ReadAll 一次性读入全部行。返回的 lines 是二维切片 [][]string,每个元素是一行的字段列表。
reader.Comma 指定分隔符,默认为 ,,也可以改为 \t 读取 TSV 文件:
file, err := os.Open("file.csv")
if err != nil {
log.Fatal(err)
}
defer file.Close()
reader := csv.NewReader(file)
reader.Comma = ','
lines, err := reader.ReadAll()
if err != nil {
log.Fatal(err)
}
for index, line := range lines {
fmt.Println(index, line) // line 为 []string,对应一行中的各个字段
}
WriteCSV
写入 CSV 的流程:os.OpenFile 以追加模式打开(os.O_CREATE|os.O_WRONLY|os.O_APPEND)→ csv.NewWriter 构造写入器 → 循环 Write 写入行 → defer writer.Flush() 刷盘。
注意 Flush 必须调用,否则数据可能还停留在缓冲区没有落盘。下面的示例将链上交易记录批量导出为 CSV 文件:
func ParseTxToCSV(res *[]gettxbyaddress.Result, apiKey string) {
file, err := os.OpenFile("file.csv", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
log.Fatal(err)
}
defer func(file *os.File) {
err := file.Close()
if err != nil {
log.Fatal(err)
}
}(file)
writer := csv.NewWriter(file)
defer writer.Flush()
for _, txRes := range *res {
ERC20 := checkERC20(txRes.To, apiKey)
err := writer.Write([]string{
txRes.BlockNumber,
txRes.TimeStamp,
txRes.Hash,
txRes.Nonce,
txRes.BlockHash,
txRes.TransactionIndex,
txRes.From,
txRes.To,
ERC20,
txRes.Value,
txRes.Gas,
txRes.GasPrice,
txRes.IsError,
txRes.TxReceiptStatus,
txRes.Input,
txRes.ContractAddress,
txRes.CumulativeGasUsed,
txRes.GasUsed,
txRes.Confirmations,
txRes.MethodId,
txRes.FunctionName,
})
if err != nil {
log.Fatal(err)
}
}
}
WriteEnvFile
生成 .env 风格的配置文件。要点:
- 用
strings.Join(lines, "\n")拼接内容,保证末尾换行 os.WriteFile的第三个参数是文件权限,0600表示仅文件所有者可读写——密钥类配置必须收紧权限,避免被同机其他用户读取- 注释中提醒将文件加入
.gitignore,防止敏感信息被提交到仓库
func onboardWriteEnvFile(path, postgresDSN, gatewayToken, encryptionKey string) {
var lines []string
lines = append(lines, "# GoClaw — auto-generated by onboard")
lines = append(lines, "# Keep this file secret! Add to .gitignore.")
lines = append(lines, "")
lines = append(lines, fmt.Sprintf("export GOCLAW_POSTGRES_DSN=%s", postgresDSN))
lines = append(lines, fmt.Sprintf("export GOCLAW_GATEWAY_TOKEN=%s", gatewayToken))
lines = append(lines, fmt.Sprintf("export GOCLAW_ENCRYPTION_KEY=%s", encryptionKey))
lines = append(lines, "")
content := strings.Join(lines, "\n")
_ = os.WriteFile(path, []byte(content), 0600)
}
HttpWithSameSession
默认的 http.Client 每次请求相互独立、不保留 Cookie。要模拟「同一会话」(例如登录后保持会话连续请求),需要给 http.Client 挂上 cookiejar,由它负责在各次请求间自动存取 Cookie:
cookiejar.New(nil)创建会话存储,Cookie 会按域名自动管理DisableKeepAlives: true关闭连接复用,每次请求使用新连接,适合配合代理或避免服务端连接限制MaxIdleConnsPerHost: -1表示不保留每主机空闲连接Timeout: 0表示不设置整体超时(如需超时控制可设为具体时长)
func createHttpClient() (*http.Client, error) {
jar, err := cookiejar.New(nil)
if err != nil {
return nil, fmt.Errorf("cookiejar.New error %s", err.Error())
}
return &http.Client{
Jar: jar,
Transport: &http.Transport{
DisableKeepAlives: true,
MaxIdleConnsPerHost: -1,
},
Timeout: 0,
}, nil
}