Go语言实现文件服务器
主调函数,设置路由表
package main
import (
	"fmt"
	"net/http"
	"store/handler"
)
func main() {
	http.HandleFunc("/file/upload", handler.UploadHandler)
	http.HandleFunc("/file/upload/suc", handler.UploadSucHandler)
	http.HandleFunc("/file/meta", handler.GetFileMetaHandler)
	http.HandleFunc("/file/download", handler.DownloadHandler)
	http.HandleFunc("/file/delete", handler.FileDelHandler)
	http.HandleFunc("/file/update", handler.FileMetaUpdateHandler)
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		fmt.Printf("Failed to start server: %s", err.Error())
	}
}
文件元信息
package meta
// FileMeta 文件元信息结构
type FileMeta struct {
	FileSha1 string // 文件哈希
	FileName string // 文件名
	FileSize int64  // 文件大小
	Location string // 文件位置
	UploadAt string // 上传时间
}
// 保存文件元信息映射
var fileMetas map[string]FileMeta
func init() {
	fileMetas = make(map[string]FileMeta) // 初始化
}
// UpdateFileMeta 更新文件元信息
func UpdateFileMeta(fileMeta FileMeta) {
	fileMetas[fileMeta.FileSha1] = fileMeta
}
// GetFileMeta 获取文件元信息对象
func GetFileMeta(fileSha1 string) FileMeta {
	return fileMetas[fileSha1]
}
// RemoveFileMeta 删除文件元信息
func RemoveFileMeta(fileSha1 string) {
	delete(fileMetas, fileSha1)
}
handler逻辑
package handler
import (
	"encoding/json"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"store/meta"
	"store/utils"
	"time"
)
const storePath = "./tmp/"
func UploadHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		// HTML 上传页面
		data, err := ioutil.ReadFile("./static/view/index.html")
		if err != nil {
			_, _ = io.WriteString(w, "internal server error")
			return
		}
		_, _ = io.WriteString(w, string(data))
	} else if r.Method == "POST" {
		// 接收文件流
		file, head, err := r.FormFile("file")
		if err != nil {
			log.Printf("Failed to get data: %s\n", err.Error())
			_, _ = io.WriteString(w, "")
			return
		}
		defer file.Close()
		fileMeta := meta.FileMeta{
			FileName: head.Filename,
			Location: storePath + head.Filename,
			UploadAt: time.Now().Format("2006-01-02 15:04:05"),
		}
		newFile, err := os.Create(fileMeta.Location)
		if err != nil {
			log.Printf("Failed to create file: %s\n", err.Error())
			return
		}
		defer newFile.Close()
		_, err = io.Copy(newFile, file)
		if err != nil {
			log.Printf("Failed to save data into file: %s\n", err.Error())
			return
		}
		_, _ = newFile.Seek(0, 0)
		fileMeta.FileSha1 = utils.FileSha1(newFile)
		meta.UpdateFileMeta(fileMeta)
		http.Redirect(w, r, "/file/upload/suc", http.StatusFound)
	}
}
func UploadSucHandler(w http.ResponseWriter, r *http.Request) {
	_, _ = io.WriteString(w, "Upload successfully")
}
// GetFileMetaHandler 获取文件元信息
func GetFileMetaHandler(w http.ResponseWriter, r *http.Request) {
	_ = r.ParseForm()
	fileHash := r.Form["filehash"][0]
	fileMeta := meta.GetFileMeta(fileHash)
	data, err := json.Marshal(fileMeta)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	_, _ = w.Write(data)
}
func DownloadHandler(w http.ResponseWriter, r *http.Request) {
	_ = r.ParseForm()
	fileHash := r.Form.Get("filehash")
	fileMeta := meta.GetFileMeta(fileHash)
	file, err := os.Open(fileMeta.Location)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	defer file.Close()
	data, err := ioutil.ReadAll(file)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/octet-stream")
	w.Header().Set("Content-Disposition", "attachment;filename=\""+fileMeta.FileName+"\"")
	_, _ = w.Write(data)
}
func FileDelHandler(w http.ResponseWriter, r *http.Request) {
	_ = r.ParseForm()
	fileHash := r.Form.Get("fileHash")
	fileMeta := meta.GetFileMeta(fileHash)
	_ = os.Remove(fileMeta.Location)
	meta.RemoveFileMeta(fileHash)
	w.WriteHeader(http.StatusOK)
}
func FileMetaUpdateHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	_ = r.ParseForm()
	opType := r.Form.Get("op")
	if opType != "0" {
		w.WriteHeader(http.StatusForbidden)
		return
	}
	fileHash := r.Form.Get("filehash")
	newFileName := r.Form.Get("filename")
	curFileMeta := meta.GetFileMeta(fileHash)
	curFileMeta.FileName = newFileName
	meta.UpdateFileMeta(curFileMeta)
	data, err := json.Marshal(curFileMeta)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusOK)
	_, _ = w.Write(data)
}
加密
package utils
import (
	"crypto/md5"
	"crypto/sha1"
	"encoding/hex"
	"hash"
	"io"
	"os"
	"path/filepath"
)
type Sha1Stream struct {
	_sha1 hash.Hash
}
func (obj *Sha1Stream) Update(data []byte) {
	if obj._sha1 == nil {
		obj._sha1 = sha1.New()
	}
	obj._sha1.Write(data)
}
func (obj *Sha1Stream) Sum() string {
	return hex.EncodeToString(obj._sha1.Sum([]byte("")))
}
func Sha1(data []byte) string {
	_sha1 := sha1.New()
	_sha1.Write(data)
	return hex.EncodeToString(_sha1.Sum([]byte("")))
}
func FileSha1(file *os.File) string {
	_sha1 := sha1.New()
	_, _ = io.Copy(_sha1, file)
	return hex.EncodeToString(_sha1.Sum(nil))
}
func MD5(data []byte) string {
	_md5 := md5.New()
	_md5.Write(data)
	return hex.EncodeToString(_md5.Sum([]byte("")))
}
func FileMD5(file *os.File) string {
	_md5 := md5.New()
	_, _ = io.Copy(_md5, file)
	return hex.EncodeToString(_md5.Sum(nil))
}
func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}
func GetFileSize(filename string) int64 {
	var result int64
	_ = filepath.Walk(filename, func(path string, f os.FileInfo, err error) error {
		result = f.Size()
		return nil
	})
	return result
}
前端:
<html lang="">
<head>
  <!-- bootstrap 4.x is supported. You can also use the bootstrap css 3.3.x versions -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css">
  <link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-fileinput/4.4.9/css/fileinput.min.css" media="all"
    rel="stylesheet" type="text/css" />
  <!-- if using RTL (Right-To-Left) orientation, load the RTL CSS file after fileinput.css by uncommenting below -->
  <!-- link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-fileinput/4.4.9/css/fileinput-rtl.min.css" media="all" rel="stylesheet" type="text/css" /-->
  <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
  <!-- piexif.min.js is needed for auto orienting image files OR when restoring exif data in resized images and when you
        wish to resize images before upload. This must be loaded before fileinput.min.js -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-fileinput/4.4.9/js/plugins/piexif.min.js"
    type="text/javascript"></script>
  <!-- sortable.min.js is only needed if you wish to sort / rearrange files in initial preview.
        This must be loaded before fileinput.min.js -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-fileinput/4.4.9/js/plugins/sortable.min.js"
    type="text/javascript"></script>
  <!-- purify.min.js is only needed if you wish to purify HTML content in your preview for
        HTML files. This must be loaded before fileinput.min.js -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-fileinput/4.4.9/js/plugins/purify.min.js"
    type="text/javascript"></script>
  <!-- popper.min.js below is needed if you use bootstrap 4.x. You can also use the bootstrap js
       3.3.x versions without popper.min.js. -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js"></script>
  <!-- bootstrap.min.js below is needed if you wish to zoom and preview file content in a detail modal
        dialog. bootstrap 4.x is supported. You can also use the bootstrap js 3.3.x versions. -->
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/js/bootstrap.min.js"
    type="text/javascript"></script>
  <!-- the main fileinput plugin file -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-fileinput/4.4.9/js/fileinput.min.js"></script>
  <!-- optionally if you need a theme like font awesome theme you can include it as mentioned below -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-fileinput/4.4.9/themes/fa/theme.js"></script>
  <!-- optionally if you need translation for your language then include  locale file as mentioned below -->
  <title></title>
