golang抽象文件存储插件库afs支持内存/SCP/ZIP/TAR/云存储(S3/GS)操作

Golang 抽象文件存储插件库 afs 支持内存/SCP/ZIP/TAR/云存储(S3/GS)操作

简介

afs (Abstract File Storage) 是一个 Go 语言库,提供了统一的 API 来操作多种存储系统,包括本地文件系统、内存、SCP、ZIP、TAR 以及云存储(如 AWS S3 和 Google Cloud Storage)。使用共享 API 可以大大简化对不同存储系统的操作,同时还能模拟存储相关的错误(如认证错误或 EOF)来测试应用程序的错误处理能力。

主要功能

CRUD 操作

List(ctx context.Context, URL string, options ...Option) ([]Object, error)

Walk(ctx context.Context, URL string, handler OnVisit, options ...Option) error

Open(ctx context.Context, object Object, options ...Option) (io.ReadCloser, error)

OpenURL(ctx context.Context, URL string, options ...Option) (io.ReadCloser, error)

Upload(ctx context.Context, URL string, mode os.FileMode, reader io.Reader, options ...Option) error

Create(ctx context.Context, URL string, mode os.FileMode, isDir bool, options ...Option) error

Delete(ctx context.Context, URL string, options ...Option) error

批量上传

type Upload func(ctx context.Context, parent string, info os.FileInfo, reader io.Reader) error
 
Uploader(ctx context.Context, URL string, options ...Option) (Upload, io.Closer, error)

实用工具

Copy(ctx context.Context, sourceURL, destURL string, options ...Option) error

Move(ctx context.Context, sourceURL, destURL string, options ...Option) error

NewWriter(ctx context.Context, URL string, mode os.FileMode, options ...storage.Option) (io.WriteCloser, error)

DownloadWithURL(ctx context.Context, URL string, options ...Option) ([]byte, error)

Download(ctx context.Context, object Object, options ...Option) ([]byte, error)

使用示例

下载内容

func main() {
    fs := afs.New()
    ctx := context.Background()
    objects, err := fs.List(ctx, "/tmp/folder")
    if err != nil {
        log.Fatal(err)
    }
    for _, object := range objects {
        fmt.Printf("%v %v\n", object.Name(), object.URL())
        if object.IsDir() {
            continue
        }
        reader, err := fs.Open(ctx, object)
        if err != nil {
            log.Fatal(err)
        }
        data, err := ioutil.ReadAll(reader)
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("%s\n", data)
    }
}

上传内容

func main() {
    fs := afs.New()
    ctx := context.Background()
    keyAuth, err := scp.LocalhostKeyAuth("")
    if err != nil {
        log.Fatal(err)
    }
    err = fs.Init(ctx, "scp://127.0.0.1:22/", keyAuth)
    if err != nil {
        log.Fatal(err)
    }	
    err = fs.Upload(ctx, "scp://127.0.0.1:22/folder/asset.txt", 0644, strings.NewReader("test me"))
    if err != nil {
        log.Fatal(err)
    }
    ok, err := fs.Exists(ctx, "scp://127.0.0.1:22/folder/asset.txt")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("has file: %v\n", ok)
    _ = fs.Delete(ctx, "scp://127.0.0.1:22/folder/asset.txt")
}

使用 Writer 上传内容

func main() {
    fs := afs.New()
    ctx := context.Background()
    keyAuth, err := scp.LocalhostKeyAuth("")
    if err != nil {
        log.Fatal(err)
    }
    err = fs.Init(ctx, "scp://127.0.0.1:22/", keyAuth)
    if err != nil {
        log.Fatal(err)
    }	
    writer = fs.NewWriter(ctx, "scp://127.0.0.1:22/folder/asset.txt", 0644)
    _, err := writer.Write([]byte("test me")))
    if err != nil {
        log.Fatal(err)
    }
    err = writer.Close()
    if err != nil {
        log.Fatal(err)
    }
    ok, err := fs.Exists(ctx, "scp://127.0.0.1:22/folder/asset.txt")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("has file: %v\n", ok)
    _ = fs.Delete(ctx, "scp://127.0.0.1:22/folder/asset.txt")
}

数据复制

func main() {
    fs := afs.New()
    ctx := context.Background()
    keyAuth, err := scp.LocalhostKeyAuth("")
    if err != nil {
        log.Fatal(err)
    }
    err = fs.Copy(ctx, "s3://mybucket/myfolder", "scp://127.0.0.1/tmp", option.NewSource(), option.NewDest(keyAuth))
    if err != nil {
        log.Fatal(err)
    }
}

