【Gin框架入门到精通系列09】Gin中的文件上传与处理

【go语言】Gin框架的简单基本文档 我们要定义一个检验器:如果传入的IP字段中有值,一定是正确的;如果不传,就不传。// 创建翻译器// 注册翻译器if ok {})// 可以允许开发者将用于自定义的验证函数注册到验证器中// 可以自定义和使用自己的验证逻辑,从而扩展男默认的验证功能v.RegisterValidation("fip", func(fl validator.FieldLevel) bool { // 这种类型是检验上下文信息// 下面将每一个字段打印出来= "" {// 传了值就去校验是不是IP地址。 阅读详情

📚 原创系列: “Gin框架入门到精通系列”

🔄 转载说明: 本文最初发布于"Gopher部落"微信公众号,经原作者授权转载。

🔗 关注原创: 欢迎扫描文末二维码,关注"Gopher部落"微信公众号获取第一手Gin框架技术文章。

📑 Gin框架学习系列导航

本文是【Gin框架入门到精通系列】的第9篇,点击下方链接查看更多文章

👉 数据交互篇
  1. Gin连接数据库
  2. Gin中的中间件机制
  3. Gin中的参数验证
  4. Gin中的Cookie和Session管理
  5. Gin中的文件上传与处理👈 当前位置

🔍 查看完整系列文章

📖 文章导读

在本文中,您将了解:

  • Gin框架中处理文件上传的基本方法
  • 单文件与多文件上传的实现技术
  • 文件验证与安全处理的最佳实践
  • 实用的文件存储策略及大文件处理方案

无论您是开发文件共享系统、图片上传功能还是文档管理应用,本文都会为您提供清晰的指导,帮助您在Gin框架中高效实现文件处理功能。

一、导言部分

1.1 本节知识点概述

本文是Gin框架入门到精通系列的第九篇文章,主要介绍Gin框架中的文件上传与处理功能。通过本文的学习,你将了解到:

  • Gin框架中处理文件上传的基本方法
  • 单文件与多文件上传的实现
  • 文件验证与安全处理的最佳实践
  • 文件存储策略及大文件处理方案

1.2 学习目标说明

完成本节学习后,你将能够:

  • 在Gin应用中实现文件上传功能
  • 对上传的文件进行有效验证和安全处理
  • 设计适合不同场景的文件存储策略
  • 处理大文件上传和下载的性能问题

1.3 预备知识要求

学习本教程需要以下预备知识:

  • 基本的Go语言知识
  • HTTP协议中的multipart/form-data格式
  • 文件系统基础
  • 已完成前八篇教程的学习

二、理论讲解

2.1 文件上传基础

2.1.1 HTTP文件上传原理

文件上传是Web应用的常见需求,从技术角度看,它是一种特殊的HTTP请求,具有以下特点:

  1. 请求方法: 通常使用POST方法
  2. Content-Type: 必须设置为multipart/form-data
  3. 请求体: 包含文件内容和可能的其他表单字段

在HTML中,实现文件上传表单需要:

<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="file" />
    <input type="submit" value="上传" />
</form>

其中enctype="multipart/form-data"是必不可少的属性,它告诉浏览器使用multipart编码而不是默认的URL编码。

2.1.2 multipart/form-data格式

multipart/form-data是一种特殊的HTTP请求体格式,用于发送文件和表单数据。它的特点是:

  1. 使用边界(boundary)字符串分隔不同的表单字段
  2. 每个部分都有自己的头部信息(Content-Disposition、Content-Type等)
  3. 支持同时发送文本数据和二进制数据

一个典型的multipart/form-data请求如下:

POST /upload HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="title"

这是文件标题
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="file"; filename="example.jpg"
Content-Type: image/jpeg

[二进制文件数据]
------WebKitFormBoundary7MA4YWxkTrZu0gW--

这种格式允许我们发送任意数量的表单字段,包括文件和文本数据。

2.1.3 Gin中的文件处理接口

Gin框架为文件上传提供了简单而强大的API,主要涉及以下几个接口:

  1. c.FormFile(name string): 获取单个上传的文件
  2. c.MultipartForm(): 获取包含所有上传文件的表单
  3. c.SaveUploadedFile(file, dst): 保存上传的文件到指定路径

