使用Go語(yǔ)言實(shí)現(xiàn)的WebDAV內(nèi)存文件系統(tǒng)
這個(gè) Go 小玩具,讓內(nèi)存秒變網(wǎng)盤!關(guān)機(jī)就消失,重命名隨便改,還能自動(dòng)掛成 Z 盤——這不是魔法,是 Go 寫的 WebDAV 內(nèi)存文件系統(tǒng)!
你有沒(méi)有想過(guò):如果有一個(gè)網(wǎng)盤,不用注冊(cè)、不占硬盤、速度飛快,但只要一關(guān)程序,所有數(shù)據(jù)就"人間蒸發(fā)"?聽(tīng)起來(lái)像間諜工具?其實(shí)它只是個(gè)用 Go 寫的小玩具——而且現(xiàn)在,它還能讓你在 Windows 資源管理器里直接重命名文件,就像操作本地文件一樣絲滑!
今天,我們就來(lái)揭開(kāi)這個(gè)"內(nèi)存網(wǎng)盤"的神秘面紗。放心,代碼不多,笑點(diǎn)管夠,原理講透,連你家貓都能看懂(大概)。
功能特性
- 所有文件存在內(nèi)存里(RAM),關(guān)進(jìn)程就清零,干凈得像沒(méi)來(lái)過(guò)
- 支持完整的 WebDAV 協(xié)議:新建、刪除、讀寫、建文件夾……
- 新增重磅功能:支持重命名文件/文件夾!拖拽、右鍵改名統(tǒng)統(tǒng) OK
- 啟動(dòng)時(shí)自動(dòng)在 Windows 上映射為 Z: 盤(可自定義),像本地磁盤一樣用!
- 自帶 README.txt 彩蛋,內(nèi)含作者簽名(不是病毒,真的?。?/li>
適用場(chǎng)景
- 臨時(shí)共享
- 快速測(cè)試
- 演示環(huán)境
技術(shù)原理
1. 內(nèi)存文件系統(tǒng) = 一棵樹(shù)
我們用 Go 的 map[string]*File 模擬文件目錄結(jié)構(gòu),每個(gè) File 可以是普通文件或目錄。整棵樹(shù)從根節(jié)點(diǎn) / 開(kāi)始,長(zhǎng)得像這樣:
/
└── README.txt
所有操作(創(chuàng)建、讀取、刪除、重命名)都是在這棵樹(shù)上"修枝剪葉"。
2. WebDAV = HTTP 的"文件操作擴(kuò)展包"
普通 HTTP 只能 GET/POST,而 WebDAV 增加了 MKCOL(建目錄)、PUT(上傳)、MOVE(重命名)等方法。Go 的 golang.org/x/net/webdav 包幫我們實(shí)現(xiàn)了協(xié)議解析,我們只需提供底層文件系統(tǒng)的實(shí)現(xiàn)。
3. 重命名 = "搬家+改名"
重命名的本質(zhì)是:
- 從舊父目錄中刪掉條目
- 在新父目錄中加上新名字
- 如果跨目錄,還要更新父指針
關(guān)鍵是要同時(shí)鎖住兩個(gè)父目錄,防止并發(fā)時(shí)"文件失蹤"。我們的代碼做到了這一點(diǎn),安全又高效。
4. Windows 映射 = net use 命令自動(dòng)化
程序啟動(dòng)后,偷偷執(zhí)行:
net use Z: http://localhost:8080 /y
于是你的資源管理器就多了一個(gè)"網(wǎng)絡(luò)驅(qū)動(dòng)器"。退出時(shí)再執(zhí)行 /delete,不留痕跡。
使用方法
第一步:準(zhǔn)備環(huán)境
確保已安裝 Go(1.16+),并啟用 Go Modules。
第二步:保存以下三個(gè)文件
注意:三個(gè)文件需放在同一模塊下,例如項(xiàng)目結(jié)構(gòu)如下:
your-project/
├── go.mod
├── main.go
└── memdisk/
├── memfs.go
└── webdav.go
第三步:運(yùn)行!
go run main.go -port=8080 -drive=Z:
然后打開(kāi)"此電腦",看看是不是多了個(gè) Z: 盤?雙擊進(jìn)去,試試新建文件、重命名——是不是和本地磁盤一模一樣?


源碼展示
main.go
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命令映射網(wǎng)絡(luò)驅(qū)動(dòng)器
func mapNetworkDrive(serverURL, drive string) {
// 首先,如果已經(jīng)連接則斷開(kāi)連接
exec.Command("net", "use", drive, "/delete", "/y").Run()
// 然后映射網(wǎng)絡(luò)驅(qū)動(dòng)器
cmd := exec.Command("net", "use", drive, serverURL)
if err := cmd.Run(); err != nil {
log.Printf("映射網(wǎng)絡(luò)驅(qū)動(dòng)器失敗: %v", err)
// 嘗試不同的方法
log.Printf("您可以手動(dòng)映射驅(qū)動(dòng)器: net use %s %s", drive, serverURL)
} else {
log.Printf("成功將 %s 映射到 %s", drive, serverURL)
}
}
// 使用Windows net use命令取消映射網(wǎng)絡(luò)驅(qū)動(dòng)器
func unmapNetworkDrive(drive string) {
log.Printf("正在取消映射網(wǎng)絡(luò)驅(qū)動(dòng)器: %s", drive)
cmd := exec.Command("net", "use", drive, "/delete", "/y")
if err := cmd.Run(); err != nil {
log.Printf("取消映射網(wǎng)絡(luò)驅(qū)動(dòng)器失敗: %v", err)
} else {
log.Printf("成功取消映射 %s", drive)
}
}
func main() {
// 解析命令行參數(shù)
var port string
var drive string
flag.StringVar(&port, "port", "8080", "服務(wù)器端口")
flag.StringVar(&drive, "drive", "Z:", "映射的網(wǎng)絡(luò)驅(qū)動(dòng)器盤符")
flag.Parse()
// 如果使用舊的參數(shù)方式,仍然支持
if flag.NArg() > 0 {
port = flag.Arg(0)
}
if flag.NArg() > 1 {
drive = flag.Arg(1)
}
// 創(chuàng)建一個(gè)新的內(nèi)存文件系統(tǒng)
fs := memdisk.NewMemFS()
// 只創(chuàng)建一個(gè)README文件
fs.WriteFile("/README.txt", []byte("內(nèi)存文件系統(tǒng)\r\n\r\n這是一個(gè)運(yùn)行在內(nèi)存中的文件服務(wù)器。\r\n所有文件都存儲(chǔ)在RAM中,服務(wù)器停止時(shí)將丟失。\r\nJjMgx"))
// 用于網(wǎng)絡(luò)驅(qū)動(dòng)器映射的服務(wù)器URL
serverURL := fmt.Sprintf("http://localhost:%s", port)
// 啟動(dòng)WebDAV服務(wù)器
startWebDAVServer(fs, port, drive, serverURL)
}
// 啟動(dòng)WebDAV服務(wù)器
func startWebDAVServer(fs *memdisk.MemFS, port, drive, serverURL string) {
// 創(chuàng)建WebDAV文件系統(tǒng)
wdFs := memdisk.NewWebDAVFS(fs)
// 創(chuàng)建WebDAV處理器
handler := &webdav.Handler{
FileSystem: wdFs,
LockSystem: webdav.NewMemLS(),
Logger: func(r *http.Request, err error) {
if err != nil {
log.Printf("WebDAV錯(cuò)誤: %v %v", r.Method, err)
} else {
log.Printf("WebDAV請(qǐng)求: %v %v", r.Method, r.URL)
}
},
}
// 創(chuàng)建服務(wù)器多路復(fù)用器
mux := http.NewServeMux()
// 為所有路徑注冊(cè)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請(qǐng)求
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
// 調(diào)用WebDAV處理器
handler.ServeHTTP(w, r)
})
// 監(jiān)聽(tīng)中斷信號(hào)的通道
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
// 確保清理完成的等待組
var wg sync.WaitGroup
// 啟動(dòng)服務(wù)器goroutine并在準(zhǔn)備好時(shí)映射網(wǎng)絡(luò)驅(qū)動(dòng)器
log.Printf("正在啟動(dòng)WebDAV服務(wù)器于 :%s", port)
log.Printf("訪問(wèn)服務(wù)器地址 http://localhost:%s", port)
log.Printf("嘗試映射為網(wǎng)絡(luò)驅(qū)動(dòng)器: %s", drive)
// 服務(wù)器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("服務(wù)器啟動(dòng)失敗: %v", err)
}
}()
// 給服務(wù)器一點(diǎn)時(shí)間啟動(dòng),然后映射網(wǎng)絡(luò)驅(qū)動(dòng)器
go func() {
time.Sleep(500 * time.Millisecond)
log.Printf("正在映射網(wǎng)絡(luò)驅(qū)動(dòng)器: %s 到 %s", drive, serverURL)
mapNetworkDrive(serverURL, drive)
}()
// 等待中斷信號(hào)
<-sigChan
log.Println("正在關(guān)閉服務(wù)器...")
// 取消映射網(wǎng)絡(luò)驅(qū)動(dòng)器
unmapNetworkDrive(drive)
// 優(yōu)雅地關(guān)閉服務(wù)器
if err := server.Shutdown(context.Background()); err != nil {
log.Printf("服務(wù)器關(guān)閉錯(cuò)誤: %v", err)
}
// 等待所有g(shù)oroutine完成
wg.Wait()
log.Println("服務(wù)器已優(yōu)雅退出")
}
memdisk/memfs.go
package memdisk
import (
"os"
"sync"
"time"
)
// File 表示內(nèi)存文件系統(tǒng)中的一個(gè)文件
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 表示內(nèi)存文件系統(tǒng)
type MemFS struct {
Root *File
mu sync.RWMutex
}
// NewMemFS 創(chuàng)建一個(gè)新的MemFS實(shí)例
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 根據(jù)路徑獲取文件或目錄
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 在給定路徑中創(chuàng)建新目錄
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 // 根目錄已存在
}
// 在不持有全局鎖的情況下獲取父級(jí)
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 在給定路徑中創(chuàng)建新文件
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
}
// 在不持有全局鎖的情況下獲取父級(jí)
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 讀取文件內(nèi)容
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 將內(nèi)容寫入文件
func (fs *MemFS) WriteFile(path string, content []byte) error {
file, err := fs.GetFile(path)
if err != nil {
// 如果文件不存在則嘗試創(chuàng)建
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
}
// 在不持有全局鎖的情況下獲取父級(jí)
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
}
// 對(duì)相同對(duì)象只鎖定一次
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
// 更新修改時(shí)間
oldFile.ModifiedAt = time.Now()
return nil
}
// ListDir 列出目錄內(nèi)容
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()
// 創(chuàng)建副本以避免競(jìng)態(tài)條件
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 將路徑組件連接成單個(gè)路徑字符串
func joinPath(components []string) string {
result := ""
for i, comp := range components {
if i > 0 {
result += "/"
}
result += comp
}
return result
}
memdisk/webdav.go
package memdisk
import (
"context"
"io"
"os"
"time"
"golang.org/x/net/webdav"
)
// 為File實(shí)現(xiàn)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
}
// ... 移除兼容性層,現(xiàn)在直接實(shí)現(xiàn)Name()和Size() ...
// WebDAVFS實(shí)現(xiàn)了webdav.FileSystem接口
type WebDAVFS struct {
fs *MemFS
}
// NewWebDAVFS創(chuàng)建一個(gè)新的WebDAVFS實(shí)例
func NewWebDAVFS(fs *MemFS) *WebDAVFS {
return &WebDAVFS{
fs: fs,
}
}
// Mkdir創(chuàng)建一個(gè)新目錄
func (wfs *WebDAVFS) Mkdir(ctx context.Context, name string, perm os.FileMode) error {
_, err := wfs.fs.CreateDir(name)
return err
}
// OpenFile打開(kāi)一個(gè)文件
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標(biāo)志,則創(chuàng)建文件
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實(shí)現(xiàn)了webdav.File接口
type WebDAVFile struct {
file *File
pos int64
}
// Close關(guān)閉文件
func (wf *WebDAVFile) Close() error {
return nil // 內(nèi)存文件無(wú)需操作
}
// 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()
// 計(jì)算寫入后的新位置
newPos := wf.pos + int64(len(p))
// 如需要?jiǎng)t調(diào)整內(nèi)容大小
if newPos > int64(len(wf.file.Content)) {
// 擴(kuò)展內(nèi)容
newContent := make([]byte, newPos)
copy(newContent, wf.file.Content)
wf.file.Content = newContent
}
// 將p寫入當(dāng)前位置
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)) {
// 擴(kuò)展內(nèi)容
newContent := make([]byte, newPos)
copy(newContent, wf.file.Content)
wf.file.Content = newContent
}
copy(wf.file.Content[off:newPos], p)
// 如需要?jiǎng)t更新大小
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值轉(zhuǎn)換為切片
children := make([]os.FileInfo, 0, len(wf.file.Children))
for _, child := range wf.file.Children {
children = append(children, child)
}
// 處理count參數(shù)
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鍵轉(zhuǎn)換為切片
names := make([]string, 0, len(wf.file.Children))
for name := range wf.file.Children {
names = append(names, name)
}
// 處理n參數(shù)
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
}
注意事項(xiàng)
- 此項(xiàng)目?jī)H限本地測(cè)試,無(wú)任何身份驗(yàn)證,請(qǐng)勿暴露到公網(wǎng)!
- Windows 映射功能僅在 Windows 上有效(廢話文學(xué)+1)
- 數(shù)據(jù)隨進(jìn)程消亡——所以別把情書存進(jìn)去,除非你想制造"數(shù)字失憶"浪漫
注意:README.txt 末尾的 JjMgx 是作者簽名,不是亂碼,也不是病毒哈 :)
到此這篇關(guān)于使用Go語(yǔ)言實(shí)現(xiàn)的WebDAV內(nèi)存文件系統(tǒng)的文章就介紹到這了,更多相關(guān)Go語(yǔ)言內(nèi)存文件系統(tǒng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
源碼分析Golang?log是如何實(shí)現(xiàn)的
go語(yǔ)言的log包提供了簡(jiǎn)單的日志記錄功能,允許開(kāi)發(fā)者在應(yīng)用程序中記錄重要的信息、錯(cuò)誤、警告等,log包是Go標(biāo)準(zhǔn)庫(kù)的一部分,因此,使用它不需要安裝額外的第三方庫(kù),本文給大家源碼分析了Golang?log是如何實(shí)現(xiàn)的,需要的朋友可以參考下2024-03-03
golang使用map支持高并發(fā)的方法(1000萬(wàn)次操作14ms)
這篇文章主要介紹了golang使用map支持高并發(fā)的方法(1000萬(wàn)次操作14ms),本文給大家詳細(xì)講解,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-11-11
Golang使用cobra實(shí)現(xiàn)命令行程序的示例代碼
Cobra 是 Go 語(yǔ)言中一個(gè)強(qiáng)大的命令行應(yīng)用庫(kù),它提供了創(chuàng)建命令行工具所需的基本結(jié)構(gòu)和功能,被許多開(kāi)發(fā)者用于構(gòu)建各種命令行工具和應(yīng)用程序,本文將給大家介紹Golang使用cobra實(shí)現(xiàn)命令行程序,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2024-02-02
Ubuntu安裝Go語(yǔ)言運(yùn)行環(huán)境
由于最近偏愛(ài)Ubuntu,在加上作為一門開(kāi)源語(yǔ)言,在Linux上從源代碼開(kāi)始搭建環(huán)境更讓人覺(jué)得有趣味性。讓我們直接先從Go語(yǔ)言的環(huán)境搭建開(kāi)始2015-04-04
詳解Go語(yǔ)言中如何通過(guò)Goroutine實(shí)現(xiàn)高并發(fā)
在Go語(yǔ)言中,并發(fā)編程是一個(gè)核心且強(qiáng)大的特性,Go語(yǔ)言通過(guò)goroutine和channel等機(jī)制,使得并發(fā)編程變得更加簡(jiǎn)單和直觀,本文給大家介紹了Go語(yǔ)言中如何通過(guò)Goroutine快速實(shí)現(xiàn)高并發(fā),感興趣的小伙伴跟著小編一起來(lái)看看吧2024-10-10
Go語(yǔ)言實(shí)現(xiàn)多文本文件合并的示例代碼
這篇文章主要為大家詳細(xì)介紹了使用Go語(yǔ)言實(shí)現(xiàn)多文本文件合并的相關(guān)知識(shí),適用于初學(xué)者學(xué)習(xí)文件讀取與寫入的綜合運(yùn)用,有需要的小伙伴可以了解下2025-07-07
golang中判斷請(qǐng)求是http還是https獲取當(dāng)前訪問(wèn)地址
這篇文章主要為大家介紹了golang中判斷請(qǐng)求是http還是https獲取當(dāng)前訪問(wèn)地址示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
SingleFlight模式的Go并發(fā)編程學(xué)習(xí)
這篇文章主要為大家介紹了SingleFlight模式的Go并發(fā)編程學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04