归档内容

func main() {
    secretPath := path.Join(os.Getenv("HOME"), ".secret", "gcp-e2e.json")
    auth, err := gs.NewJwtConfig(option.NewLocation(secretPath))
    if err != nil {
        return
    }
    sourceURL := "mylocalPath/"
    destURL := "gs:mybucket/test.zip/zip://localhost/dir1"
    fs := afs.New()
    ctx := context.Background()
    err = fs.Copy(ctx, sourceURL, destURL, option.NewDest(auth))
    if err != nil {
        log.Fatal(err)
    }
}

归档遍历器

func main() {
    ctx := context.Background()
    fs := afs.New()
    walker := tar.NewWalker(s3afs.New())
    err := fs.Copy(ctx, "/tmp/test.tar", "s3:///dest/folder/test", walker)
    if err != nil {
        log.Fatal(err)
    }
}

归档上传器

func main() {
    ctx := context.Background()
    fs := afs.New()
    uploader := zip.NewBatchUploader(gsafs.New())
    err := fs.Copy(ctx, "gs:///tmp/test/data", "/tmp/data.zip", uploader)
    if err != nil {
        log.Fatal(err)
    }
}

数据移动

func main() {
    fs := afs.New()
    ctx := context.Background()
    keyAuth, err := scp.LocalhostKeyAuth("")
    if err != nil {
        log.Fatal(err)
    }
    err = fs.Move(ctx, "/tmp/transient/app", "scp://127.0.0.1/tmp", option.NewSource(), option.NewDest(keyAuth))
    if err != nil {
        log.Fatal(err)
    }
}

批量上传

func main() {
    fs := afs.New()
    ctx := context.Background()
    upload, closer, err := fs.Uploader(ctx, "/tmp/clone")
    if err != nil {
        log.Fatal(err)
    }
    defer closer.Close()
    assets := []*asset.Resource{
        asset.NewFile("asset1.txt", []byte("test 1"), 0644),
        asset.NewFile("asset2.txt", []byte("test 2"), 0644),
        asset.NewDir("folder1", file.DefaultDirOsMode),
        asset.NewFile("folder1/asset1.txt", []byte("test 3"), 0644),
        asset.NewFile("folder1/asset2.txt", []byte("test 4"), 0644),
    }
    for _, asset := range assets {
        relative := ""
        var reader io.Reader
        if strings.Contains(asset.Name, "/") {
            relative, _ = path.Split(asset.Name)
        }
        if !asset.Dir {
            reader = bytes.NewReader(asset.Data)
        }
        err = upload(ctx, relative, asset.Info(), reader)
        if err != nil {
            log.Fatal(err)
        }
    }
}

存储实现

  • 文件系统
  • 内存存储
  • SSH - SCP
  • HTTP
  • Tar
  • Zip
  • GCP - GS
  • AWS - S3

许可证

源代码根据 Apache License, Version 2 许可提供,详见 LICENSE 文件。


更多关于golang抽象文件存储插件库afs支持内存/SCP/ZIP/TAR/云存储(S3/GS)操作的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang抽象文件存储插件库afs支持内存/SCP/ZIP/TAR/云存储(S3/GS)操作的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 抽象文件存储插件库 afs 介绍

afs 是一个 Go 语言编写的抽象文件系统库,它提供了统一的接口来操作多种存储后端,包括内存、SCP、ZIP、TAR 和各种云存储(S3/GS等)。

主要特性

  • 统一 API 操作不同存储后端
  • 支持本地文件系统、内存、SCP、ZIP、TAR
  • 支持云存储如 AWS S3、Google Cloud Storage
  • 支持文件读写、列表、删除等常见操作
  • 支持流式读写

安装

go get github.com/viant/afs

基本使用示例

1. 初始化不同存储后端

import (
	"github.com/viant/afs"
	"github.com/viant/afs/file"
	"github.com/viant/afs/mem"
	"github.com/viant/afs/storage"
	"github.com/viant/afs/url"
)

// 初始化内存存储
memStorage := afs.New()
memService := mem.Singleton()

// 初始化本地文件系统
fileStorage := afs.New()
fileService := file.Singleton()

// 初始化S3存储 (需要配置AWS凭证)
s3Storage := afs.New()
s3Service := storage.S3()

