使用Go语言实现的WebDAV内存文件系统

Written by

in

文章目录
  • 所有文件存在内存里(RAM),关进程就清零,干净得像没来过 支持完整的 WebDAV 协议:新建、删除、读写、建文件夹…… 新增重磅功能:支持重命名文件/文件夹!拖拽、右键改名统统 OK 启动时自动在 Windows 上映射为 Z: 盘(可自定义),像本地磁盘一样用! 自带 README.txt 彩蛋,内含作者签名(不是病毒,真的!) 适用场景 临时共享 快速测试 演示环境
  • 此项目仅限本地测试,无任何身份验证,请勿暴露到公网! Windows 映射功能仅在 Windows 上有效(废话文学+1) 数据随进程消亡——所以别把情书存进去,除非你想制造"数字失忆"浪漫 注意:README.txt 末尾的 JjMgx 是作者签名,不是乱码,也不是病毒哈 🙂 到此这篇关于使用Go语言实现的WebDAV内存文件系统的文章就介绍到这了,更多相关Go语言内存文件系统内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 您可能感兴趣的文章: 基于Go语言实现高性能文件上传下载系统 Golang使用minio替代文件系统的实战教程 详解Golang中文件系统事件监听 go实现一个内存缓存系统的示例代码
  • 目录
    • 功能特性
    • 技术原理
      • 1. 内存文件系统 = 一棵树
      • 2. WebDAV = HTTP 的"文件操作扩展包"
      • 3. 重命名 = "搬家+改名"
      • 4. Windows 映射 = net use 命令自动化
    • 使用方法
      • 第一步:准备环境
      • 第二步:保存以下三个文件
      • 第三步:运行!
    • 源码展示
      • main.go
      • memdisk/memfs.go
      • memdisk/webdav.go
    • 注意事项

      这个 Go 小玩具,让内存秒变网盘!关机就消失,重命名随便改,还能自动挂成 Z 盘——这不是魔法,是 Go 写的 WebDAV 内存文件系统!

      你有没有想过:如果有一个网盘,不用注册、不占硬盘、速度飞快,但只要一关程序,所有数据就"人间蒸发"?听起来像间谍工具?其实它只是个用 Go 写的小玩具——而且现在,它还能让你在 Windows 资源管理器里直接重命名文件,就像操作本地文件一样丝滑!

      今天,我们就来揭开这个"内存网盘"的神秘面纱。放心,代码不多,笑点管够,原理讲透,连你家猫都能看懂(大概)。

      • 所有文件存在内存里(RAM),关进程就清零,干净得像没来过
      • 支持完整的 WebDAV 协议:新建、删除、读写、建文件夹……
      • 新增重磅功能:支持重命名文件/文件夹!拖拽、右键改名统统 OK
      • 启动时自动在 Windows 上映射为 Z: 盘(可自定义),像本地磁盘一样用!
      • 自带 README.txt 彩蛋,内含作者签名(不是病毒,真的!)

      适用场景

      • 临时共享
      • 快速测试
      • 演示环境

      我们用 Go 的 map[string]*File 模拟文件目录结构,每个 File 可以是普通文件或目录。整棵树从根节点 / 开始,长得像这样:

      /
      └── README.txt

      所有操作(创建、读取、删除、重命名)都是在这棵树上"修枝剪叶"。

      普通 HTTP 只能 GET/POST,而 WebDAV 增加了 MKCOL(建目录)、PUT(上传)、MOVE(重命名)等方法。Go 的 golang.org/x/net/webdav 包帮我们实现了协议解析,我们只需提供底层文件系统的实现。

      重命名的本质是:

      • 从旧父目录中删掉条目
      • 在新父目录中加上新名字
      • 如果跨目录,还要更新父指针

      关键是要同时锁住两个父目录,防止并发时"文件失踪"。我们的代码做到了这一点,安全又高效。

      程序启动后,偷偷执行:

      net use Z: http://localhost:8080 /y
      

      于是你的资源管理器就多了一个"网络驱动器"。退出时再执行 /delete,不留痕迹。

      确保已安装 Go(1.16+),并启用 Go Modules。

      注意:三个文件需放在同一模块下,例如项目结构如下:

      your-project/
      ├── go.mod
      ├── main.go
      └── memdisk/
          ├── memfs.go
          └── webdav.go

      go run main.go -port=8080 -drive=Z:
      

      然后打开"此电脑",看看是不是多了个 Z: 盘?双击进去,试试新建文件、重命名——是不是和本地磁盘一模一样?

      package main
      
      import (
      	"context"
      	"flag"
      	"fmt"
      	"log"
      	"net/http"
      	"os"
      	"os/exec"
      	"os/signal"
      	"sync"
      	"syscall"
      	"time"
      
      	"golang.org/x/net/webdav"
      	
      	"memdisk/memdisk"
      )
      
      // 使用Windows net use命令映射网络驱动器
      func mapNetworkDrive(serverURL, drive string) {
      	// 首先,如果已经连接则断开连接
      	exec.Command("net", "use", drive, "/delete", "/y").Run()
      
      	// 然后映射网络驱动器
      	cmd := exec.Command("net", "use", drive, serverURL)
      	if err := cmd.Run(); err != nil {
      		log.Printf("映射网络驱动器失败: %v", err)
      		// 尝试不同的方法
      		log.Printf("您可以手动映射驱动器: net use %s %s", drive, serverURL)
      	} else {
      		log.Printf("成功将 %s 映射到 %s", drive, serverURL)
      	}
      }
      
      // 使用Windows net use命令取消映射网络驱动器
      func unmapNetworkDrive(drive string) {
      	log.Printf("正在取消映射网络驱动器: %s", drive)
      	cmd := exec.Command("net", "use", drive, "/delete", "/y")
      	if err := cmd.Run(); err != nil {
      		log.Printf("取消映射网络驱动器失败: %v", err)
      	} else {
      		log.Printf("成功取消映射 %s", drive)
      	}
      }
      
      func main() {
      	// 解析命令行参数
      	var port string
      	var drive string
      
      	flag.StringVar(&port, "port", "8080", "服务器端口")
      	flag.StringVar(&drive, "drive", "Z:", "映射的网络驱动器盘符")
      	flag.Parse()
      
      	// 如果使用旧的参数方式,仍然支持
      	if flag.NArg() > 0 {
      		port = flag.Arg(0)
      	}
      	if flag.NArg() > 1 {
      		drive = flag.Arg(1)
      	}
      
      	// 创建一个新的内存文件系统
      	fs := memdisk.NewMemFS()
      
      	// 只创建一个README文件
      	fs.WriteFile("/README.txt", []byte("内存文件系统rnrn这是一个运行在内存中的文件服务器。rn所有文件都存储在RAM中,服务器停止时将丢失。rnJjMgx"))
      
      	// 用于网络驱动器映射的服务器URL
      	serverURL := fmt.Sprintf("http://localhost:%s", port)
      
      	// 启动WebDAV服务器
      	startWebDAVServer(fs, port, drive, serverURL)
      
      }
      
      // 启动WebDAV服务器
      func startWebDAVServer(fs *memdisk.MemFS, port, drive, serverURL string) {
      	// 创建WebDAV文件系统
      	wdFs := memdisk.NewWebDAVFS(fs)
      
      	// 创建WebDAV处理器
      	handler := &webdav.Handler{
      		FileSystem: wdFs,
      		LockSystem: webdav.NewMemLS(),
      		Logger: func(r *http.Request, err error) {
      			if err != nil {
      				log.Printf("WebDAV错误: %v %v", r.Method, err)
      			} else {
      				log.Printf("WebDAV请求: %v %v", r.Method, r.URL)
      			}
      		},
      	}
      
      	// 创建服务器多路复用器
      	mux := http.NewServeMux()
      
      	// 为所有路径注册WebDAV处理器
      	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
      		// 添加CORS头部
      		w.Header().Set("Access-Control-Allow-Origin", "*")
      		w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, MKCOL, COPY, MOVE, OPTIONS")
      		w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Depth, Overwrite, Destination, Authorization")
      
      		// 添加可能影响显示名称的自定义头部
      		w.Header().Set("Server", "CustomWebDAVServer")
      		w.Header().Set("X-Server-Name", "MemoryFileSystem")
      
      		// 处理OPTIONS请求
      		if r.Method == "OPTIONS" {
      			w.WriteHeader(http.StatusOK)
      			return
      		}
      
      		// 调用WebDAV处理器
      		handler.ServeHTTP(w, r)
      	})
      
      	// 监听中断信号的通道
      	sigChan := make(chan os.Signal, 1)
      	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
      
      	// 确保清理完成的等待组
      	var wg sync.WaitGroup
      
      	// 启动服务器goroutine并在准备好时映射网络驱动器
      	log.Printf("正在启动WebDAV服务器于 :%s", port)
      	log.Printf("访问服务器地址 http://localhost:%s", port)
      	log.Printf("尝试映射为网络驱动器: %s", drive)
      
      	// 服务器goroutine
      	server := &http.Server{
      		Addr:    fmt.Sprintf(":%s", port),
      		Handler: mux,
      	}
      
      	go func() {
      		wg.Add(1)
      		defer wg.Done()
      		if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
      			log.Fatalf("服务器启动失败: %v", err)
      		}
      	}()
      
      	// 给服务器一点时间启动,然后映射网络驱动器
      	go func() {
      		time.Sleep(500 * time.Millisecond)
      		log.Printf("正在映射网络驱动器: %s 到 %s", drive, serverURL)
      		mapNetworkDrive(serverURL, drive)
      	}()
      
      	// 等待中断信号
      	<-sigChan
      	log.Println("正在关闭服务器...")
      
      	// 取消映射网络驱动器
      	unmapNetworkDrive(drive)
      
      	// 优雅地关闭服务器
      	if err := server.Shutdown(context.Background()); err != nil {
      		log.Printf("服务器关闭错误: %v", err)
      	}
      
      	// 等待所有goroutine完成
      	wg.Wait()
      	log.Println("服务器已优雅退出")
      }
      

      package memdisk
      
      import (
      	"os"
      	"sync"
      	"time"
      )
      
      // File 表示内存文件系统中的一个文件
      type File struct {
      	Filename     string
      	Content      []byte
      	FileSize     int64
      	CreatedAt    time.Time
      	ModifiedAt   time.Time
      	IsDirectory  bool
      	Children     map[string]*File
      	Parent       *File
      	mu           sync.RWMutex
      }
      
      // MemFS 表示内存文件系统
      type MemFS struct {
      	Root  *File
      	mu    sync.RWMutex
      }
      
      // NewMemFS 创建一个新的MemFS实例
      func NewMemFS() *MemFS {
      	root := &File{
      		Filename:     "",
      		IsDirectory:  true,
      		Children:     make(map[string]*File),
      		CreatedAt:    time.Now(),
      		ModifiedAt:   time.Now(),
      	}
      	return &MemFS{
      		Root: root,
      	}
      }
      
      // splitPath 将路径分割为其组成部分
      func splitPath(path string) []string {
      	if path == "/" {
      		return []string{}
      	}
      
      	components := []string{}
      	current := ""
      	for _, c := range path {
      		if c == '/' {
      			if current != "" {
      				components = append(components, current)
      				current = ""
      			}
      		} else {
      			current += string(c)
      		}
      	}
      	if current != "" {
      		components = append(components, current)
      	}
      	return components
      }
      
      // GetFile 根据路径获取文件或目录
      func (fs *MemFS) GetFile(path string) (*File, error) {
      	if path == "" {
      		return nil, os.ErrInvalid
      	}
      
      	fs.mu.RLock()
      	defer fs.mu.RUnlock()
      
      	components := splitPath(path)
      	current := fs.Root
      
      	for _, comp := range components {
      		current.mu.RLock()
      		child, exists := current.Children[comp]
      		current.mu.RUnlock()
      		if !exists {
      			return nil, os.ErrNotExist
      		}
      		current = child
      	}
      
      	return current, nil
      }
      
      // CreateDir 在给定路径中创建新目录
      func (fs *MemFS) CreateDir(path string) (*File, error) {
      	if path == "" {
      		return nil, os.ErrInvalid
      	}
      
      	components := splitPath(path)
      	if len(components) == 0 {
      		return fs.Root, nil // 根目录已存在
      	}
      
      	// 在不持有全局锁的情况下获取父级
      	parentPathComponents := components[:len(components)-1]
      	parentPath := "/" + joinPath(parentPathComponents)
      	parent, err := fs.GetFile(parentPath)
      	if err != nil {
      		return nil, err
      	}
      
      	fs.mu.Lock()
      	defer fs.mu.Unlock()
      
      	parent.mu.Lock()
      	defer parent.mu.Unlock()
      
      	newDirName := components[len(components)-1]
      	if _, exists := parent.Children[newDirName]; exists {
      		return nil, os.ErrExist
      	}
      
      	newDir := &File{
      		Filename:     newDirName,
      		IsDirectory:  true,
      		Children:     make(map[string]*File),
      		CreatedAt:    time.Now(),
      		ModifiedAt:   time.Now(),
      		Parent:       parent,
      	}
      
      	parent.Children[newDirName] = newDir
      	return newDir, nil
      }
      
      // CreateFile 在给定路径中创建新文件
      func (fs *MemFS) CreateFile(path string) (*File, error) {
      	if path == "" {
      		return nil, os.ErrInvalid
      	}
      
      	components := splitPath(path)
      	if len(components) == 0 {
      		return nil, os.ErrInvalid
      	}
      
      	// 在不持有全局锁的情况下获取父级
      	parentPathComponents := components[:len(components)-1]
      	parentPath := "/" + joinPath(parentPathComponents)
      	parent, err := fs.GetFile(parentPath)
      	if err != nil {
      		return nil, err
      	}
      
      	fs.mu.Lock()
      	defer fs.mu.Unlock()
      
      	parent.mu.Lock()
      	defer parent.mu.Unlock()
      
      	newFileName := components[len(components)-1]
      	if _, exists := parent.Children[newFileName]; exists {
      		return nil, os.ErrExist
      	}
      
      	newFile := &File{
      		Filename:     newFileName,
      		IsDirectory:  false,
      		Content:      []byte{},
      		FileSize:     0,
      		CreatedAt:    time.Now(),
      		ModifiedAt:   time.Now(),
      		Parent:       parent,
      	}
      
      	parent.Children[newFileName] = newFile
      	return newFile, nil
      }
      
      // ReadFile 读取文件内容
      func (fs *MemFS) ReadFile(path string) ([]byte, error) {
      	file, err := fs.GetFile(path)
      	if err != nil {
      		return nil, err
      	}
      
      	file.mu.RLock()
      	defer file.mu.RUnlock()
      
      	if file.IsDirectory {
      		return nil, os.ErrInvalid
      	}
      
      	content := make([]byte, len(file.Content))
      	copy(content, file.Content)
      	return content, nil
      }
      
      // WriteFile 将内容写入文件
      func (fs *MemFS) WriteFile(path string, content []byte) error {
      	file, err := fs.GetFile(path)
      	if err != nil {
      		// 如果文件不存在则尝试创建
      		file, err = fs.CreateFile(path)
      		if err != nil {
      			return err
      		}
      	}
      
      	file.mu.Lock()
      	defer file.mu.Unlock()
      
      	if file.IsDirectory {
      		return os.ErrInvalid
      	}
      
      	file.Content = make([]byte, len(content))
      	copy(file.Content, content)
      	file.FileSize = int64(len(content))
      	file.ModifiedAt = time.Now()
      	return nil
      }
      
      // Delete 删除文件或目录
      func (fs *MemFS) Delete(path string) error {
      	if path == "/" {
      		return os.ErrPermission
      	}
      
      	components := splitPath(path)
      	if len(components) == 0 {
      		return os.ErrInvalid
      	}
      
      	// 在不持有全局锁的情况下获取父级
      	parentPathComponents := components[:len(components)-1]
      	parentPath := "/" + joinPath(parentPathComponents)
      	parent, err := fs.GetFile(parentPath)
      	if err != nil {
      		return err
      	}
      
      	fs.mu.Lock()
      	defer fs.mu.Unlock()
      
      	parent.mu.Lock()
      	defer parent.mu.Unlock()
      
      	fileName := components[len(components)-1]
      	if _, exists := parent.Children[fileName]; !exists {
      		return os.ErrNotExist
      	}
      
      	delete(parent.Children, fileName)
      	return nil
      }
      
      // Rename 重命名文件或目录
      func (fs *MemFS) Rename(oldPath, newPath string) error {
      	if oldPath == "/" || newPath == "/" {
      		return os.ErrPermission
      	}
      
      	oldComponents := splitPath(oldPath)
      	newComponents := splitPath(newPath)
      	
      	if len(oldComponents) == 0 || len(newComponents) == 0 {
      		return os.ErrInvalid
      	}
      
      	// 获取旧文件的父目录和文件名
      	oldParentPathComponents := oldComponents[:len(oldComponents)-1]
      	oldParentPath := "/" + joinPath(oldParentPathComponents)
      	oldParent, err := fs.GetFile(oldParentPath)
      	if err != nil {
      		return err
      	}
      
      	// 获取新文件的父目录和文件名
      	newParentPathComponents := newComponents[:len(newComponents)-1]
      	newParentPath := "/" + joinPath(newParentPathComponents)
      	newParent, err := fs.GetFile(newParentPath)
      	if err != nil {
      		return err
      	}
      
      	// 对相同对象只锁定一次
      	sameParent := oldParent == newParent
      
      	fs.mu.Lock()
      	defer fs.mu.Unlock()
      
      	oldParent.mu.Lock()
      	defer oldParent.mu.Unlock()
      
      	// 如果不是同一父目录,则锁定新父目录
      	if !sameParent {
      		newParent.mu.Lock()
      		defer newParent.mu.Unlock()
      	}
      
      	oldFileName := oldComponents[len(oldComponents)-1]
      	newFileName := newComponents[len(newComponents)-1]
      
      	// 检查旧文件是否存在
      	oldFile, exists := oldParent.Children[oldFileName]
      	if !exists {
      		return os.ErrNotExist
      	}
      
      	// 检查新文件是否已存在
      	if _, exists := newParent.Children[newFileName]; exists {
      		return os.ErrExist
      	}
      
      	// 从旧位置移除
      	delete(oldParent.Children, oldFileName)
      
      	// 更新文件名
      	oldFile.Filename = newFileName
      	
      	// 更新父指针(如果不是同一父目录)
      	if !sameParent {
      		oldFile.Parent = newParent
      	}
      	
      	// 添加到新位置
      	newParent.Children[newFileName] = oldFile
      	
      	// 更新修改时间
      	oldFile.ModifiedAt = time.Now()
      
      	return nil
      }
      
      // ListDir 列出目录内容
      func (fs *MemFS) ListDir(path string) ([]*File, error) {
      	dir, err := fs.GetFile(path)
      	if err != nil {
      		return nil, err
      	}
      
      	dir.mu.RLock()
      	defer dir.mu.RUnlock()
      
      	if !dir.IsDirectory {
      		return nil, os.ErrInvalid
      	}
      
      	children := make([]*File, 0, len(dir.Children))
      	for _, child := range dir.Children {
      		child.mu.RLock()
      		// 创建副本以避免竞态条件
      		copyChild := &File{
      		Filename:     child.Filename,
      		FileSize:     child.FileSize,
      		CreatedAt:    child.CreatedAt,
      		ModifiedAt:   child.ModifiedAt,
      		IsDirectory:  child.IsDirectory,
      	}
      		child.mu.RUnlock()
      		children = append(children, copyChild)
      	}
      
      	return children, nil
      }
      
      // joinPath 将路径组件连接成单个路径字符串
      func joinPath(components []string) string {
      	result := ""
      	for i, comp := range components {
      		if i > 0 {
      			result += "/"
      		}
      		result += comp
      	}
      	return result
      }
      

      package memdisk
      
      import (
      	"context"
      	"io"
      	"os"
      	"time"
      	"golang.org/x/net/webdav"
      )
      
      // 为File实现os.FileInfo接口
      func (f *File) Name() string {
      	return f.Filename
      }
      
      func (f *File) Size() int64 {
      	return f.FileSize
      }
      
      func (f *File) Mode() os.FileMode {
      	if f.IsDirectory {
      		return 0755 | os.ModeDir
      	}
      	return 0644
      }
      
      func (f *File) ModTime() time.Time {
      	return f.ModifiedAt
      }
      
      func (f *File) IsDir() bool {
      	return f.IsDirectory
      }
      
      func (f *File) Sys() interface{} {
      	return nil
      }
      
      // ... 移除兼容性层,现在直接实现Name()和Size() ...
      
      // WebDAVFS实现了webdav.FileSystem接口
      
      type WebDAVFS struct {
      	fs *MemFS
      }
      
      // NewWebDAVFS创建一个新的WebDAVFS实例
      func NewWebDAVFS(fs *MemFS) *WebDAVFS {
      	return &WebDAVFS{
      		fs: fs,
      	}
      }
      
      // Mkdir创建一个新目录
      func (wfs *WebDAVFS) Mkdir(ctx context.Context, name string, perm os.FileMode) error {
      	_, err := wfs.fs.CreateDir(name)
      	return err
      }
      
      // OpenFile打开一个文件
      func (wfs *WebDAVFS) OpenFile(ctx context.Context, name string, flag int, perm os.FileMode) (webdav.File, error) {
      	// 检查文件是否存在
      	file, err := wfs.fs.GetFile(name)
      	if err != nil {
      		if os.IsNotExist(err) && (flag&os.O_CREATE != 0) {
      			// 如果文件不存在且指定了O_CREATE标志,则创建文件
      			file, err = wfs.fs.CreateFile(name)
      			if err != nil {
      				return nil, err
      			}
      		} else {
      			return nil, err
      		}
      	}
      
      	// 返回WebDAVFile包装器
      	return &WebDAVFile{
      		file: file,
      		pos:  0,
      	}, nil
      }
      
      // RemoveAll删除文件或目录
      func (wfs *WebDAVFS) RemoveAll(ctx context.Context, name string) error {
      	return wfs.fs.Delete(name)
      }
      
      // Rename重命名文件或目录
      func (wfs *WebDAVFS) Rename(ctx context.Context, oldName, newName string) error {
      	return wfs.fs.Rename(oldName, newName)
      }
      
      // Stat返回文件信息
      func (wfs *WebDAVFS) Stat(ctx context.Context, name string) (os.FileInfo, error) {
      	file, err := wfs.fs.GetFile(name)
      	if err != nil {
      		return nil, err
      	}
      	return file, nil
      }
      
      // WebDAVFile实现了webdav.File接口
      type WebDAVFile struct {
      	file *File
      	pos  int64
      }
      
      // Close关闭文件
      func (wf *WebDAVFile) Close() error {
      	return nil // 内存文件无需操作
      }
      
      // Read从文件读取
      func (wf *WebDAVFile) Read(p []byte) (n int, err error) {
      	wf.file.mu.RLock()
      	defer wf.file.mu.RUnlock()
      
      	if wf.pos >= int64(len(wf.file.Content)) {
      		return 0, io.EOF
      	}
      
      	n = copy(p, wf.file.Content[wf.pos:])
      	wf.pos += int64(n)
      	return n, nil
      }
      
      // ReadAt在指定偏移位置从文件读取
      func (wf *WebDAVFile) ReadAt(p []byte, off int64) (n int, err error) {
      	wf.file.mu.RLock()
      	defer wf.file.mu.RUnlock()
      
      	if off >= int64(len(wf.file.Content)) {
      		return 0, io.EOF
      	}
      
      	n = copy(p, wf.file.Content[off:])
      	if n < len(p) {
      		err = io.EOF
      	}
      	return n, err
      }
      
      // Seek定位到指定位置
      func (wf *WebDAVFile) Seek(offset int64, whence int) (int64, error) {
      	wf.file.mu.RLock()
      	defer wf.file.mu.RUnlock()
      
      	var newPos int64
      
      	switch whence {
      	case io.SeekStart:
      		newPos = offset
      	case io.SeekCurrent:
      		newPos = wf.pos + offset
      	case io.SeekEnd:
      		newPos = int64(len(wf.file.Content)) + offset
      	default:
      		return 0, os.ErrInvalid
      	}
      
      	if newPos < 0 {
      		return 0, os.ErrInvalid
      	}
      
      	wf.pos = newPos
      	return newPos, nil
      }
      
      // Write向文件写入
      func (wf *WebDAVFile) Write(p []byte) (n int, err error) {
      	wf.file.mu.Lock()
      	defer wf.file.mu.Unlock()
      
      	// 计算写入后的新位置
      	newPos := wf.pos + int64(len(p))
      
      	// 如需要则调整内容大小
      	if newPos > int64(len(wf.file.Content)) {
      		// 扩展内容
      		newContent := make([]byte, newPos)
      		copy(newContent, wf.file.Content)
      		wf.file.Content = newContent
      	}
      
      	// 将p写入当前位置
      	copy(wf.file.Content[wf.pos:newPos], p)
      
      	// 更新位置和大小
      	wf.pos = newPos
      	wf.file.FileSize = newPos
      	wf.file.ModifiedAt = time.Now()
      
      	return len(p), nil
      }
      
      // WriteAt在指定偏移位置向文件写入
      func (wf *WebDAVFile) WriteAt(p []byte, off int64) (n int, err error) {
      	wf.file.mu.Lock()
      	defer wf.file.mu.Unlock()
      
      	newPos := off + int64(len(p))
      	if newPos > int64(len(wf.file.Content)) {
      		// 扩展内容
      		newContent := make([]byte, newPos)
      		copy(newContent, wf.file.Content)
      		wf.file.Content = newContent
      	}
      
      	copy(wf.file.Content[off:newPos], p)
      
      	// 如需要则更新大小
      	if newPos > wf.file.FileSize {
      		wf.file.FileSize = newPos
      	}
      
      	wf.file.ModifiedAt = time.Now()
      
      	return len(p), nil
      }
      
      // Readdir读取目录条目
      func (wf *WebDAVFile) Readdir(count int) ([]os.FileInfo, error) {
      	wf.file.mu.RLock()
      	defer wf.file.mu.RUnlock()
      
      	if !wf.file.IsDirectory {
      		return nil, os.ErrInvalid
      	}
      
      	// 将map值转换为切片
      	children := make([]os.FileInfo, 0, len(wf.file.Children))
      	for _, child := range wf.file.Children {
      		children = append(children, child)
      	}
      
      	// 处理count参数
      	if count <= 0 {
      		return children, nil
      	}
      
      	if count > len(children) {
      		return children, io.EOF
      	}
      
      	return children[:count], nil
      }
      
      // Readdirnames读取目录条目名称
      func (wf *WebDAVFile) Readdirnames(n int) ([]string, error) {
      	wf.file.mu.RLock()
      	defer wf.file.mu.RUnlock()
      
      	if !wf.file.IsDirectory {
      		return nil, os.ErrInvalid
      	}
      
      	// 将map键转换为切片
      	names := make([]string, 0, len(wf.file.Children))
      	for name := range wf.file.Children {
      		names = append(names, name)
      	}
      
      	// 处理n参数
      	if n <= 0 {
      		return names, nil
      	}
      
      	if n > len(names) {
      		return names, io.EOF
      	}
      
      	return names[:n], nil
      }
      
      // Stat返回文件信息
      func (wf *WebDAVFile) Stat() (os.FileInfo, error) {
      	return wf.file, nil
      }
      

      • 此项目仅限本地测试,无任何身份验证,请勿暴露到公网!
      • Windows 映射功能仅在 Windows 上有效(废话文学+1)
      • 数据随进程消亡——所以别把情书存进去,除非你想制造"数字失忆"浪漫

      注意:README.txt 末尾的 JjMgx 是作者签名,不是乱码,也不是病毒哈 🙂

      到此这篇关于使用Go语言实现的WebDAV内存文件系统的文章就介绍到这了,更多相关Go语言内存文件系统内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

      您可能感兴趣的文章:

      • 基于Go语言实现高性能文件上传下载系统
      • Golang使用minio替代文件系统的实战教程
      • 详解Golang中文件系统事件监听
      • go实现一个内存缓存系统的示例代码

      站内搜索