Base64 是开发中常用的编码格式,无论是处理 API 认证头、嵌入图片数据,还是 URL 安全传输,都离不开它。虽然在线 Base64 工具不少,但每次都要打开浏览器复制粘贴实在低效。
今天我用 OpenCode 从零写一个命令行 Base64 编解码工具,支持标准编码、URL 安全编码、文件输入和自动格式检测,全部代码约 90 行,完全用自然语言指挥 AI 完成。
技术栈: Go 1.21+,纯标准库,无第三方依赖。
最终效果:
# 编码 $ echo "Hello World" | go run main.go SGVsbG8gV29ybGQ= # 解码 $ echo "SGVsbG8gV29ybGQ=" | go run main.go -d Hello World # URL 安全编码 $ echo "Hello World" | go run main.go -u SGVsbG8gV29ybGQ= # 从文件编码 $ go run main.go -f logo.png iVBORw0KGgo...
在项目目录下打开 OpenCode:
opencode
我直接告诉 OpenCode 我想做什么,它帮我生成项目骨架。
> 我对 OpenCode 说:
>
> "用 Go 写一个命令行 Base64 编解码工具,先帮我初始化项目结构,用 main.go 单文件就行,加上 flag 解析、stdin 读取的基本框架,错误信息用中文。"
OpenCode 立刻生成了 main.go 的初始骨架,包含了 flag 定义、标准输入读取和基本的错误处理。
关键要点: OpenCode 会根据你的描述推断项目规模,如果你只说"写一个工具",它可能会创建多文件结构。明确说"单文件"和"基础框架"能让它聚焦在最小可用版本上。
骨架有了,该让它实现核心的编码逻辑了。
> 我对 OpenCode 说:
>
> "把编码功能补全:从 stdin 读取文本,去掉首尾空白后,使用 base64.StdEncoding 编码,结果直接打印到 stdout。如果输入为空就提示错误。"
OpenCode 在 main 函数中补充了完整的编码逻辑:
text := strings.TrimSpace(string(input))
if text == "" {
fmt.Fprintln(os.Stderr, "错误: 输入为空")
os.Exit(1)
}
result := base64.StdEncoding.EncodeToString([]byte(text))
fmt.Println(result)
关键要点: 这是 OpenCode 的强项——标准库 API 调用非常准确。你不需要记 EncodeToString 的参数类型,告诉它"用 base64 标准编码",它自动补全正确的调用方式。
一个工具光能编码不够,解码才是高频需求。
> 我对 OpenCode 说:
>
> "加上 -d 参数,当传了 -d 时走解码逻辑。解码时先尝试 StdEncoding,失败了试试 RawStdEncoding(兼容不带 = 填充的格式),还失败就给用户中文错误提示。"
OpenCode 帮我写出了一段带自动回退的解码逻辑:
if *decode {
decoded, err := base64.StdEncoding.DecodeString(text)
if err != nil {
decoded, err = base64.RawStdEncoding.DecodeString(text)
if err != nil {
fmt.Fprintf(os.Stderr, "解码失败: 无法识别的 Base64 格式\n")
os.Exit(1)
}
}
fmt.Print(string(decoded))
}
关键要点: 注意我说了"先尝试...失败了试试..."这种条件分支描述。OpenCode 能理解这种级联回退逻辑,自动生成嵌套的 if-err 结构,比你手写快得多。
Base64 有标准、URL 安全、Raw 几种变体,我让 OpenCode 全部支持。
> 我对 OpenCode 说:
>
> "再加两个参数:-u 启用 URL 安全编码(使用 base64.URLEncoding),-f 从文件读取输入。解码时也用 URL 安全编码优先尝试。把编码器选择抽成一个独立函数。"
OpenCode 重构了代码,把编码器选择提成了 getEncoder 函数,解码逻辑进化成了遍历 4 种编码格式自动匹配:
func getEncoder(urlSafe, raw bool) *base64.Encoding {
if urlSafe && raw {
return base64.RawURLEncoding
}
if urlSafe {
return base64.URLEncoding
}
if raw {
return base64.RawStdEncoding
}
return base64.StdEncoding
}
关键要点: "抽成一个独立函数"这个指令非常重要。OpenCode 默认倾向于把所有逻辑写在一起,你主动要求重构,它会立刻把代码模块化——这正是结对编程的感觉。
一个好的 CLI 工具离不开清晰的帮助输出。
> 我对 OpenCode 说:
>
> "给 flag.Usage 加一个自定义的帮助信息,包含工具简介、用法示例和参数说明,全部用中文。另外加一个 -r 参数控制是否使用 Raw 编码(去掉结尾的 =)。"
OpenCode 生成了一段带有使用示例的帮助函数,并且无缝集成了 -r 参数到已有的编码选择逻辑中。最终的 --help 输出非常友好。
package main
import (
"encoding/base64"
"flag"
"fmt"
"io"
"os"
"strings"
)
func main() {
decode := flag.Bool("d", false, "解码模式")
urlSafe := flag.Bool("u", false, "使用 URL 安全编码")
filePath := flag.String("f", "", "从文件读取输入")
raw := flag.Bool("r", false, "使用 Raw 编码(无填充字符)")
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Base64 编解码工具\n\n")
fmt.Fprintf(os.Stderr, "用法:\n")
fmt.Fprintf(os.Stderr, " echo <文本> | %s # 编码\n", os.Args[0])
fmt.Fprintf(os.Stderr, " echo <编码> | %s -d # 解码\n", os.Args[0])
fmt.Fprintf(os.Stderr, " %s -f <文件> # 从文件编码\n\n", os.Args[0])
fmt.Fprintf(os.Stderr, "参数:\n")
flag.PrintDefaults()
}
flag.Parse()
var input []byte
var err error
if *filePath != "" {
input, err = os.ReadFile(*filePath)
} else {
input, err = io.ReadAll(os.Stdin)
}
if err != nil {
fmt.Fprintf(os.Stderr, "读取输入失败: %v\n", err)
os.Exit(1)
}
text := strings.TrimSpace(string(input))
if text == "" {
fmt.Fprintln(os.Stderr, "错误: 输入为空")
os.Exit(1)
}
if *decode {
output := tryDecode(text, *urlSafe)
fmt.Print(string(output))
} else {
enc := getEncoder(*urlSafe, *raw)
result := enc.EncodeToString([]byte(text))
fmt.Println(result)
}
}
func getEncoder(urlSafe, raw bool) *base64.Encoding {
if urlSafe && raw {
return base64.RawURLEncoding
}
if urlSafe {
return base64.URLEncoding
}
if raw {
return base64.RawStdEncoding
}
return base64.StdEncoding
}
func tryDecode(text string, urlSafe bool) []byte {
encodings := []*base64.Encoding{
base64.StdEncoding,
base64.URLEncoding,
base64.RawStdEncoding,
base64.RawURLEncoding,
}
if urlSafe {
encodings = []*base64.Encoding{
base64.URLEncoding,
base64.RawURLEncoding,
base64.StdEncoding,
base64.RawStdEncoding,
}
}
for _, enc := range encodings {
decoded, err := enc.DecodeString(text)
if err == nil {
return decoded
}
}
fmt.Fprintln(os.Stderr, "解码失败: 无法识别的 Base64 格式")
os.Exit(1)
return nil
}
从零到完整可用的 Base64 工具,整个过程我没有写过一行代码,都是通过自然语言让 OpenCode 完成:
| 环节 | 传统开发 | 用 OpenCode |
|------|---------|------------|
| 编码 API 查文档 | 2-3 分钟 | 0(AI 直接写对) |
| 错误处理 | 5 分钟 | 30 秒(一句"给出中文错误提示") |
| 重构抽函数 | 3 分钟 | 10 秒(一句"抽成独立函数") |
| 写帮助信息 | 5 分钟 | 20 秒 |
效率提升大约 5-10 倍。 更重要的是,你不需要在编码-文档-StackOverflow 之间来回切换,所有对话都在终端里完成,思维的连贯性得到了最大程度的保留。
如果你还没试过 OpenCode,强烈建议从这样一个小工具开始体验。