文件系统、终端与端口
读写文件、操作目录、监听变更、上传下载,使用 PTY 交互终端,并通过 getHost 暴露端口。
每个沙箱都有一套完整、可读写的 Linux 文件系统。所有文件操作通过 sandbox.files 完成;交互式终端通过 sandbox.pty;对外暴露服务通过 sandbox.getHost(port)。
读文件
读取默认返回文本;通过 format 选项可读为二进制或流:
// 文本(默认)
const text = await sandbox.files.read('/home/user/hello.txt');
// 二进制
const bytes = await sandbox.files.read('/bin/app', { format: 'bytes' });
// -> Uint8Array
// 流(适合大文件)
const stream = await sandbox.files.read('/data/big.csv', { format: 'stream' });
// -> ReadableStream<Uint8Array># 文本(默认)
text = sandbox.files.read("/home/user/hello.txt")
# 二进制
data = sandbox.files.read("/bin/app", format="bytes") # -> bytes// 文本
text, _ := sandbox.Files.Read(ctx, "/home/user/hello.txt", nil)
// 二进制
data, _ := sandbox.Files.ReadBytes(ctx, "/bin/app", nil) // -> []byte
// 流(适合大文件)
rc, _ := sandbox.Files.ReadStream(ctx, "/data/big.csv", nil) // -> io.ReadCloser
defer rc.Close()Go 把 TS 的 read({format}) 拆成 Read(string)、ReadBytes([]byte)、ReadStream(io.ReadCloser)。
写文件
写入单个文件返回写入后的 EntryInfo。数据可以是字符串、字节、Blob 或流:
// 单文件
const info = await sandbox.files.write('/tmp/hello.txt', 'Hello World!');
// 批量写入
const infos = await sandbox.files.write([
{ path: '/tmp/a.txt', data: 'aaa' },
{ path: '/tmp/b.txt', data: 'bbb' },
]);from tensor_box import WriteEntry
# 单文件
info = sandbox.files.write("/tmp/hello.txt", "Hello World!")
# 批量写入
infos = sandbox.files.write([
WriteEntry("/tmp/a.txt", "aaa"),
WriteEntry("/tmp/b.txt", b"\x00\x01"),
])// 字符串单文件
info, _ := sandbox.Files.WriteString(ctx, "/tmp/hello.txt", "Hello World!", nil)
// 字节单文件
sandbox.Files.Write(ctx, "/tmp/blob.bin", []byte{0, 1, 2}, nil)
// 批量写入
infos, _ := sandbox.Files.WriteFiles(ctx, []tensorbox.WriteEntry{
{Path: "/tmp/a.txt", Data: []byte("aaa")},
{Path: "/tmp/b.txt", Data: []byte("bbb")},
}, nil)目录与元数据操作
// 列目录
const entries = await sandbox.files.list('/home/user');
// EntryInfo[]: { name, path, type: 'file' | 'dir', size, mode, permissions, owner, ... }
// 创建目录(含父目录)
await sandbox.files.makeDir('/home/user/project/src');
// 判断是否存在
const ok = await sandbox.files.exists('/home/user/project');
// 重命名 / 移动
await sandbox.files.rename('/tmp/old.txt', '/tmp/new.txt');
// 删除文件或目录
await sandbox.files.remove('/tmp/new.txt');
// 获取单个文件 / 目录的信息
const stat = await sandbox.files.getInfo('/home/user/hello.txt');# 列目录
entries = sandbox.files.list("/home/user")
# [EntryInfo(name, path, type, size, ...), ...]
# 创建目录(含父目录)
sandbox.files.make_dir("/home/user/project/src")
# 判断是否存在
ok = sandbox.files.exists("/home/user/project")
# 重命名 / 移动
sandbox.files.rename("/tmp/old.txt", "/tmp/new.txt")
# 删除文件或目录
sandbox.files.remove("/tmp/new.txt")
# 获取单个文件 / 目录的信息
stat = sandbox.files.get_info("/home/user/hello.txt")// 列目录
entries, _ := sandbox.Files.List(ctx, "/home/user", nil)
// []EntryInfo{ {Name, Path, Type, Size, ...}, ... }
// 创建目录(含父目录)
sandbox.Files.MakeDir(ctx, "/home/user/project/src", nil)
// 判断是否存在
ok := sandbox.Files.Exists(ctx, "/home/user/project", nil)
// 重命名 / 移动
sandbox.Files.Rename(ctx, "/tmp/old.txt", "/tmp/new.txt", nil)
// 删除文件或目录
sandbox.Files.Remove(ctx, "/tmp/new.txt", nil)
// 获取单个文件 / 目录的信息
stat, _ := sandbox.Files.GetInfo(ctx, "/home/user/hello.txt", nil)监听目录变更
watchDir 实时回调目录内的 create / write / remove 事件,返回一个可停止监听的句柄:
const watcher = await sandbox.files.watchDir(
'/home/user/project',
(event) => {
// event: { type: 'create' | 'write' | 'remove', name, path }
console.log(event.type, event.path);
},
{ recursive: true }, // 可选:递归监听子目录
);
// 停止监听
watcher.stop();handle = sandbox.files.watch_dir(
"/home/user/project",
lambda ev: print(ev.type, ev.path), # ev.type in {"create", "write", "remove"}
recursive=True,
)
# 停止监听
handle.stop()watcher, _ := sandbox.Files.WatchDir(ctx, "/home/user/project",
func(ev tensorbox.WatchEvent) {
// ev.Type in {"create", "write", "remove"}
fmt.Println(ev.Type, ev.Path)
},
&tensorbox.WatchOptions{Recursive: true})
// 停止监听
watcher.Stop()目录监听走 X-API-Key 鉴权的 WebSocket(/sandboxes/:id/files/watch)。Python 需要安装 websocket-client、Go 依赖 gorilla/websocket;若路由不可用(升级 404),监听会通过 onExit 回调干净结束。
上传与下载
对于较大的文件或浏览器 / 外部工具直传,SDK 可以生成上传 / 下载 URL:
// 生成一个下载该路径文件的 URL
const dlUrl = sandbox.downloadUrl('/home/user/output.zip');
// 生成一个上传文件到沙箱的 URL
const upUrl = sandbox.uploadUrl('/home/user/input.zip');dl_url = sandbox.download_url("/home/user/output.zip")
up_url = sandbox.upload_url("/home/user/input.zip")dlURL := sandbox.DownloadURL("/home/user/output.zip")
upURL := sandbox.UploadURL("/home/user/input.zip")日常读写直接用 files.read / files.write 即可;downloadUrl / uploadUrl 适合把链接交给浏览器、curl 或第三方服务做直传,避免数据绕经你的应用进程。
PTY 交互终端
需要带 TTY 的真正交互式终端(行编辑、vim、top 等全屏程序),用 sandbox.pty。create 建立一个 PTY 会话,通过 onData 接收输出,返回 PtyHandle:
const pty = await sandbox.pty.create({
cols: 120,
rows: 40,
onData: (data) => process.stdout.write(data), // data: Uint8Array
});
// 写入输入(可传字符串或 Uint8Array)
pty.sendInput('ls -la\n');
// 终端尺寸变化时同步
pty.resize({ cols: 200, rows: 50 });
// 结束会话
await pty.kill();PtyHandle 提供 pid、sendInput(data)、resize({ cols, rows })、kill() 以及 isOpen。
pty = sandbox.pty.create(
cols=120, rows=40,
on_data=lambda b: print(b.decode(), end=""),
)
pty.send_input("ls -la\n")
pty.resize(cols=200, rows=50)
pty.kill()PtyHandle 提供 send_input(data)、resize(cols, rows)、kill() 以及 is_open。
pty, _ := sandbox.Pty.Create(ctx, &tensorbox.PtyOptions{
Cols: 120, Rows: 40,
OnData: func(b []byte) { fmt.Print(string(b)) },
})
pty.SendInput([]byte("ls -la\n"))
pty.Resize(200, 50)
pty.Kill()*PtyHandle 提供 SendInput、Resize、Kill、IsOpen。
# 直接进入交互式 PTY(Ctrl-D 退出)
tensor-box sandbox terminal "$sbx" --shell /bin/bash这正是控制台「终端」标签页接入 xterm 的底层方式。PTY WebSocket 通过 X-API-Key 升级请求头鉴权。
暴露端口
沙箱内启动的服务(HTTP、WebSocket 等)可通过 getHost(port) 拿到一个对外可访问的主机名:
// 在沙箱内启动一个服务
await sandbox.commands.run('python3 -m http.server 8000', { background: true });
// 拿到该端口对外的主机名
const host = sandbox.getHost(8000);
console.log(`https://${host}`);sandbox.commands.run("python3 -m http.server 8000", background=True)
host = sandbox.get_host(8000)
print(f"https://{host}")sandbox.Commands.RunBackground(ctx, "python3 -m http.server 8000", nil)
host := sandbox.GetHost(8000)
fmt.Printf("https://%s\n", host)getHost(port) 返回的是形如 <sandboxId>-<port>.<你的控制面域名> 的主机名字符串(不含协议),你可以据此拼出完整 URL 访问沙箱内服务。
关于 per-port 预览的就绪状态:按端口对外路由的预览 ingress(让 getHost 返回的 URL 浏览器直开即可访问沙箱内服务)仍在实现中(对应内部工单 S1.5)。在该能力落地前,getHost(port) 仅返回拼好的主机名/地址字符串本身——它写法正确、便于你提前组装 URL,但此刻直接用浏览器打开尚不可达。需要从沙箱外访问端口时,请在 S1.5 落地前先用 SDK 的命令 / 文件接口,或在你的 Tensor OS 部署侧自行接入反向代理。
Tensor Box 不提供网络白名单 / 防火墙规则之类的出站管控 API。沙箱的隔离来自 microVM 的硬件边界与独立资源配额;如需网络层管控,请在你的 Tensor OS 部署的网络策略层处理。
方法一览
| 方法(TS / Python / Go) | 说明 |
|---|---|
files.read / files.read(format=) / Files.Read·ReadBytes·ReadStream | 读文件:文本(默认)/ 二进制 / 流 |
files.write / files.write / Files.Write·WriteString·WriteFiles | 写单个 / 批量文件,返回 EntryInfo |
files.list / files.list / Files.List | 列目录,返回 EntryInfo[] |
files.makeDir / files.make_dir / Files.MakeDir | 创建目录(含父目录) |
files.exists / files.exists / Files.Exists | 判断路径是否存在 |
files.rename / files.rename / Files.Rename | 重命名 / 移动 |
files.remove / files.remove / Files.Remove | 删除文件或目录 |
files.getInfo / files.get_info / Files.GetInfo | 获取文件 / 目录信息 |
files.watchDir / files.watch_dir / Files.WatchDir | 监听目录变更,返回可 stop 的句柄 |
pty.create / pty.create / Pty.Create | 创建 PTY 会话,返回 PtyHandle |
getHost / get_host / GetHost | 拿到端口对外主机名 |
downloadUrl·uploadUrl / download_url·upload_url / DownloadURL·UploadURL | 生成下载 / 上传 URL |