
本文介绍如何使用 Go 标准库的 flag 包实现命令行参数驱动的功能选择(如加密/解密),避免硬编码逻辑,提升 CLI 程序的灵活性与可维护性。
本文介绍如何使用 go 标准库的 `flag` 包实现命令行参数驱动的功能选择(如加密/解密),避免硬编码逻辑,提升 cli 程序的灵活性与可维护性。
在构建 Go 命令行工具时,若需根据用户输入动态决定执行加密还是解密流程(而非同时运行两者),直接依赖 os.Args 不仅脆弱、难以扩展,还缺乏参数校验和帮助提示能力。推荐使用标准库 flag 包——它提供类型安全的参数解析、自动 -h/--help 支持、错误提示及位置参数管理。
以下是一个结构清晰、生产就绪的改造示例(基于原代码优化):
package main
import (
"flag"
"io/ioutil"
"log"
"os"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"errors"
"io"
)
// encrypt 加密明文,返回带 IV 的密文(CFB 模式)
func encrypt(key, text []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
ciphertext := make([]byte, aes.BlockSize+len(text))
iv := ciphertext[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
cfb := cipher.NewCFBEncrypter(block, iv)
cfb.XORKeyStream(ciphertext[aes.BlockSize:], text)
return ciphertext, nil
}
// decrypt 解密密文(首 aes.BlockSize 字节为 IV)
func decrypt(key, ciphertext []byte) ([]byte, error) {
if len(ciphertext) < aes.BlockSize {
return nil, errors.New("ciphertext too short")
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
iv := ciphertext[:aes.BlockSize]
data := ciphertext[aes.BlockSize:]
cfb := cipher.NewCFBDecrypter(block, iv)
cfb.XORKeyStream(data, data)
return data, nil
}
// encryptFileData 读取源文件、加密、写入目标文件
func encryptFileData(srcFile, destFile string) {
key := []byte("abcdefg123456789") // ⚠️ 生产环境请使用安全密钥生成方式
plaintext, err := ioutil.ReadFile(srcFile)
if err != nil {
log.Fatalf("读取源文件失败: %v", err)
}
ciphertext, err := encrypt(key, plaintext)
if err != nil {
log.Fatalf("加密失败: %v", err)
}
if err := ioutil.WriteFile(destFile, ciphertext, 0644); err != nil {
log.Fatalf("写入目标文件失败: %v", err)
}
log.Printf("✅ 已加密: %s → %s", srcFile, destFile)
}
// decryptFileData 读取密文文件、解密、写入明文文件
func decryptFileData(srcFile, destFile string) {
key := []byte("abcdefg123456789")
ciphertext, err := ioutil.ReadFile(srcFile)
if err != nil {
log.Fatalf("读取源文件失败: %v", err)
}
plaintext, err := decrypt(key, ciphertext)
if err != nil {
log.Fatalf("解密失败: %v", err)
}
if err := ioutil.WriteFile(destFile, plaintext, 0644); err != nil {
log.Fatalf("写入目标文件失败: %v", err)
}
log.Printf("✅ 已解密: %s → %s", srcFile, destFile)
}
func main() {
// 定义布尔标志:-encrypt 和 -decrypt(互斥)
encryptFlag := flag.Bool("encrypt", false, "启用加密模式")
decryptFlag := flag.Bool("decrypt", false, "启用解密模式")
// 解析命令行参数
flag.Parse()
// 验证至少指定一个操作模式
if !*encryptFlag && !*decryptFlag {
log.Fatal("❌ 错误:必须指定 -encrypt 或 -decrypt")
}
if *encryptFlag && *decryptFlag {
log.Fatal("❌ 错误:-encrypt 和 -decrypt 不能同时启用")
}
// 获取位置参数:srcFile 和 destFile
args := flag.Args()
if len(args) != 2 {
log.Fatal("❌ 错误:需要恰好两个参数 —— 源文件路径和目标文件路径")
}
srcFile, destFile := args[0], args[1]
// 执行对应操作
if *encryptFlag {
encryptFileData(srcFile, destFile)
}
if *decryptFlag {
decryptFileData(srcFile, destFile)
}
}关键改进说明:
- ✅ 标志驱动逻辑:通过 flag.Bool 显式声明 -encrypt / -decrypt 开关,语义清晰;
- ✅ 参数校验:检查是否至少启用一个模式、是否冲突、是否提供完整文件路径;
- ✅ 安全性提示:注释强调密钥硬编码的风险(生产中应使用 crypto/rand 生成密钥 + 安全存储);
- ✅ 健壮 I/O:使用 0644 替代 0755(文件无需执行权限),并统一错误处理与日志;
- ✅ 用户体验:支持 yourtool -h 自动输出用法,例如:
$ go run main.go -h Usage of main: -decrypt 启用解密模式 -encrypt 启用加密模式
使用示例:
# 加密 test.txt → encrypted.bin $ go run main.go -encrypt test.txt encrypted.bin # 解密 encrypted.bin → decrypted.txt $ go run main.go -decrypt encrypted.bin decrypted.txt
? 提示:后续可进一步增强——添加 -key-file 支持外部密钥、-iv 自定义初始化向量、或使用 cobra 库构建更复杂的 CLI 结构。但对初学者而言,flag 包已足够简洁可靠。


