这些API基于Go标准库的multipart包,但提供了更简洁的使用方式。在处理文件时,Gin会返回以下类型:

  • *multipart.FileHeader: 包含文件元信息(文件名、大小等)
  • multipart.File: 文件内容的读取接口

2.2 单文件上传

2.2.1 基本的单文件上传

在Gin中,处理单文件上传非常简单,主要使用c.FormFile方法:

func uploadHandler(c *gin.Context) {
   
   
    // 获取上传的文件
    file, err := c.FormFile("file")
    if err != nil {
   
   
        c.JSON(http.StatusBadRequest, gin.H{
   
   "error": "获取文件失败"})
        return
    }
    
    // 文件保存路径
    dst := filepath.Join("./uploads", file.Filename)
    
    // 保存文件
    if err := c.SaveUploadedFile(file, dst); err != nil {
   
   
        c.JSON(http.StatusInternalServerError, gin.H{
   
   "error": "保存文件失败"})
        return
    }
    
    c.JSON(http.StatusOK, gin.H{
   
   "message": "文件上传成功"})
}

在路由中注册这个处理函数:

router.POST("/upload", uploadHandler)
router.MaxMultipartMemory = 8 << 20 // 8 MiB

MaxMultipartMemory用于限制上传文件在内存中的最大大小,超过这个大小的文件会被写入临时文件。

2.2.2 文件信息获取

通过*multipart.FileHeader,我们可以获取上传文件的详细信息:

func getFileInfo(c *gin.Context) {
   
   
    file, err := c.FormFile("file")
    if err != nil {
   
   
        c.JSON(http.StatusBadRequest, gin.H{
   
   "error": "获取文件失败"})
        return
    }
    
    // 获取文件信息
    fileInfo := gin.H{
   
   
        "filename": file.Filename,
        "size":     file.Size,
        "header":   file.Header,
    }
    
    // 获取文件内容
    f, err := file.Open()
    if err != nil {
   
   
        c.JSON(http.StatusInternalServerError, gin.H{
   
   "error": "打开文件失败"})
        return
    }
    defer f.Close()
    
    // 读取文件前20个字节
    buffer := make([]byte, 20)
    n, err := f.Read(buffer)
    if err != nil && err != io.EOF {
   
   
        c.JSON(http.StatusInternalServerError, gin.H{
   
   "error": "读取文件失败"})
        return
    }
    
    fileInfo["contentPreview"] = fmt.Sprintf("%x", buffer[:n])
    
    c.JSON(http.StatusOK, fileInfo)
}

上面的代码展示了如何获取文件名、文件大小、HTTP头部和文件内容的预览。

2.2.3 保存上传文件

Gin提供了c.SaveUploadedFile()方法简化文件保存过程,但你也可以自己控制文件保存过程:

func customSaveFile(c *gin.Context) {
   
   
    file, header, err := c.Request.FormFile("file")
    if err != nil {
   
   
        c.JSON(http.StatusBadRequest, gin.H{
   
   "error": "获取文件失败"})
        return
    }
    defer file.Close()
    
    // 自定义文件名(添加时间戳防止重名)
    filename := fmt.Sprintf("%d_%s", time.Now().Unix(), header.Filename)
    
    // 确保目录存在
    uploadDir := "./uploads"
    if err := os.MkdirAll(uploadDir, 0755); err != nil {
   
   
        c.JSON(http.StatusInternalServerError, gin.H{
   
   "error": "创建目录失败"})
        return
    }
    
    // 创建目标文件
    dst, err := os.Create(filepath.Join(uploadDir, filename))
    if err != nil {
   
   
        c.JSON(http.StatusInternalServerError, gin.H{
   
   "error": "创建文件失败"})
        return
    }
    defer dst.Close()
    
    // 复制文件内容
    if _, err = io.Copy(dst, file); err != nil {
   
   
        c.JSON(http.StatusInternalServerError, gin.H{
   
   "error": "保存文件内容失败"})
        return
    }
    
    c.JSON(http.StatusOK, gin.H{
   
   
        "message":  "文件上传成功",
        "filename": filename,
    })
}

上述代码展示了如何自定义文件保存过程,包括创建目录、重命名文件和手动复制文件内容。

2.3 多文件上传

2.3.1 多文件上传实现

Gin支持同时上传多个文件,这需要使用c.MultipartForm()方法:

