作者:坚果 (Jianguo) 日期:2025-11-03 项目:filesize - 文件大小格式化工具库
本文详细记录了从零开始开发一个仓颉三方库的完整过程,包括从克隆模板、编写代码、解决问题到最终发布的每一个步骤。通过这篇文章,你将学会如何创建一个标准的、文档完善的仓颉三方库。
在日常开发中,我们经常需要将文件大小(字节数)转换为人类可读的格式,比如将 1048576 显示为 1.05 MB。虽然这是一个简单的需求,但如果每个项目都重复实现一遍,不仅浪费时间,还容易出错。因此,我决定开发一个专门的仓颉三方库来解决这个问题。
开始之前,确保你的开发环境已准备就绪:
# 检查仓颉编译器版本
cjc --version
# 要求: >= 1.0.3
# 检查包管理器
cjpm --version
# 确认环境变量
echo $CANGJIE_HOME
仓颉官方提供了标准的三方库模板,可以帮助我们快速启动项目:
# 克隆模板仓库
git clone git@gitcode.com:cj-awaresome/template.git filesize
cd filesize
# 查看项目结构
tree -L 2
模板的目录结构:
template/
├── README.md # 项目说明(需要修改)
├── CHANGELOG.md # 版本日志(需要修改)
├── LICENSE # 开源协议(需要修改)
├── README.OpenSource # 开源声明(需要修改)
├── cjpm.toml # 包配置(需要修改)
├── doc/ # 文档目录
│ ├── design.md # 设计文档(需要重写)
│ ├── feature_api.md # API文档(需要重写)
│ └── assets/ # 资源文件
├── src/ # 源码目录
│ └── Template.cj # 模板源码(需要替换)
└── test/ # 测试目录
├── HLT/ # 高层测试
└── LLT/ # 低层测试
这是项目的核心配置文件,需要修改为我们的库信息:
[dependencies]
[package]
cjc-version = "1.0.3"
compile-option = ""
description = "文件大小格式化工具库 - 将字节数转换为人类可读的格式"
link-option = ""
name = "filesize" # 修改包名
output-type = "static" # 三方库使用 static
src-dir = ""
target-dir = ""
version = "1.0.0" # 设置版本号
package-configuration = {}
关键点:
name: 包名要与功能相关,简洁明了output-type: 三方库使用 "static",不是 "executable"description: 简短说明库的功能# 修改远程仓库地址
git remote set-url origin git@gitcode.com:cj-awaresome/filesize.git
# 验证修改
git remote -v
删除模板文件,创建我们的 filesize.cj:
rm src/Template.cj
touch src/filesize.cj
开始编写核心功能。这是一个迭代过程,我先写了一个基础版本:
package filesize
import std.math.*
// 主格式化函数
public func formatFileSize(size: Int64): String {
let base = 10
let roundDigits = 2
let bits = false
let result = calculateFileSize(size, base, roundDigits, bits)
return result
}
// 核心计算逻辑
internal func calculateFileSize(size: Int64, base: Int, roundDigits: Int, bits: Bool): String {
let ceil = if (base == 10) { 1000 } else { 1024 }
let num = Float64(size)
var e: Int64 = 0
// 计算指数
if (num > 0.0) {
let logVal = log(num) / log(Float64(ceil))
let floorVal = floor(logVal)
e = Int64(floorVal)
if (e < 0) { e = 0 }
if (e > 8) { e = 8 }
}
// 计算值
var val = if (base == 2) {
num / pow(2.0, Float64(e * 10))
} else {
num / pow(1000.0, Float64(e))
}
if (bits) { val = val * 8.0 }
// 四舍五入
let factor = pow(10.0, Float64(roundDigits))
let rounded = round(val * factor) / factor
// 获取单位
let unit = getUnit(e)
return "${rounded} ${unit}"
}
// 单位映射
private func getUnit(exponent: Int64): String {
if (exponent == 0) { return "B" }
if (exponent == 1) { return "KB" }
if (exponent == 2) { return "MB" }
if (exponent == 3) { return "GB" }
if (exponent == 4) { return "TB" }
if (exponent == 5) { return "PB" }
if (exponent == 6) { return "EB" }
if (exponent == 7) { return "ZB" }
if (exponent == 8) { return "YB" }
return "B"
}
cjpm build
错误信息:
Error: the package name in /Users/jianguo/Desktop/cangjie/tpc/template-1/src is wrong,
the right name should be 'filesize'
问题分析: 这是仓颉语言的一个重要特性 - 每个源文件都必须声明它所属的包!我在文件开头添加了 package filesize,但编译器还在报错。
经过排查,发现还有其他文件(constants.cj、types.cj)也缺少包声明。
解决方案: 确保所有 .cj 文件的第一行都是包声明:
package filesize
// 其他代码...
错误信息:
Error: root package 'filesize' imports package 'std.string' in its source code,
but it is not added as a dependency in cjpm.toml
问题分析: 我引用了 std.string.*,但实际上仓颉标准库中并不存在这个模块!
解决方案: 删除不存在的导入:
package filesize
import std.math.*
// import std.string.* ❌ 删除这一行
在开发过程中,我发现我最初写的一些语法在仓颉中不支持:
问题 1:默认参数
// ❌ 错误:仓颉不支持默认参数
public func formatFileSize(size: Int64, options: Map<String, Any> = {}): String
// ✅ 正确:使用函数重载或固定参数
public func formatFileSize(size: Int64): String
问题 2:三元运算符
// ❌ 错误:不支持 ? : 语法
let ceil = base == 10 ? 1000 : 1024
// ✅ 正确:使用 if 表达式
let ceil = if (base == 10) { 1000 } else { 1024 }
问题 3:类型转换方法
// ❌ 错误:方法名不对
let num = size.toFloat64()
// ✅ 正确:使用类型构造函数
let num = Float64(size)
修复所有问题后:
cjpm build
# 输出:cjpm build success ✅
rm -rf test/HLT test/LLT
touch test/test.cj
package filesize.test
import filesize.*
test "格式化 1KB" {
let result = formatFileSize(1024)
println("1024 bytes = ${result}")
assert(result.contains("KB"))
}
test "格式化 1MB" {
let result = formatFileSize(1024 * 1024)
println("1MB = ${result}")
assert(result.contains("MB"))
}
test "格式化 1GB" {
let result = formatFileSize(1024 * 1024 * 1024)
println("1GB = ${result}")
assert(result.contains("GB"))
}
cjpm test
# 输出:cjpm test success ✅
采用 Apache 2.0 开源协议:
# 创建完整的 Apache 2.0 协议文件
# 并在文件头部添加版权声明
Apache License
Version 2.0, January 2004
Copyright 2025 坚果 (Jianguo)
Licensed under the Apache License, Version 2.0...
编写专业的项目说明文档,包括:
# filesize - 文件大小格式化库
## 介绍
简要说明库的功能...
## 项目特性
- ✨ 简单易用
- 📊 自动单位转换
...
## 使用说明
### 安装
### 使用示例
## 开源协议
Apache License 2.0
记录版本历史:
# 更新日志
## [1.0.0] - 2025-11-03
### Feature
- 实现文件大小格式化核心功能
- 支持 KB、MB、GB 等单位自动转换
...
doc/design.md - 设计文档:
doc/feature_api.md - API 文档:
[
{
"Name": "filesize",
"License": "Apache License 2.0",
"License File": "LICENSE",
"Version": "1.0.0",
"Owner": "jianguo@nutpi.net",
"Upstream URL": "https://gitcode.com/cj-awaresome/filesize",
"Description": "仓颉语言的文件大小格式化工具库"
}
]
# 创建 .gitignore 文件
cat > .gitignore << 'EOF'
# 编译输出
target/
cjpm.lock
# IDE 配置
.vscode/
.idea/
*.swp
# 系统文件
.DS_Store
EOF
git add -A
git status
查看待提交的文件:
Changes to be committed:
new file: .gitignore
modified: CHANGELOG.md
modified: LICENSE
modified: README.OpenSource
modified: README.md
modified: cjpm.toml
deleted: src/Template.cj
new file: src/filesize.cj
modified: doc/design.md
modified: doc/feature_api.md
deleted: test/HLT/testcase0001.cj
deleted: test/LLT/testcase0001.cj
new file: test/test.cj
git commit -m "实现 filesize 库:文件大小格式化工具
- 添加 filesize.cj 实现文件大小格式化功能
- 支持 KB, MB, GB 等单位自动转换
- 更新 cjpm.toml 配置,包名改为 filesize
- 添加基础测试用例
- 完善所有文档和开源协议
- 删除模板文件,添加 .gitignore"
git push origin main
输出:
remote: Start Git Hooks Checking [PASSED]
To gitcode.com:cj-awaresome/filesize.git
* [new branch] main -> main
成功!🎉
第一次运行时发现有未使用变量的警告:
warning: unused variable:'standard'
解决方案:删除未使用的参数
git commit -m "修复编译警告,移除未使用的参数"
git push origin main
三方库不应该包含可执行入口:
// ❌ 删除 main() 函数
main() {
println("Testing...")
}
git commit -m "完善三方库配置 - 移除 main() 函数"
git push origin main
.cj 文件必须以 package 包名 开头cjpm.toml 中的 name 一致if (condition) { value } else { value } 而不是三元运算符Float64(value)output-type 必须是 "static"main() 函数std.math.*std.string.* 模块错误 | 原因 | 解决方案 |
|---|---|---|
package name is wrong | 缺少包声明 | 添加 package 包名 |
imports package 'std.xxx' but not in dependencies | 模块不存在或未声明依赖 | 检查模块是否存在 |
expected ',' or ')' | 语法错误(如默认参数) | 使用仓颉支持的语法 |
undeclared identifier | 类型转换方法错误 | 使用类型构造函数 |
经过几个小时的开发,我们完成了一个标准的仓颉三方库:
filesize.cj,64 行)test.cj,22 行)其他开发者可以这样使用我们的库:
// 在 cjpm.toml 中添加依赖
[dependencies.filesize]
git = "git@gitcode.com:cj-awaresome/filesize.git"
// 在代码中使用
import filesize.*
main() {
let size = formatFileSize(1048576)
println(size) // 输出: 1.05 MB
}
从零开始开发一个仓颉三方库并不难,关键是要:
希望这篇文章能帮助更多开发者参与到仓颉生态建设中来。如果你也想开发自己的三方库,不妨从这个模板开始,创造属于你的优秀作品!
作者: 坚果 (Jianguo) 项目: filesize v1.0.0 日期: 2025-11-03 协议: Apache License 2.0