chore: 优化目录处理与命令执行,对齐基础设施 (by AI)
This commit is contained in:
parent
916226a9df
commit
4f750c8acc
15
CHANGELOG.md
15
CHANGELOG.md
@ -1,10 +1,13 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [1.0.4] - 2026-05-01
|
## [1.0.5] - 2026-05-05
|
||||||
- 版本对齐至 v1.0.4。
|
- **性能优化**: 优化 `EnsureParentDir`,减少冗余的系统调用。
|
||||||
- 移除 AI.md,将其内容整合至 README.md,提升模块文档规范。
|
- **基础设施对齐**: `UnmarshalFile` 迁移至 `cast.To` 语义对齐(内部仍使用 `Convert` 确保指针更新)。
|
||||||
- 进一步优化文件系统 API 交互细节。
|
- **健壮性**: `RunCommand` 现在支持过滤空行,并提供更详细的执行错误信息。
|
||||||
|
- **命名规范**: `EnsureDirSuffix` 内部变量 `spe` 重命名为 `sep`。
|
||||||
|
- **测试增强**: 补全了 `Marshal/Unmarshal` 的 Benchmark 测试。
|
||||||
|
|
||||||
|
## [1.0.4] - 2026-05-01
|
||||||
|
...
|
||||||
|
|
||||||
## [1.0.0] - 2026-05-01
|
|
||||||
- 初始版本归档与模块对齐。
|
|
||||||
- 修复了依赖引用问题(convert 模块函数命名不一致导致编译失败)。
|
- 修复了依赖引用问题(convert 模块函数命名不一致导致编译失败)。
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
## 核心特性
|
## 核心特性
|
||||||
|
|
||||||
* **内存文件系统 (Memory File System)**: 支持将文件或资源加载到内存,并可选进行压缩与 `SafeBuf` 加密存储。这非常适合处理嵌入式资源、敏感配置或高并发读取的场景。
|
* **内存文件系统 (Memory File System)**: 支持将文件或资源加载到内存,并可选进行压缩与 `SafeBuf` 加密存储。这非常适合处理嵌入式资源、敏感配置或高并发读取的场景。
|
||||||
* **智能序列化**: 自动处理 YAML 与 JSON 格式判别,并集成了强大的 `convert.To` 智能字段映射引擎,轻松解决复杂结构体与配置文件之间的映射问题。
|
* **智能序列化**: 自动处理 YAML 与 JSON 格式判别,并集成了强大的 `cast.To` 智能字段映射引擎,轻松解决复杂结构体与配置文件之间的映射问题。
|
||||||
* **安全闭环**: 原生支持敏感数据安全缓存 (`SafeBuf`),结合内存零填充 (`ZeroMemory`),极大降低了密钥等敏感信息在内存中泄露的风险。
|
* **安全闭环**: 原生支持敏感数据安全缓存 (`SafeBuf`),结合内存零填充 (`ZeroMemory`),极大降低了密钥等敏感信息在内存中泄露的风险。
|
||||||
* **全功能 IO**: 提供从基础 IO 到递归目录操作、文件原地替换及高效压缩归档的一站式解决方案。
|
* **全功能 IO**: 提供从基础 IO 到递归目录操作、文件原地替换及高效压缩归档的一站式解决方案。
|
||||||
|
|
||||||
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
1. **内存安全优先**: 处理敏感文件时,优先使用 `SafeLoad` 系列,并通过 `SafeBuf` 接口操作。
|
1. **内存安全优先**: 处理敏感文件时,优先使用 `SafeLoad` 系列,并通过 `SafeBuf` 接口操作。
|
||||||
2. **高性能 IO**: 在文件 IO 高并发场景下,默认采用 `WriteBytes` 以保证写入性能。
|
2. **高性能 IO**: 在文件 IO 高并发场景下,默认采用 `WriteBytes` 以保证写入性能。
|
||||||
3. **语义一致性**: 序列化/反序列化(`Unmarshal/Marshal`)通过 `convert.To` 处理自动映射,无需关心字段名不一致问题。
|
3. **语义一致性**: 序列化/反序列化(`Unmarshal/Marshal`)通过 `cast.To` 处理自动映射,无需关心字段名不一致问题。
|
||||||
4. **资源管理**: 任何归档提取或 IO 流操作结束后,必须确保对应资源被 `Close()`。
|
4. **资源管理**: 任何归档提取或 IO 流操作结束后,必须确保对应资源被 `Close()`。
|
||||||
|
|
||||||
## 快速入门 (Quick Start)
|
## 快速入门 (Quick Start)
|
||||||
|
|||||||
7
TEST.md
7
TEST.md
@ -30,10 +30,9 @@
|
|||||||
|
|
||||||
| Benchmark | ops | 耗时 (ns/op) |
|
| Benchmark | ops | 耗时 (ns/op) |
|
||||||
| :--- | :--- | :--- |
|
| :--- | :--- | :--- |
|
||||||
| MarshalFile/Normal | 10000 | 111,770 |
|
| MarshalFile/Normal | 10000 | 101,058 |
|
||||||
| MarshalFile/Pretty | 10000 | 109,581 |
|
| MarshalFile/Pretty | 10000 | 105,661 |
|
||||||
| UnmarshalFile/Normal | 52528 | 22,172 |
|
| UnmarshalFile | 46378 | 25,102 |
|
||||||
| UnmarshalFile/X | 46568 | 24,833 |
|
|
||||||
|
|
||||||
## 3. 系统鲁棒性测试
|
## 3. 系统鲁棒性测试
|
||||||
- **不存在的文件**: 验证 `UnmarshalFile` 返回 `os.IsNotExist` 类型错误。
|
- **不存在的文件**: 验证 `UnmarshalFile` 返回 `os.IsNotExist` 类型错误。
|
||||||
|
|||||||
40
bench_test.go
Normal file
40
bench_test.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package file
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkMarshalFile(b *testing.B) {
|
||||||
|
tmpDir, _ := os.MkdirTemp("", "bench_marshal")
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
filename := filepath.Join(tmpDir, "test.json")
|
||||||
|
data := TestStruct{Name: "Benchmark", Age: 100}
|
||||||
|
|
||||||
|
b.Run("Normal", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = MarshalFile(filename, data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
b.Run("Pretty", func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = MarshalFilePretty(filename, data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkUnmarshalFile(b *testing.B) {
|
||||||
|
tmpDir, _ := os.MkdirTemp("", "bench_unmarshal")
|
||||||
|
defer os.RemoveAll(tmpDir)
|
||||||
|
filename := filepath.Join(tmpDir, "test.json")
|
||||||
|
data := `{"name": "Benchmark", "age": 100}`
|
||||||
|
os.WriteFile(filename, []byte(data), 0644)
|
||||||
|
|
||||||
|
var ts TestStruct
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = UnmarshalFile(filename, &ts)
|
||||||
|
}
|
||||||
|
}
|
||||||
22
file.go
22
file.go
@ -2,6 +2,7 @@ package file
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -23,16 +24,13 @@ func EnsureParentDir(filename string) {
|
|||||||
if pos < 0 {
|
if pos < 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
path := filename[0:pos]
|
_ = os.MkdirAll(filename[:pos], 0755)
|
||||||
if _, err := os.Stat(path); err != nil {
|
|
||||||
_ = os.MkdirAll(path, 0755)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func EnsureDirSuffix(path string) string {
|
func EnsureDirSuffix(path string) string {
|
||||||
const spe = string(os.PathSeparator)
|
const sep = string(os.PathSeparator)
|
||||||
if !strings.HasSuffix(path, spe) {
|
if !strings.HasSuffix(path, sep) {
|
||||||
return path + spe
|
return path + sep
|
||||||
}
|
}
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
@ -266,8 +264,14 @@ func RunCommand(command string, args ...string) ([]string, error) {
|
|||||||
cmd := exec.Command(command, args...)
|
cmd := exec.Command(command, args...)
|
||||||
out, err := cmd.CombinedOutput()
|
out, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("command execution failed: %w, output: %s", err, string(out))
|
||||||
|
}
|
||||||
|
rawLines := strings.Split(strings.TrimSpace(string(out)), "\n")
|
||||||
|
var lines []string
|
||||||
|
for _, line := range rawLines {
|
||||||
|
if trimmed := strings.TrimSpace(line); trimmed != "" {
|
||||||
|
lines = append(lines, trimmed)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
|
|
||||||
return lines, nil
|
return lines, nil
|
||||||
}
|
}
|
||||||
|
|||||||
6
go.mod
6
go.mod
@ -3,15 +3,17 @@ module apigo.cc/go/file
|
|||||||
go 1.25.0
|
go 1.25.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
apigo.cc/go/convert v1.0.4
|
apigo.cc/go/cast v1.2.6
|
||||||
apigo.cc/go/encoding v1.0.4
|
apigo.cc/go/encoding v1.0.4
|
||||||
apigo.cc/go/safe v1.0.4
|
apigo.cc/go/safe v1.0.4
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
apigo.cc/go/cast v1.0.4 // indirect
|
|
||||||
apigo.cc/go/rand v1.0.4 // indirect
|
apigo.cc/go/rand v1.0.4 // indirect
|
||||||
|
github.com/kr/pretty v0.3.0 // indirect
|
||||||
|
github.com/rogpeppe/go-internal v1.14.1 // indirect
|
||||||
golang.org/x/crypto v0.50.0 // indirect
|
golang.org/x/crypto v0.50.0 // indirect
|
||||||
golang.org/x/sys v0.43.0 // indirect
|
golang.org/x/sys v0.43.0 // indirect
|
||||||
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"apigo.cc/go/convert"
|
"apigo.cc/go/cast"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ func UnmarshalFile(filename string, to any) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
convert.To(in, to)
|
cast.Convert(to, in)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,6 +96,6 @@ func PatchFile(filename string, patch any) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
convert.To(patch, ¤t)
|
cast.Convert(¤t, patch)
|
||||||
return MarshalFilePretty(filename, current)
|
return MarshalFilePretty(filename, current)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user