func multipleFilesUpload(c *gin.Context) {
   
   
    // 解析multipart表单
    form, err := c.MultipartForm()
    if err != nil {
   
   
        c.JSON(http.StatusBadRequest, gin.H{
   
   "error": "解析表单失败"})
        return
    }
    
    // 获取所有上传的文件
    files := form.File["files"]
    
    // 确保目录存在
    uploadDir := "./uploads"
    if err := os.MkdirAll(uploadDir, 0755); err != nil {
   
   
        c.JSON(http.StatusInternalServerError, gin.H{
   
   "error": "创建目录失败"})
        return
    }
    
    // 处理每个文件
    filenames := []string{
   
   }
    for _, file := range files {
   
   
        // 自定义文件名
        filename := fmt.Sprintf("%d_%s", time.Now().UnixNano(), file.Filename)
        dst := filepath.Join(uploadDir, filename)
        
        // 保存文件
        if err := c.SaveUploadedFile(file, dst); err != nil {
   
   
            c.JSON(http.StatusInternalServerError, gin.H{
   
   
                "error": fmt.Sprintf("保存文件 %s 失败", file.Filename),
            })
            return
        }
        
        filenames = append(filenames, filename)
    }
    
    c.JSON(http.StatusOK, gin.H{
   
   
        "message":   "所有文件上传成功",
        "filenames": filenames,
        "count":     len(files),
    })
}

对应的HTML表单:

<form action="/upload-multiple" method="post" enctype="multipart/form-data">
    <input type="file" name="files" multiple />
    <input type="submit" value="上传多个文件" />
</form>
2.3.2 批量处理文件

对于多个文件的上传,我们通常需要批量处理,可以使用并发处理提高效率:

func concurrentFilesUpload(c *gin.Context) {
   
   
    form, err := c.MultipartForm()
    if err != nil {
   
   
        c.JSON(http.StatusBadRequest, gin.H{
   
   "error": "解析表单失败"})
        return
    }
    
    files := form.File["files"]
    
    // 创建上传目录
    uploadDir := "./uploads"
    if err := os.MkdirAll(uploadDir, 0755); err != nil {
   
   
        c.JSON(http.StatusInternalServerError, gin.H{
   
   "error": "创建目录失败"})
        return
    }
    
    // 创建等待组和结果通道
    var wg sync.WaitGroup
    results := make(chan gin.H, len(files))
    
    // 启动多个goroutine处理文件上传
    for i, file := range files {
   
   
        wg.Add(1)
        
        go func(idx int, fileHeader *multipart.FileHeader) {
   
   
            defer wg.Done()
            
            // 自定义文件名
            filename := fmt.Sprintf("%d_%s", time.Now().UnixNano(), fileHeader.Filename)
            dst := filepath.Join(uploadDir, filename)
            
            // 保存文件
            err := c.SaveUploadedFile(fileHeader, dst)
            
            // 发送处理结果
            results <- gin.H{
   
   
                "index":    idx,
                "filename": fileHeader.Filename,
                "saved_as": filename,
                "success":  err == nil,
                "error":    err,
            }
        }(i, file)
    }
    
    // 等待所有goroutine完成
    go func() {
   
   
        wg.Wait()
        close(results)
    }()
    
    // 收集结果
    fileResults := []gin.H{
   
   }
    for result := range results {
   
   
        fileResults = append(fileResults, result)
    }
    
    c.JSON(http.StatusOK, gin.H{
   
   
        "message": "文件处理完成",
        "results": fileResults,
        "count":   len(fileResults),
    })
}

这段代码使用goroutine并发处理多个文件上传,适合处理大量文件的场景。

2.3.3 多文件上传的优化

优化多文件上传还有以下几个方向:

  1. 限制同时处理的文件数量:
// 限制并发数
const maxConcurrentUploads = 5

func limitedConcurrentUpload(c *gin.Context) {
   
   
    // ... 获取文件列表 ...
    
    // 创建限制并发的信号量
    sem := make(chan struct{
   
   }, maxConcurrentUploads)
    
    for _, file := range files {
   
   
        wg.Add(1)
        
        go func(fileHeader *multipart.FileHeader) {
   
   
            // 获取信号量,限制并发
            sem <- struct{
   
   }{
   
   }
            defer func() {
   
    <-sem }()
            defer wg.Done()
            
            // 处理文件上传...
        }(file)
    }
    
    // ... 等待完成并返回结果 ...
}
  1. 进度跟踪:
