文件管理
通过 sb.Files() 进行文件读写、批量操作、目录管理和文件变更监听。
写入文件
_, err := sb.Files().Write(ctx, "/tmp/hello.txt", []byte("Hello from Go SDK!\n"))
if err != nil {
log.Fatalf("写入文件失败: %v", err)
}
Write 返回 *EntryInfo,包含写入后的文件元信息。
读取文件
读取为字节数组
content, err := sb.Files().Read(ctx, "/tmp/hello.txt")
if err != nil {
log.Fatalf("读取文件失败: %v", err)
}
fmt.Printf("文件内容: %s", string(content))
读取为字符串
text, err := sb.Files().ReadText(ctx, "/tmp/hello.txt")
if err != nil {
log.Fatalf("ReadText 失败: %v", err)
}
fmt.Printf("文件内容: %s", text)
流式读取
适用于大文件,避免一次性加载到内存。
rc, err := sb.Files().ReadStream(ctx, "/tmp/hello.txt")
if err != nil {
log.Fatalf("ReadStream 失败: %v", err)
}
defer rc.Close()
data, err := io.ReadAll(rc)
if err != nil {
log.Fatalf("读取流失败: %v", err)
}
fmt.Printf("内容: %s", string(data))
批量写入文件
一次写入多个文件,减少网络往返。
files := []sandbox.WriteEntry{
{Path: "/tmp/a.txt", Data: []byte("content A")},
{Path: "/tmp/b.txt", Data: []byte("content B")},
{Path: "/tmp/c.txt", Data: []byte("content C")},
}
infos, err := sb.Files().WriteFiles(ctx, files)
if err != nil {
log.Fatalf("批量写入失败: %v", err)
}
for _, fi := range infos {
fmt.Printf("已写入: %s (%d bytes)\n", fi.Path, fi.Size)
}
目录操作
创建目录
_, err := sb.Files().MakeDir(ctx, "/tmp/mydir")
if err != nil {
log.Fatalf("创建目录失败: %v", err)
}
列出目录内容
entries, err := sb.Files().List(ctx, "/tmp")
if err != nil {
log.Fatalf("列出目录失败: %v", err)
}
for _, e := range entries {
fmt.Printf("%s %s (%s, %d bytes)\n", e.Type, e.Name, e.Permissions, e.Size)
}
可以指定递归深度:
entries, err := sb.Files().List(ctx, "/tmp", sandbox.WithDepth(3))
文件管理操作
检查文件是否存在
exists, err := sb.Files().Exists(ctx, "/tmp/hello.txt")
if err != nil {
log.Fatalf("Exists 失败: %v", err)
}
fmt.Printf("文件是否存在: %v\n", exists)
获取文件信息
info, err := sb.Files().GetInfo(ctx, "/tmp/hello.txt")
if err != nil {
log.Fatalf("GetInfo 失败: %v", err)
}
fmt.Printf("名称: %s, 类型: %s, 大小: %d, 权限: %s\n",
info.Name, info.Type, info.Size, info.Permissions)
EntryInfo 包含以下字段:
| 字段 | 类型 | 说明 |
|---|---|---|
Name |
string |
文件名 |
Type |
FileType |
文件类型(file、dir、unknown) |
Path |
string |
完整路径 |
Size |
int64 |
文件大小(字节) |
Mode |
uint32 |
文件模式 |
Permissions |
string |
权限字符串 |
Owner |
string |
所有者 |
Group |
string |
所属组 |
ModifiedTime |
time.Time |
修改时间 |
SymlinkTarget |
*string |
符号链接目标 |
重命名文件
renamed, err := sb.Files().Rename(ctx, "/tmp/old.txt", "/tmp/new.txt")
if err != nil {
log.Fatalf("Rename 失败: %v", err)
}
fmt.Printf("重命名为: %s\n", renamed.Path)
删除文件
if err := sb.Files().Remove(ctx, "/tmp/hello.txt"); err != nil {
log.Fatalf("Remove 失败: %v", err)
}
文件系统选项
| 选项 | 适用方法 | 说明 |
|---|---|---|
WithUser(string) |
所有文件操作 | 设置操作用户(默认 user) |
WithDepth(uint32) |
List |
设置递归深度(默认 1) |
WithListUser(string) |
List |
设置列目录的用户 |
WithRecursive(bool) |
WatchDir |
是否递归监听子目录 |
监听目录变更
WatchDir 实时监听目录中的文件变更事件。
wh, err := sb.Files().WatchDir(ctx, "/tmp/watch", sandbox.WithRecursive(true))
if err != nil {
log.Fatalf("WatchDir 失败: %v", err)
}
// 接收文件变更事件
for ev := range wh.Events() {
fmt.Printf("事件: type=%s, name=%s\n", ev.Type, ev.Name)
}
// 停止监听
wh.Stop()
if err := wh.Err(); err != nil {
log.Printf("监听错误: %v", err)
}
事件类型
| 事件类型 | 说明 |
|---|---|
create |
文件或目录被创建 |
write |
文件被写入 |
remove |
文件或目录被删除 |
rename |
文件或目录被重命名 |
chmod |
文件或目录权限被修改 |
超时收集事件
wh, _ := sb.Files().WatchDir(ctx, "/tmp/watch", sandbox.WithRecursive(true))
timer := time.NewTimer(3 * time.Second)
defer timer.Stop()
loop:
for {
select {
case ev, ok := <-wh.Events():
if !ok {
break loop
}
fmt.Printf("事件: %s %s\n", ev.Type, ev.Name)
case <-timer.C:
break loop
}
}
wh.Stop()
文件下载和上传 URL
获取带签名的文件操作 URL,可用于浏览器直接下载/上传。
// 下载 URL
downloadURL := sb.DownloadURL("/tmp/hello.txt")
fmt.Printf("下载 URL: %s\n", downloadURL)
// 上传 URL(POST multipart/form-data)
uploadURL := sb.UploadURL("/tmp/upload.txt")
fmt.Printf("上传 URL: %s\n", uploadURL)
可以指定选项:
// 自定义用户和签名过期时间
downloadURL := sb.DownloadURL("/tmp/hello.txt",
sandbox.WithFileUser("root"),
sandbox.WithSignatureExpiration(600), // 600 秒
)
完整示例
package main
import (
"context"
"fmt"
"log"
"os"
"time"
"github.com/qiniu/go-sdk/v7/sandbox"
)
func main() {
c, err := sandbox.NewClient(&sandbox.Config{
APIKey: os.Getenv("QINIU_API_KEY"),
Endpoint: os.Getenv("QINIU_SANDBOX_API_URL"),
})
if err != nil {
log.Fatalf("创建客户端失败: %v", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
timeout := int32(120)
sb, _, err := c.CreateAndWait(ctx, sandbox.CreateParams{
TemplateID: "base",
Timeout: &timeout,
}, sandbox.WithPollInterval(2*time.Second))
if err != nil {
log.Fatalf("创建沙箱失败: %v", err)
}
defer sb.Kill(ctx)
// 写入文件
sb.Files().Write(ctx, "/tmp/hello.txt", []byte("Hello from Go SDK!\n"))
// 读取文件
content, _ := sb.Files().Read(ctx, "/tmp/hello.txt")
fmt.Printf("文件内容: %s", string(content))
// 批量写入
files := []sandbox.WriteEntry{
{Path: "/tmp/a.txt", Data: []byte("file A")},
{Path: "/tmp/b.txt", Data: []byte("file B")},
}
sb.Files().WriteFiles(ctx, files)
// 创建目录
sb.Files().MakeDir(ctx, "/tmp/mydir")
// 列出目录
entries, _ := sb.Files().List(ctx, "/tmp")
fmt.Printf("/tmp 目录: %d 项\n", len(entries))
for _, e := range entries {
fmt.Printf(" %s %s (%d bytes)\n", e.Type, e.Name, e.Size)
}
// 文件管理
exists, _ := sb.Files().Exists(ctx, "/tmp/hello.txt")
fmt.Printf("文件存在: %v\n", exists)
info, _ := sb.Files().GetInfo(ctx, "/tmp/hello.txt")
fmt.Printf("文件信息: %s %d bytes\n", info.Name, info.Size)
sb.Files().Rename(ctx, "/tmp/b.txt", "/tmp/b-renamed.txt")
sb.Files().Remove(ctx, "/tmp/b-renamed.txt")
// 文件 URL
fmt.Printf("下载 URL: %s\n", sb.DownloadURL("/tmp/hello.txt"))
}
文档反馈
(如有产品使用问题,请 提交工单)