</head>
<body style="width:100%;height:100%;text-align:center;">
  <div style="width:60%;height:30%;text-align:center;">
    <form action='#' method="post" enctype="multipart/form-data">
      <input id="file" name="file" type="file" class="file" data-msg-placeholder="选择文件">
    </form>
  </div>
</body>
</html>
目录结构
.
├── go.mod
├── handler
│   └── handler.go
├── main.go
├── meta
│   └── file.go
├── static
│   └── view
│       ├── index.html
│       └── search.html
├── tmp
│   └── apple.jpg
└── utils
    └── utils.go
Go语言实现文件服务器的更多相关文章
- JVM 平台上的各种语言的开发指南
		JVM 平台上的各种语言的开发指南 为什么我们需要如此多的JVM语言? 在2013年你可以有50中JVM语言的选择来用于你的下一个项目.尽管你可以说出一大打的名字,你会准备为你的下一个项目选择一种新的 ... 
- Ueditor1.4.3实现跨域上传到独立文件服务器,完美解决单文件和多文件上传!
		再写配置方法之前先吐槽一下网上的各种教程,TM没一个有卵用,一群傻屌不会写就别写,写了就要负责. 百度google搜了半天,全是配置什么document.domain,根域名什么的,我只想对你说: 好 ... 
- Java语言进阶过程(转)
		[以下肯定是不完整的列表,欢迎补充] Java是一个通用的编程语言,其实可以干很多事,怎么学Java就看怎么用了. 但有一些一般的步骤: 1. 熟悉一种文本编辑器,比如Vim, Emacs, Note ... 