type UploadProgress struct {
   
   
    Filename    string  `json:"filename"`
    TotalSize   int64   `json:"total_size"`
    UploadedSize int64  `json:"uploaded_size"`
    Percentage  float64 `json:"percentage"`
}

// 使用io.TeeReader跟踪上传进度
func trackUploadProgress(file multipart.File, header *multipart.FileHeader, progressChan chan<- UploadProgress) io.Reader {
   
   
    progress := UploadProgress{
   
   
        Filename:  header.Filename,
        TotalSize: header.Size,
    }
    
    return io.TeeReader(file, &progressWriter{
   
   
        progress:     &progress,
        progressChan: progressChan,
    })
}

type progressWriter struct {
   
   
    progress     *UploadProgress
    progressChan chan<- UploadProgress
}

func (pw *progressWriter) Write(p []byte) (int, error) {
   
   
    n := len(p)
    pw.progress.UploadedSize += int64(n)
    pw.progress.Percentage = float64(pw.progress.UploadedSize) * 100 / float64(pw.progress.TotalSize)
    
    // 发送进度更新
    pw.progressChan <- *pw.progress
    
    return n, nil
}

这些优化方法可以提高多文件上传的用户体验和系统性能。

2.4 文件验证与安全

2.4.1 文件类型验证

为了安全起见,通常需要验证上传文件的类型,有以下几种方法:

  1. 检查文件扩展名:
func validateFileExtension(filename string, allowedExts []string) bool {
   
   
    ext := strings.ToLower(filepath.Ext(filename))
    for _, allowedExt := range allowedExts {
   
   
        if ext == allowedExt {
   
   
            return true
        }
    }
    return false
}

// 使用示例
func uploadWithExtensionCheck(c *gin.Context) {
   
   
    file, err := c.FormFile("file")
    if err != nil {
   
   
        c.JSON(http.StatusBadRequest, gin.H{
   
   "error": "获取文件失败"})
        return
    }
    
    // 检查文件扩展名
    allowedExts := []string{
   
   ".jpg", ".jpeg", ".png", ".gif"}
    if !validateFileExtension(file.Filename, allowedExts) {
   
   
        c.JSON(http.StatusBadRequest, gin.H{
   
   
            "error": "不支持的文件类型,仅支持 JPG、JPEG、PNG 和 GIF",
        })
        return
    }
    
    // ... 保存文件 ...
}
  1. 检查MIME类型:
func validateMimeType(file *multipart.FileHeader, allowedTypes []string) (bool, error) {
   
   
    f, err := file.Open()
    if err != nil {
   
   
        return false, err
    }
    defer f.Close()
    
    // 读取文件前512字节用于类型检测
    buffer := make([]byte, 512)
    _, err = f.Read(buffer)
    if err != nil && err != io.EOF {
   
   
        return false, err
    }
    
    // 检测内容类型
    contentType := http.DetectContentType(buffer)
    
    for _, allowedType := range allowedTypes {
   
   
        if strings.HasPrefix(contentType, allowedType) {
   
   
            return true, nil
        }
    }
    
    return false, nil
}

// 使用示例
func uploadWithMimeCheck(c *gin.Context) {
   
   
    file, err := c.FormFile("file")
    if err != nil {
   
   
        c.JSON(http.StatusBadRequest, gin.H{
   
   "error": "获取文件失败"})
        return
    }
    
    // 检查MIME类型
    allowedTypes := []string{
   
   "image/jpeg", "image/png", "image/gif"}
    valid, err := validateMimeType(file, allowedTypes)
    if err != nil {
   
   
        c.JSON(http.StatusInternalServerError, gin.H{
   
   "error": "检验文件类型失败"})
        return
    }
    
    if !valid {
   
   
        c.JSON(http.StatusBadRequest, gin.H{
   
   
            "error": "不支持的文件类型,仅支持JPEG、PNG和GIF图片",
        })
        return
    }
    
    // ... 保存文件 ...
}
2.4.2 文件大小限制

控制上传文件的大小对于防止服务器资源耗尽至关重要:

// 设置全局上传文件大小限制
router.MaxMultipartMemory = 8 << 20 // 8 MiB