2. 文件操作示例

// 写入文件
func writeFile(service afs.Service, URL string, data []byte) error {
	return service.Upload(context.Background(), URL, 0644, bytes.NewReader(data))
}

// 读取文件
func readFile(service afs.Service, URL string) ([]byte, error) {
	reader, err := service.Download(context.Background(), URL)
	if err != nil {
		return nil, err
	}
	defer reader.Close()
	return ioutil.ReadAll(reader)
}

// 列出文件
func listFiles(service afs.Service, URL string) ([]storage.Object, error) {
	return service.List(context.Background(), URL)
}

// 删除文件
func deleteFile(service afs.Service, URL string) error {
	return service.Delete(context.Background(), URL)
}

3. 使用不同存储后端

// 使用内存存储
memURL := "mem:///testfile.txt"
err := writeFile(memStorage, memURL, []byte("Hello Memory Storage"))

// 使用本地文件系统
localURL := "/tmp/localfile.txt"
err = writeFile(fileStorage, localURL, []byte("Hello Local Storage"))

// 使用S3存储
s3URL := "s3://mybucket/testfile.txt"
err = writeFile(s3Storage, s3URL, []byte("Hello S3 Storage"))

4. ZIP 文件操作示例

import "github.com/viant/afs/zip"

func zipExample() error {
	zipStorage := afs.New()
	zipService := zip.Singleton()
	
	// 创建ZIP文件
	zipURL := "zip:///tmp/test.zip"
	files := map[string][]byte{
		"file1.txt": []byte("content1"),
		"file2.txt": []byte("content2"),
	}
	
	for name, content := range files {
		fileURL := url.Join(zipURL, name)
		if err := zipStorage.Upload(context.Background(), fileURL, 0644, bytes.NewReader(content)); err != nil {
			return err
		}
	}
	
	// 列出ZIP内容
	objects, err := zipStorage.List(context.Background(), zipURL)
	if err != nil {
		return err
	}
	
	for _, obj := range objects {
		fmt.Printf("File in ZIP: %s\n", obj.Name())
	}
	
	return nil
}

5. SCP 文件传输示例

import "github.com/viant/afs/scp"

func scpExample() error {
	scpStorage := afs.New()
	scpService := scp.Singleton()
	
	// 配置SSH连接
	authConfig := &scp.AuthConfig{
		Username: "user",
		Password: "password",
		// 或者使用私钥
		// PrivateKey: "path/to/private/key",
	}
	
	// 上传文件到远程服务器
	remoteURL := "scp://remote.server.com/path/to/remote/file.txt"
	err := scpStorage.UploadWithAuth(context.Background(), remoteURL, 0644, 
		bytes.NewReader([]byte("SCP content")), authConfig)
	if err != nil {
		return err
	}
	
	// 从远程服务器下载文件
	reader, err := scpStorage.DownloadWithAuth(context.Background(), remoteURL, authConfig)
	if err != nil {
		return err
	}
	defer reader.Close()
	
	content, err := ioutil.ReadAll(reader)
	if err != nil {
		return err
	}
	
	fmt.Printf("Downloaded content: %s\n", string(content))
	return nil
}

高级功能

1. 跨存储复制

func copyBetweenStorages(srcURL, destURL string) error {
	srcService := afs.New()
	destService := afs.New()
	
	reader, err := srcService.Download(context.Background(), srcURL)
	if err != nil {
		return err
	}
	defer reader.Close()
	
	return destService.Upload(context.Background(), destURL, 0644, reader)
}

2. 流式处理大文件

func processLargeFile(service afs.Service, URL string) error {
	reader, err := service.Download(context.Background(), URL)
	if err != nil {
		return err
	}
	defer reader.Close()
	
	// 使用bufio处理大文件
	scanner := bufio.NewScanner(reader)
	for scanner.Scan() {
		line := scanner.Text()
		// 处理每一行
		fmt.Println(line)
	}
	
	return scanner.Err()
}

总结

afs 库提供了强大的抽象能力,使得开发者可以用统一的 API 操作多种存储后端。它的主要优点包括:

  1. 代码一致性 - 相同的 API 操作不同存储
  2. 易于扩展 - 可以添加新的存储后端实现
  3. 支持流式处理 - 适合大文件操作
  4. 丰富的存储后端支持

通过 afs,开发者可以轻松构建支持多种存储方案的应用程序,而无需为每种存储编写特定的代码。

回到顶部