- 无敌简单快速的文件服务器sgfs
		前言 想要构建一个Linux文件服务器?看看下面几个要求是不是你想要的? 1.只需要单节点部署就够了 2.部署启动简单,下载之后,一键启动,一键关闭 3.不需要任何其他的依赖安装,而且运行时占用内存资 ... 
- linux搭建FastDFS文件服务器
		本文主要介绍在linux服务器如何搭建FastDFS文件服务器.大概分为9个步骤,由于内容较为繁琐.下面带你入坑! 首先简单介绍一下FastDFS是淘宝资深架构师余庆老师主导开源的一个分布式文件系统, ... 
- 不安分的 Go 语言开始入侵 Web 前端领域了!( WebAssembly )
		参考:https://blog.csdn.net/csdnnews/article/details/84038848 从 Go 语言诞生以来,它就开始不断侵蚀 Java .C.C++ 语言的领地.今年 ... 
- 百度富文本编辑器整合fastdfs文件服务器上传
		技术:springboot+maven+ueditor 概述 百度富文本整合fastdfs文件服务器上传 详细 代码下载:http://www.demodashi.com/demo/15008.h ... 
- 开源文件服务器file-service介绍
		file-service 一个基于ASP.NET Core的可伸缩.通用的文件服务器. 通常后端项目可能会有头像.图片.音频.视频等上传/下载需求,这些需求都可以抽象为文件服务. 功能特点 支持Lin ... 
- Golang vs PHP 之文件服务器
		前面的话 作者为golang脑残粉,本篇内容可能会引起phper不适,请慎读! 前两天有同事遇到一个问题,需要一个能支持上传.下载功能的HTTP服务器做一个数据中心.我刚好弄过,于是答应帮他搭一个. ... 
- Go语言编程 (许式伟 等 著)
		第1章 初识Go语言 1.1 语言简史 1.2 语言特性 1.2.1 自动垃圾回收 1.2.2 更丰富的内置类型 1.2.3 函数多返回值 1.2.4 错误处理 1.2.5 匿名函数和闭包 1.2.6 ... 
随机推荐
- K8SYaml文件详解
			一.K8S支持的文件格式 kubernetes支持YAML和JSON文件格式管理资源对象. JSON格式:主要用于api接口之间消息的传递 YAML格式:用于配置和管理,YAML是一种简洁的非标记性语 ... 
- HTML基础知识学习
			一.HTML概述 1.系统结构: ①.B/S架构 Browser Server(浏览器/服务器的交互形式.) Browser支持哪些语言:HTML CSS Javascript S是服务器端Serve ... 
- JavaScript基础学习之一
			目录 let和var之间的区别 作用域不同 变量提升 暂时性死区(temporal dead zone,简称 TDZ) 相同作用域下的重复声明 脚本调用 数据类型 Boolean Object 对象 ... 
- Scala操作Kakfa API
			如需大数据开发整套视频(hadoop\hive\hbase\flume\sqoop\kafka\zookeeper\presto\spark):请联系QQ:1974983704 由于我使用的是kafk ... 
- hello cnb
			Huawei executive Meng Wanzhou freed by Canada arrives home in China 目录 关于git merge冲突时候的想法 Git修改commi ... 
- 京东-Docker
			关于 Docker 版本的<使用与更新>教程修订日期:2021年 3 月 14 日ㅤ 一.基础使用教程1. 进入与退出容器:docker exec -it jd /bin/bash注意:e ... 
- JSP环境搭建及入门 和 虚拟路径和虚拟主机
			Jsp:是一个动态网页,而不是静态网页 html,css,js,Jquery:是静态网页 动态网页是随着,时间,地点,用户操作,而改变 静态不需要jsp 动态是需要的 BS 可以通过浏览器直接访问浏览 ... 
- centos7所有用户循环登录
			1 使用快捷键Ctrl+Alt+F2进入命令终端 2 输入账号密码 3 输入 /usr/bin/sudo 4 输入 startx 那种单用户,改配置的试了没有用 
- [picoCTF]Insp3ct0r write up
			根据提示,需要检查浏览器上的Web代码(动手翻译一下啦) (漫不经心的瞅瞅页面,curl+UUUUUUU(一只U就行)一下下,微微瞄一瞄,where is flag? fn+f12(或其它)打开源代码 ... 
- Xamarin.Android 利用作业计划程序实现ImageSwitcher图片自动定时轮播
			在开发android程序时,遇到一个问题,ImageSwitcher只支持手动的切换图片,不支持自动定时的切换.因为xamarin的资料很少,官方也没有相应的教程,所以想到这个方法,利用job程序来实 ... 