// 在处理函数中验证文件大小
func uploadWithSizeCheck(c *gin.Context) {
   
   
    file, err := c.FormFile("file")
    if err != nil {
   
   
        c.JSON(http.StatusBadRequest, gin.H{
   
   "error": "获取文件失败"})
        return
    }
    
    // 检查文件大小
    const maxSize = 5 * 1024 * 1024 // 5 MB
    if file.Size > maxSize {
   
   
        c.JSON(http.StatusBadRequest, gin.H{
   
   
            "error": "文件太大,大小不能超过5MB",
        })
        return
    }
    
    // ... 保存文件 ...
}

此外,还可以考虑在前端进行限制,并设置适当的nginx配置(如果使用nginx)。

2.4.3 防止恶意文件上传

除了基本验证外,还需要防范恶意文件上传:

  1. 使用病毒扫描API:
func scanFile(filePath string) (bool, error) {
   
   
    // 接入第三方病毒扫描服务
    // 这里仅作示例
    cmd := exec.Command("clamscan", filePath)
    err := cmd.Run()
    return err == nil, err
}
  1. 使用沙箱执行可执行文件:对于需要处理可执行文件的场景,可以考虑在隔离环境中执行。

  2. 图片处理:对于图片,可以考虑重新生成图片而不是直接保存上传的数据:

func sanitizeImage(inputPath, outputPath string) error {
   
   
    // 读取图片
    img, err := imaging.Open(inputPath)
    if err != nil {
   
   
        return err
    }
    
    // 重新编码图片
    return imaging.Save(img, outputPath)
}
2.4.4 文件名安全处理

文件名处理是安全上传的重要环节:

func sanitizeFilename(filename string) string {
   
   
    // 1. 移除路径信息(避免目录遍历攻击)
    filename = filepath.Base(filename)
    
    // 2. 移除或替换特殊字符
    reg := regexp.MustCompile(`[^\w\s.-]`)
    filename = reg.ReplaceAllString(filename, "_")
    
    // 3. 避免空白文件名
    if filename == "" || filename == "." || filename == ".." {
   
   
        filename = "unnamed_file"
    }
    
    // 4. 添加随机后缀
    ext := filepath.Ext(filename)
    name := filename[:len(filename)-len(ext)]
    randomStr := fmt.Sprintf("%x", md5.Sum([]byte(time.Now().String())))[:8]
    
    return fmt.Sprintf("%s_%s%s", name, randomStr, ext)
}

还可以考虑使用UUID作为文件名,完全忽略原始文件名,这在存储服务器上特别有用:

func generateUniqueFilename(originalName string) string {
   
   
    ext := filepath.Ext(originalName)
    return fmt.Sprintf("%s%s", uuid.New().String(), ext)
}

通过这些安全措施,可以有效防止恶意文件上传和服务器端请求伪造(SSRF)等攻击。

三、代码实践

3.1 基本文件上传实现

3.1.1 单文件上传示例

下面是一个完整的单文件上传实现示例:

package main

import (
    "log"
    "net/http"
    "os"
    "path/filepath"
    
    "github.com/gin-gonic/gin"
)

