Golang - 实现文件管理服务器

先看效果:

代码如下:

Go 复制代码
package main

import (
	"fmt"
	"html/template"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"strings"
)

// 配置根目录(根据需求修改)
//var baseDir = filepath.Join(os.Getenv("/")) // 用户主目录
// var baseDir = "C:\\" // Windows系统使用C盘根目录
var baseDir = "/"    // Linux/Mac使用系统根目录

// 文件信息结构体
type FileInfo struct {
	Name  string
	Path  string
	IsDir bool
}

// 页面数据
type PageData struct {
	Path      string
	ParentDir string
	Files     []FileInfo
}

// 自定义模板函数
var templateFuncs = template.FuncMap{
	"splitPath": func(path string) []string {
		return strings.Split(path, string(filepath.Separator))
	},
	"joinPath": func(parts ...string) string {
		return filepath.Join(parts...)
	},
	"slicePath": func(path string, index int) string {
		parts := strings.Split(path, string(filepath.Separator))
		return filepath.Join(parts[:index]...)
	},
}

func main() {
	// 设置路由
	http.HandleFunc("/", fileHandler)

	// 启动服务器
	fmt.Printf("文件管理服务器已启动,访问 http://localhost:8000/\n")
	fmt.Printf("根目录: %s\n", baseDir)
	fmt.Println("按 Ctrl+C 停止服务器")

	log.Fatal(http.ListenAndServe(":8000", nil))
}

func fileHandler(w http.ResponseWriter, r *http.Request) {
	// 获取路径参数
	path := r.URL.Query().Get("path")
	fullPath := filepath.Join(baseDir, path)

	// 安全检查:确保路径在baseDir下
	if !strings.HasPrefix(filepath.Clean(fullPath), filepath.Clean(baseDir)) {
		http.Error(w, "禁止访问", http.StatusForbidden)
		return
	}

	// 检查路径是否存在
	fileInfo, err := os.Stat(fullPath)
	if err != nil {
		if os.IsNotExist(err) {
			http.Error(w, "文件不存在", http.StatusNotFound)
		} else {
			http.Error(w, "无法访问文件", http.StatusInternalServerError)
		}
		return
	}

	// 如果是文件,直接提供下载
	if !fileInfo.IsDir() {
		http.ServeFile(w, r, fullPath)
		return
	}

	// 如果是目录,列出内容
	dirEntries, err := os.ReadDir(fullPath)
	if err != nil {
		http.Error(w, "无法读取目录", http.StatusInternalServerError)
		return
	}

	// 准备文件列表
	var files []FileInfo

	// 添加上级目录链接(如果不是根目录)
	if path != "" {
		parentDir := filepath.Dir(path)
		if parentDir == path {
			parentDir = ""
		}
		files = append(files, FileInfo{
			Name:  ".. (上级目录)",
			Path:  parentDir,
			IsDir: true,
		})
	}

	// 添加目录和文件
	for _, entry := range dirEntries {
		entryPath := filepath.Join(path, entry.Name())
		files = append(files, FileInfo{
			Name:  entry.Name(),
			Path:  entryPath,
			IsDir: entry.IsDir(),
		})
	}

	// 准备模板数据
	data := PageData{
		Path:      path,
		ParentDir: filepath.Dir(path),
		Files:     files,
	}

	// 创建带有自定义函数的模板
	tmpl := template.New("filelist").Funcs(templateFuncs)

	// 解析模板
	tmpl, err = tmpl.Parse(htmlTemplate)
	if err != nil {
		http.Error(w, "模板错误: "+err.Error(), http.StatusInternalServerError)
		return
	}

	// 执行模板
	err = tmpl.Execute(w, data)
	if err != nil {
		http.Error(w, "模板渲染错误: "+err.Error(), http.StatusInternalServerError)
	}
}

// HTML模板(移除了非ASCII字符)
const htmlTemplate = `
<!DOCTYPE html>
<html>
<head>
    <title>文件管理器 - {{.Path}}</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        h1 { color: #333; }
        ul { list-style-type: none; padding: 0; }
        li { padding: 5px 0; }
        a { text-decoration: none; color: #0066cc; }
        a:hover { text-decoration: underline; }
        .file { color: #666; }
        .dir { color: #009933; font-weight: bold; }
        .breadcrumb { margin-bottom: 20px; }
    </style>
</head>
<body>
    <h1>文件管理器</h1>
    <div class="breadcrumb">
        <a href="/?path=">根目录</a>
        {{if .Path}}
            {{range $i, $part := splitPath .Path}}
                / <a href="/?path={{joinPath (slicePath $.Path $i) $part}}">{{$part}}</a>
            {{end}}
        {{end}}
    </div>

    <ul>
        {{range .Files}}
            <li>
                <a href="/?path={{.Path}}" class="{{if .IsDir}}dir{{else}}file{{end}}">
                    {{if .IsDir}}[DIR]{{else}}[FILE]{{end}} {{.Name}}
                </a>
            </li>
        {{end}}
    </ul>
</body>
</html>
`

启动服务:

bash 复制代码
[root@localhost test]# go run file.go
文件管理服务器已启动,访问 http://localhost:8000/
根目录: /
按 Ctrl+C 停止服务器
相关推荐
bitbrowser3 分钟前
Facebook 验证反复回到原页面,应该从哪里排查
运维·服务器·facebook
运维行者_15 分钟前
如何查看每个IP的带宽使用情况?NetFlow 技术实战指南
开发语言·网络·分布式·后端·架构·带宽
天天进步201535 分钟前
Python全栈项目--基于深度学习的图像超分辨率系统
开发语言·python·深度学习
虹科网络安全38 分钟前
艾体宝新闻|从 SQL 注入到服务器接管:CVE-2026-57517 暴露 Web 管理面板的供应链与安全编码风险
服务器·前端·sql
小小晓.1 小时前
C++小白记:C风格字符串和数组用法
c语言·开发语言·c++
Helen_cai1 小时前
OpenHarmony 项目统一全局样式、尺寸、色彩主题封装 ThemeUtil(API23)
开发语言·前端·javascript·华为·harmonyos
AC赳赳老秦1 小时前
招投标公开数据自动化采集实战:基于 OpenClaw 的定时抓取与业务关键词精准推送
运维·服务器·数据库·自动化·测试用例·deepseek·openclaw
郑州光合科技余经理1 小时前
家政O2O平台解析:从0搭建上门预约小程序解决方案
android·java·开发语言·前端·小程序·架构·php
酷可达拉斯1 小时前
Linux操作系统-shell编程(0)
linux·运维·服务器·python·云计算
FellAveal2 小时前
【Go语言入门学习笔记】Part13.结构体与接口
笔记·学习·golang