首页 > 其他分享 >Golang文件服务器

Golang文件服务器

时间:2022-12-04 10:57:27浏览次数:35  
标签:文件 http func err return Golang file 服务器 string

主调函数,设置路由表

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

标签:文件,http,func,err,return,Golang,file,服务器,string
From: https://www.cnblogs.com/N3ptune/p/16949501.html

相关文章

  • Python标准库-Configparser-配置文件解析器
    简介官方文档开发中INI格式的配置文件使用还是有必要的。如果某些配置项需要在运行时由用户来修改指定,比如数据库用户信息等等,这种配置项如果使用INI格式的配置文件来操......
  • Nacos 中的配置文件如何实现加密传输
    小伙伴们知道,SpringCloudConfig很早就提供了配置文件的加解密功能,并且支持对称加密和非对称加密两种不同的模式。Nacos作为分布式配置中心+服务注册中心的合体,在配置文......
  • TLS协议学习(1) -- 在pcapng文件中嵌入(Pre)-Master-Secret
    1.已有方案如下link告知在pcap文件中如何使用(Pre)-Master-Secret文件,以及如何把pcap和(Pre)-Master-Secret文件转为pcapng文件。https://wiki.wireshark.or......
  • 目前最流行的网页自动运行EXE文件
    大家对木马都不陌生了,它可能要算是计算机病毒史上最厉害的了,相信会使木马的人千千万万,但是有很多人苦于怎么把木马发给对方,现在随着计算机的普及,在网络上我相信很少有人会......
  • ssm四个配置文件的相关解释
    一.解释1.application-config.xml1.1总的配置文件,将三个配置联系在一起。2.spring-dao.xml2.1管理数据流层,导入并管理mybatis.xml。2.2mybatis.xml管理数据库连接,操作......
  • SSM配置文件整合
    SSM配置文件整合1.ApplicationContext.xml<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="ht......
  • 【python】使用百度api进行音频文件转写
     【python】使用百度api进行音频文件转写脚本目标:智能云的音频文件转写文档只给了个demo,每次只能传1分钟以内的音频啥的,不好直接用,简单打包一下,做到把音频放文件夹,直......
  • nodejs、ts 上传文件之根据文件路径实现本地文件上传至服务器
    安装依赖库npminstallmyjs-common 参数//待上传文件数组letfiles=["C:\\Users\\bm\\img\\0.jpg","C:\\Users\\bm\\img\\1.jpg","C:\\Users\\bm\\img\\2.......
  • Ubuntu通过NFS实现文件共享
    搭建基础NFS服务服务端(192.168.1.1)#安装NFSServer服务sudoapt-getinstallnfs-kernel-server-y#创建共享目录并设置权限cd/datamkdir-psharechmod777share......
  • Golang反射获得变量类型和值
    1.什么是反射反射是程序在运行期间获取变量的类型和值、或者执行变量的方法的能力。Golang反射包中有两对非常重要的函数和类型,两个函数分别是:reflect.TypeOf能获取类......