func main() {
   
   
    // 创建一个默认的路由引擎
    r := gin.Default()
    
    // 设置上传文件大小限制
    r.MaxMultipartMemory = 8 << 20 
GIN框架介绍以及使用 李文周的博客 阅读详情

相关推荐

golang——Gin框架及路由介绍

gin框架中采用的路由库是基于httprouter做的支持Restful风格的API,意思是"表面层状态转化",是一个互联网应用程序的API设计理念:URL定位资源。可以创建路由组,为了管理相同的URL。import ("net/http"//将应用切换到“发布模式”以提升性能//创建路由//默认使用了两个中间件Logger(),Recovery()})})//路由组1})})//路由组2})})//监听端口,默认绑定端口8080。

weixin_57023347的博客 5850

【Gin框架入门到精通系列】全系列导航手册

本文是Gin框架入门到精通系列的导航手册,系统梳理了从入门到精通的25篇学习资源。包含基础入门、中间件、高级功能、测试部署和架构实战等全方位内容,为您提供清晰的Gin框架学习路径。

GopherTribe的博客 3396

在psotgres中的gist和gin索引介绍

GiST 索引:适用于处理多维数据和范围查询,常用于几何数据和自定义数据类型的索引。GIN 索引:适用于处理包含多个元素的数据类型,常用于全文搜索、数组和 JSON 数据的索引。

HGX-DJK 1227

HEC-HMS水文建模从入门到精通:手把手教你安装与配置(附常见问题解决)

本文详细指导HEC-HMS水文建模软件的安装与配置,重点解析了基于InstallShield Wizard的安装流程,并提供了针对常见错误代码(如-6003)的解决方案。旨在帮助水文、水利领域从业者快速搭建稳定的建模环境,为后续流域模拟与洪水预报奠定基础。

weixin_29213827的博客 496

Orange:一个基于 Python 的数据挖掘和机器学习平台

Orange是一个开源的数据挖掘和机器学习平台,采用可视化编程方式,用户可通过拖拽组件构建数据分析工作流。它支持交互式数据探索、多种机器学习算法,并允许Python脚本扩展。Orange特别适合教育和研究,提供直观的界面和丰富的可视化工具。最新版本为3.39.0,支持Windows、macOS和Linux系统。作为GPL许可的免费工具,它既能满足初学者需求,又能通过Python集成实现高级功能。

likuoelie的博客 1435

Agent测试框架Harbor指南

Harbor是一个AI Agent单元测试框架,用于自动化测试AI代理在容器环境中的任务执行能力。它支持18+种AI代理,通过沙箱隔离和自动验证机制评估任务完成情况。任务必须具有可编程验证的输出结果,适合代码、数据、系统等可量化任务,不适合创意写作等主观任务。Harbor采用CLI操作方式,核心架构包含Job管理、Trial执行和验证器三个层级,执行流程包括环境启动、Agent执行和结果验证。任务目录包含指令文件、配置文件、Docker环境定义和测试脚本等必需组件,通过测试脚本自动判断任务完成质量。

loo_Charles_ool的博客 1401

Bochs源码分析 - 4: 使用ida来调试bochs

前言 bochs内部提供了一个调试器,但是这个命令行调试器相当难用,想找一个gui的debugger。第一次是在百度百科的bochs词条中介绍的peter-bochs-debugger调试器(java编写),但是后来发现ida也有一个bochs调试器,因为对ida比较熟悉,就选用此作为bochs调试器。 在配置过程中参考博客 https://blog.youkuaiyun.com/cssxn/article/details/90738498 中的配置,但是这是直接发布版本,拿源码编译...

WriteAnything_的博客 2755

《Linux运维总结:etcd 3.5.15集群数据备份与恢复》

《Linux运维总结:etcd 3.5.15集群数据备份与恢复》

东城绝神 1079

SAP CEWB 高效批量调整工艺路线与BOM的实战指南

本文详细介绍了SAP CEWB工具在批量调整工艺路线与BOM中的高效应用。通过实战案例和操作指南,帮助制造业企业快速掌握批量修改技巧,显著提升工作效率,避免手工操作带来的错误和耗时。特别适合需要频繁更新工艺路线和BOM的企业用户。

weixin_42524708的博客 397

lammps案例:reaxff势模拟Fe(OH)3高温反应过程

所有的reaxff模拟,如:氧化、腐蚀、热裂解、燃烧等模拟,均可采用此模拟框架,只需要更换data文件、势文件,代码中的control文件可以不写,电荷平衡文件也可以用reaxff替换。该案例主要模拟Fe(OH)3在高温下的反应过程,主要代码来自lammps自带的案例。lammps自带案例没有产物输出,故在此基础上稍加修改,增加了产物输出命令。如果需要系统学习反应势的模拟,可考虑报名培训课程。本文分享一个reaxff反应势的案例。in文件代码已经注释,以供参考。大家好,我是小马老师。

lammps_jiayou的博客 1965

Python实现PDB文件预处理

蛋白质结构研究依赖PDB文件存储的三维结构数据,但原始文件常含无关的水分子、离子和非标准残基等干扰信息。本文介绍了一个基于BioPython的Python预处理脚本,可自动清理PDB文件,主要功能包括:1)移除短于阈值的蛋白质链;2)过滤非标准氨基酸;3)可选保留水分子和金属离子。该脚本逻辑清晰,支持批量处理,能显著提升结构比对、分子对接等分析前的数据准备效率,为后续生物信息学研究提供更纯净的结构数据基础。

Protein Designer的博客 568

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

上一篇: 【Gin框架入门到精通系列08】Gin中的Cookie和Session管理
下一篇: 【Gin框架入门到精通系列10】Gin中的中间件高级应用
Gopher部落
博客等级 码龄2年 784粉丝 92原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gopher部落

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值