主调函数,设置路由表

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语言实现文件服务器的更多相关文章

  1. JVM 平台上的各种语言的开发指南

    JVM 平台上的各种语言的开发指南 为什么我们需要如此多的JVM语言? 在2013年你可以有50中JVM语言的选择来用于你的下一个项目.尽管你可以说出一大打的名字,你会准备为你的下一个项目选择一种新的 ...

  2. Ueditor1.4.3实现跨域上传到独立文件服务器,完美解决单文件和多文件上传!

    再写配置方法之前先吐槽一下网上的各种教程,TM没一个有卵用,一群傻屌不会写就别写,写了就要负责. 百度google搜了半天,全是配置什么document.domain,根域名什么的,我只想对你说: 好 ...

  3. Java语言进阶过程(转)

    [以下肯定是不完整的列表,欢迎补充] Java是一个通用的编程语言,其实可以干很多事,怎么学Java就看怎么用了. 但有一些一般的步骤: 1. 熟悉一种文本编辑器,比如Vim, Emacs, Note ...

  4. 无敌简单快速的文件服务器sgfs

    前言 想要构建一个Linux文件服务器?看看下面几个要求是不是你想要的? 1.只需要单节点部署就够了 2.部署启动简单,下载之后,一键启动,一键关闭 3.不需要任何其他的依赖安装,而且运行时占用内存资 ...

  5. linux搭建FastDFS文件服务器

    本文主要介绍在linux服务器如何搭建FastDFS文件服务器.大概分为9个步骤,由于内容较为繁琐.下面带你入坑! 首先简单介绍一下FastDFS是淘宝资深架构师余庆老师主导开源的一个分布式文件系统, ...

  6. 不安分的 Go 语言开始入侵 Web 前端领域了!( WebAssembly )

    参考:https://blog.csdn.net/csdnnews/article/details/84038848 从 Go 语言诞生以来,它就开始不断侵蚀 Java .C.C++ 语言的领地.今年 ...

  7. 百度富文本编辑器整合fastdfs文件服务器上传

    技术:springboot+maven+ueditor   概述 百度富文本整合fastdfs文件服务器上传 详细 代码下载:http://www.demodashi.com/demo/15008.h ...

  8. 开源文件服务器file-service介绍

    file-service 一个基于ASP.NET Core的可伸缩.通用的文件服务器. 通常后端项目可能会有头像.图片.音频.视频等上传/下载需求,这些需求都可以抽象为文件服务. 功能特点 支持Lin ...

  9. Golang vs PHP 之文件服务器

    前面的话 作者为golang脑残粉,本篇内容可能会引起phper不适,请慎读! 前两天有同事遇到一个问题,需要一个能支持上传.下载功能的HTTP服务器做一个数据中心.我刚好弄过,于是答应帮他搭一个. ...

  10. 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 ...

随机推荐

  1. TCP 异常断开连接的过程

    Tcp连接正常断开的情况,大家都了解,也就是一端发送Fin报文开启四次挥手,然后 sock 结构销毁,但是我之前很少去追踪 Tcp 在对端宕机,进程 Crash 之后的行为逻辑.前段时间正巧遇到了这样 ...

  2. 1009.Django模型基础04

    一.数据库数据渲染到模板 二.案例的功能介绍 博客小案例功能介绍: 主页index.html--------------> 展示添加博客和博客列表的文字,实现页面跳转 添加页add.html-- ...

  3. Ubuntu VMWare安装纪要

    一.VMware虚拟机下载与安装 版本:VMware Workstation 16 Pro 二.Ubuntu下载与安装 版本:ubuntu-20.04.2.0-desktop-amd64.iso 三. ...

  4. 第3章---数据探索(python数据挖掘)

    1.缺失值分析及箱型图 数据:catering_sale.xls(餐饮日销额数) 缺失值使用函数:describe()函数,能算出数据集的八个统计量 import pandas as pd cater ...

  5. 网络如何运作——详细DNS、HTTP、网站

    详细的DNS 什么是DNS? DNS(域名系统)为我们提供了一种简单的方式来与互联网上的设备进行通信,而无需记住复杂的数字.就像每个房子都有一个唯一的地址可以直接向它发送邮件一样,互联网上的每台计算机 ...

  6. Matlab笔记--Matlab概述(初登场)

    Matlab概述 安装MATLAB教程 可以参考这里:https://www.cnblogs.com/sixuwuxian/p/15858196.html Matlab的启动 右键图标,选择属性,可以 ...

  7. Spring--事务案例的实现

    案例实现(主要是想用Spring实现一下MyBatis的相关内容) JDBCConfig.java MyBatisConfig.java SpringConfig.java accountDao.ja ...

  8. jsp页面中的正则表达式--主要用于js判断文本格式

    一.方括号[] 举例: 二.^ 三.元字符 举例的话,就可以这么说,要实现要表示整数的话: []就表示输入的文本框里面的数字的第一位,可以这么写--->[1-9] 然后已知\d表示的与[0-9] ...

  9. 自用nodejs安装笔记

    下载Nodejs 进入Nodejs官网https://nodejs.org/zh-cn/ 下载 安装Node.js 检查Nodejs和npm包管理器是否安装成功 用管理员打开cmd控制台 命令行输入n ...

  10. CF859E题解

    题意简述 翻译很清楚了 题目解法 如果一个人想去的位置上原来坐着人,那么他要坐到这个位置上,就要把原来的人赶走. 原来的人被赶走了,就只能去想去的位置.如果那个位置上有人,又要把那个人赶走. 我们发现 ...