LOADING

正在加载

Golang小脚本(持续更新)

壹 说明

该文章主要记录平时工作或者生活中经常使用的Golang小脚本。

贰 小脚本

2.1 处理错误方法

// 处理错误方法
func HandlingErrors(err error, funname string) {
    if err != nil {
        fmt.Println("[\033[31;1m-\033[0m] ", funname, "Error:", err)
        log.Panic(err)
    }
}

2.2 标志

func TagPrint() {
    // tag1
    fmt.Println("\033[31;1m====================================================\033[0m\033[34;1m")
    fmt.Println("        ______  ____\033[31;1m_\033[0m\033[34;1m__\033[31;1m___\033[0m\033[34;1m____\033[31;1m___")
    fmt.Println("       /\033[0m\033[34;1m      ||   。      \033[33;1m。\033[0m\033[34;1m   /")
    fmt.Println("      /  _    \033[31;1m|\033[0m\033[34;1m|____\033[31;1m__\033[0m\033[34;1m_    _  _/ T00ls:")
    fmt.Println("     \033[31;1m/\033[0m\033[34;1m  \033[31;1m/ |\033[0m\033[34;1m   |       /   /\033[31;1m( )\033[0m\033[34;1m   工具名字")
    fmt.Println("    /  \033[31;1m/_\033[0m\033[34;1m_|   |      \033[31;1m/\033[0m\033[34;1m   /   ( )       ")
    fmt.Println("   /  ____    \033[31;1m|\033[0m\033[34;1m  \033[35;1m<-—+—+—+--}\033[0m\033[34;1m\033[31;1m( )\033[0m\033[34;1m____\033[31;1m/|\033[0m\033[34;1m")
    fmt.Println("  \033[31;1m/\033[0m\033[34;1m  /    |   |    /   /    ( \033[33;1m.\033[0m\033[34;1m   . \033[31;1m)\033[0m\033[34;1m")
    fmt.Println(" /\033[31;1m_\033[0m\033[34;1m_/     |_\033[31;1m__|\033[0m\033[34;1m   \033[31;1m/_\033[0m\033[34;1m__/     (\033[31;1m__\033[0m\033[34;1m__=___)  \033[31;1m❤\033[0m")
    fmt.Println("\033[0m\033[31;1m====================================================\033[0m")
}
func TagPrint() {
    // tag2
    fmt.Println("\033[34;1m++++++++++++++++++++++++++++++++++++++++++++++++++++++++\033[0m\033[31;1m")
    fmt.Println("                  ______     _______________            ")
    fmt.Println("                 /       \\  \\               \\           ")
    fmt.Println("                /    __   \\  \\___________   /           ")
    fmt.Println("               /    /  \\   \\         /    /             ")
    fmt.Println("              /    /    \\   \\       /    /              ")
    fmt.Println("             /    /______\\   \\   \033[34;1m<—+————+-}\033[0m\033[31;1m             ")
    fmt.Println("            /    __________   \\    |    |               ")
    fmt.Println("           /    /          \\   \\   |    |               ")
    fmt.Println("          /    /            \\   \\  |    |               ")
    fmt.Println("         /____/              \\___\\ |____|               ")
    fmt.Println("\033[0m\033[34;1m++++++++++++++++++++++++++++++++++++++++++++++++++++++++\033[0m")
    // tag3:别人的
    fmt.Println("\033[36m -------------------------------------------------------- \033[0m")
    fmt.Println("\033[31m     ██████╗  █████╗ ████████╗██╗  ██╗███████╗██████╗     \033[0m")
    fmt.Println("\033[31m    ██╔════╝ ██╔══██╗╚══██╔══╝██║  ██║██╔════╝██╔══██╗    \033[0m")
    fmt.Println("\033[31m    ██║  ███╗███████║   ██║   ███████║█████╗  ██████╔╝    \033[0m")
    fmt.Println("\033[31m    ██║   ██║██╔══██║   ██║   ██╔══██║██╔══╝  ██╔══██╗    \033[0m")
    fmt.Println("\033[31m    ╚██████╔╝██║  ██║   ██║   ██║  ██║███████╗██║  ██║    \033[0m")
    fmt.Println("\033[31m     ╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚═╝  ╚═╝╚══════╝╚═╝  ╚═╝    \033[0m")
    fmt.Println("\033[36m -------------------------------------------------------- \033[0m")
    // tag4,使用尖锐的角更显得严肃
    tag := `
________   |\
\   ___/___| | _______________|\   ___
 | |__/  __| |/ / __/  __/ _* | \ |* / 
 |  _/\ (__|   <\__ \ (_| (_| | |\| | ❤
 | |   \___| |\__\__/\___\__,_|__\\ |
 |/        |/   version: %8s  \|
`
    fmt.Printf(tag, version)
        // tag5
    tag := `
    ___  /|         /|            |\                |\
   /   |/ |        / |        ____| |__ ______  ____| | __
  / /| || |   __ __| |  _^_  /  __|  _ \   +  /   __| |/ / 
 | |_| || |/|/ //  _ |(_____)\ (__| | | |  __/\  (__|   < 
 |  _  || * ^ *|| |/ | | * |  \___| | |_\______\____| |\__\
 |_| | ||______/\__/\|  \_/       |/                |/
      \|                      比赛名称:` + YELLOW + competition + END
    fmt.Println(tag)
    // tag6:别人的
    fmt.Println("         ,;;;,     ")
    fmt.Println("        ;;;;;;;                   ")
    fmt.Println("     .- `\\, '/_      _____ _    ____  _                      _            ")
    fmt.Println("   .'   \\  (`(_)    |_   _| |_ |__ / (_)_ _  ____ __  ___ __| |_ ___ _ _ ")
    fmt.Println("  / `-,. \\ \\_/        | | | ' \\ |_ \\ | | ' \\(_-< '_ \\/ -_) _|  _/ _ \\ '_| ")
    fmt.Println("  \\  \\/ \\ `--`        |_| |_||_|___/ |_|_||_/__/ .__/\\___\\__|\\__\\___/_| V 1.9")
    fmt.Println("   \\  \\  \\                         \033[0;31m[\033[0;33m127.0.0.1\033[0;31m] \033[0;37m|_|\033[0;31m [\033[1;34m192.168.1.1\033[0;31m] \033[0;37m")
    fmt.Println("    / /| |                            \033[0;31m[\033[0;37mCoded BY Mohamed Riahi\033[0;31m]\033[0;37m")
    fmt.Println("   /_/ |_|      ")
    fmt.Println("  ( _\\ ( _\\    #:##       #:##")
    fmt.Println("                     #:## ")
}

2.3 切片去重

// 使用了1.18的泛型,如果使用的是go1.18以下版本建议改成对应类型
// 去重
// 去重函数
func RemoveDuplicate[T any](old []T) (result []T) {
    // 将第一个切片元素赋值,构建一个新的字符串切片
    result = old[:1]
    // 遍历str1的元素
    for _, word := range old {
        i := 0
        for ; i < len(result); i++ {
            if reflect.ValueOf(word).Interface() == reflect.ValueOf(result[i]).Interface() {
                break
            }
        }
        if i == len(result) {
            result = append(result, word)
        }
    }
    return result
}

// 或者
func RemoveDuplicate[T any](old []T) (result []T) {
    temp := map[any]struct{}{}
    for _, item := range old {
        if _, ok := temp[item]; !ok {
            temp[item] = struct{}{}
            result = append(result, item)
        }
    }
    return
}

2.4 排除内网IP

func DeleteLocalIP(iplist []string) []string {
    // 用于输出排除内网的字符串切片
    var out []string
    // 循环遍历iplist
    for _, v := range iplist {
        // 判断元素是否是内网地址,如果不是增加到out切片
        rege, _ := regexp.Compile(`^(127\.0\.0\.1)|(localhost)|(10\.\d{1,3}\.\d{1,3}\.\d{1,3})|(0.0.0.0)|(172\.((1[6-9])|(2\d)|(3[01]))\.\d{1,3}\.\d{1,3})|(192\.168\.\d{1,3}\.\d{1,3})$`)
        matched := rege.MatchString(v)
        if !matched {
            out = append(out, v)
        }
    }
    return out
}

2.5 IP的正则表达式

regexp.Compile(`[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}`)

2.6 终端颜色

// 终端颜色
var (
    ERR     string = "[\033[1;31m✘\033[0m]"
    RIGHT   string = "[\033[1;32m✓\033[0m]"
    WARNING string = "[\033[0;38;5;214m!\033[0m]"
    GREY    string = "\033[1;30m"
    RED     string = "\033[1;31m"
    GREEN   string = "\033[1;32m"
    YELLOW  string = "\033[1;33m"
    BLUE    string = "\033[1;34m"
    PURPLE  string = "\033[1;35m"
    MAIN    string = "\033[1;36m"
    ORANGE  string = "\033[0;38;5;214m"
    END     string = "\033[0m"
)
func Tag() {
    fmt.Printf("\x1b[%dmhello world 30: 黑 \x1b[0m\n", 30)
    fmt.Printf("\x1b[%dmhello world 31: 红 \x1b[0m\n", 31)
    fmt.Printf("\x1b[%dmhello world 32: 绿 \x1b[0m\n", 32)
    fmt.Printf("\x1b[%dmhello world 33: 黄 \x1b[0m\n", 33)
    fmt.Printf("\x1b[%dmhello world 34: 蓝 \x1b[0m\n", 34)
    fmt.Printf("\x1b[%dmhello world 35: 紫 \x1b[0m\n", 35)
    fmt.Printf("\x1b[%dmhello world 36: 深绿 \x1b[0m\n", 36)
    fmt.Printf("\x1b[%dmhello world 37: 白色 \x1b[0m\n", 37)

    fmt.Printf("\x1b[%d;%dmhello world \x1b[0m 47: 白色 30: 黑 \n", 47, 30)
    fmt.Printf("\x1b[%d;%dmhello world \x1b[0m 46: 深绿 31: 红 \n", 46, 31)
    fmt.Printf("\x1b[%d;%dmhello world \x1b[0m 45: 紫   32: 绿 \n", 45, 32)
    fmt.Printf("\x1b[%d;%dmhello world \x1b[0m 44: 蓝   33: 黄 \n", 44, 33)
    fmt.Printf("\x1b[%d;%dmhello world \x1b[0m 43: 黄   34: 蓝 \n", 43, 34)
    fmt.Printf("\x1b[%d;%dmhello world \x1b[0m 42: 绿   35: 紫 \n", 42, 35)
    fmt.Printf("\x1b[%d;%dmhello world \x1b[0m 41: 红   36: 深绿 \n", 41, 36)
    fmt.Printf("\x1b[%d;%dmhello world \x1b[0m 40: 黑   37: 白色 \n", 40, 37)
}

2.7 字符串类型的端口转换为int切片的端口

// 将字符串端口转换为int切片端口
func PortParse(port string) []int {
    var ports []int
    if port == "" {
        // 不设置端口,使用默认端口
        defPort := configs.DefaultPorts
        return defPort
    } else if len(regexp.MustCompile("-").FindAllStringIndex(port, -1)) == 1 {

        grep := regexp.MustCompile("(.*)-(.*)")
        // 获取IP段的头尾
        portHead := grep.FindStringSubmatch(port)[1]
        portTail := grep.FindStringSubmatch(port)[2]
        // 将IP的头尾转换成int类型
        intHead, _ := strconv.Atoi(portHead)
        intTail, _ := strconv.Atoi(portTail)
        // 赋值IP切片
        for p := intHead; p <= intTail; p++ {
            ports = append(ports, p)
        }
        return ports
    } else {
        // 将IP字符串分开
        CustomPorts := strings.Split(port, ",")
        // 迭代赋值给int切片
        for _, port := range CustomPorts {
            p, _ := strconv.Atoi(port)
            ports = append(ports, p)
        }
        return ports
    }
}

2.8 将int转换为字符串

int_1, _ := strconv.Atoi("asasas")
str_1 := strconv.Itoa(100)
fmt.Println(int_1)
fmt.Println(str_1)

2.9 Ping通主机以及判断操作系统类型

// hosthost是主机
// timeout是过期时间
func Ping(host string, timeout int) bool {
    // 将int类型的timeout转换为string类型的timeout
    var to = strconv.Itoa(timeout)
    // ping对应主机
    var cmd *exec.Cmd
    // 判断操作系统
    switch runtime.GOOS {
    case "windows":
        cmd = exec.Command("ping", host, "-n", "1", "-w", to)
    case "linux":
        cmd = exec.Command("ping", host, "-c", "1", "-w", to)
    case "darwin":
        cmd = exec.Command("ping", host, "-c", "1", "-W", to)
    }
    // 判断cmd是否为空
    if cmd == nil {
        return false
    }
    // 执行cmd的命令
    err := cmd.Run()
    return err == nil
}

2.10 实现SHA256生成散列值

package main
import (
    "crypto/sha256"
    "encoding/hex"
    "fmt"
)
//SHA256生成哈希值
func GetSHA256HashCode(str string)string{
    message := []byte(str)
    //方法一:
    //创建一个基于SHA256算法的hash.Hash接口的对象
    hash := sha256.New()
    //输入数据
    hash.Write(message)
    //计算哈希值
    bytes := hash.Sum(nil)
    //将字符串编码为16进制格式,返回字符串
    hashCode := hex.EncodeToString(bytes)
    //返回哈希值
    return hashCode
    
    //方法二:
    //bytes2:=sha256.Sum256(message)//计算哈希值,返回一个长度为32的数组
    //hashcode2:=hex.EncodeToString(bytes2[:])//将数组转换成切片,转换成16进制,返回字符串
    //return hashcode2
}
func main(){
    hashCode:=GetSHA256HashCode("hello world")
    fmt.Println(hashCode)
}

2.11 获取当前目录下所有文件

func GetAllFile(path string) []string {
    // 存放文件名
    filename := []string{}
    // 读取当前目录中的所有文件和子目录
    files, err := ioutil.ReadDir(path)
    if err != nil {
        panic(err)
    }
    // 获取文件,并输出它们的名字
    for _, file := range files {
        filename = append(filename, file.Name())
    }
    return filename
}

2.12 生成随机数

package main
 
import "fmt"
import "math/rand"
 
func main() {
 
    fmt.Println(rand.Intn(100)) //产生0-100的随机整数
 
    fmt.Println(rand.Float64()) //产生0.0-1.0的随机浮点点
 
    s1 := rand.NewSource(42) //用指定值创建一个随机数种子
    r1 := rand.New(s1)
    fmt.Print(r1.Intn(100), ",")
    fmt.Print(r1.Intn(100))
    fmt.Println()
 
    s2 := rand.NewSource(42) //同前面一样的种子
    r2 := rand.New(s2)
    fmt.Print(r2.Intn(100), ",")
    fmt.Print(r2.Intn(100))
    fmt.Println()
}

2.13 Base64编码

package main

import (
    "encoding/base64"
    "fmt"
)

func main() {
    info := []byte("https://www.bilibili.com/aa*()s/?=")
    fmt.Println("==============标准的Base64编码==============")
    encodeinfo := base64.StdEncoding.EncodeToString(info)
    decodeinfo, _ := base64.StdEncoding.DecodeString(encodeinfo)
    fmt.Printf("编码后:%s,解码后:%s\n", encodeinfo, decodeinfo)
    fmt.Println("==============URL的Base64编码==============")
    URLencodeinfo := base64.URLEncoding.EncodeToString(info)
    URLdecodeinfo, _ := base64.URLEncoding.DecodeString(URLencodeinfo)
    fmt.Printf("编码后:%s,解码后:%s\n", URLencodeinfo, URLdecodeinfo)
}

2.14 判断字符串是否包含某个字符

func main() {
    if find := strings.Contains("test-v1", "v1"); find {
        fmt.Println("find the character.")
    }
}

2.15 字符串反转

package main

import "fmt"

func main() {
    s := "foobar"
    a := []rune(s)
    fmt.Printf("%s\n", s)
    fmt.Printf("字符串逆转过程:\n")
    for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
        a[i], a[j] = a[j], a[i]
        fmt.Println(string(a))

    }
    fmt.Printf("%s\n", string(a))
}

2.16 读取json文件

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "os"
)

type Post struct { //带结构标签,反引号来包围字符串
    Id      int       `json:"id"`
    Content string    `json:"content"`
    Author  Author    `json:"author"`
    Comment []Comment `json:"comments"`
}

type Author struct {
    Id   int    `json:"id"`
    Name string `json:"name"`
}

type Comment struct {
    Id      int    `json:"id"`
    Content string `json:"content"`
    Author  string `json:"author"`
}

func main() {
    // 打开json文件
    jsonFile, err := os.Open("post.json")
    if err != nil {
        fmt.Println("不存在json文件!")
        return
    }
    defer jsonFile.Close()
    
    // 读取json文件
    jsonData, err := ioutil.ReadAll(jsonFile)
    if err != nil {
        fmt.Println("读取json文件错误!")
        return
    }
    fmt.Printf("JSON文件:%s\n", jsonData)
    var post Post
    // json文件反序列化
    json.Unmarshal(jsonData, &post)
    fmt.Printf("反序列化后文件的内容:%v\n",post)
}
// post.json
{
    "id": 1,
    "content": "hello golang",
    "author": {
      "id": 2,
      "name": "miller Fan"
    },
    "comments": [
      {
        "id": 3,
        "content": "Have a good night",
        "author": "屈原"
      },
      {
        "id": 4,
        "content": "道德经",
        "author": "老子"
      }
    ]
  }

2.17 进度条

package main

import (
    "fmt"
    "os"
    "strings"
    "time"
)

func main() {
    num := 100
    for i := 0; i <= num; i++ {
        // 时间50秒
        time.Sleep(50 * time.Millisecond)
        h := strings.Repeat("=", i) + strings.Repeat(" ", num-i)
        fmt.Printf("\r%3d%%[\x1b[1;0;%dm%s\x1b[0m]", i, 30+(i%7), h)
        os.Stdout.Sync()
    }
    fmt.Println("\n已完成!")
}

2.18 动态加载

package main

import (
    "fmt"
    "time"
)

func main() {
    // 需要启动一个线程
    // 需要控制top的值
    top := true
    fmt.Println("[\033[33;1m*\033[0m] 扫描开始!")
    go func() {
        for top {
            time.Sleep(100 * time.Millisecond)
            fmt.Printf("[\033[34;1m—\033[0m] 扫描中。。。\r")
            time.Sleep(100 * time.Millisecond)
            fmt.Printf("[\033[34;1m\\\033[0m] 扫描中。。。\r")
            time.Sleep(100 * time.Millisecond)
            fmt.Printf("[\033[34;1m|\033[0m] 扫描中。。。\r")
            time.Sleep(100 * time.Millisecond)
            fmt.Printf("[\033[34;1m/\033[0m] 扫描中。。。\r")
        }
        fmt.Println()
    }()
    for i := 0; i < 10; i++ {
        time.Sleep(1000 * time.Millisecond)
    }
    top = false
    fmt.Printf("\r")
    fmt.Println("\n[\033[33;1m*\033[0m] 扫描结束!")
}

2.19 汉字转拼音

package main

import (
    "fmt"

    "github.com/mozillazg/go-pinyin"
)

func main() {
    hans := "中国人"

    // 默认
    a := pinyin.NewArgs()
    fmt.Println(pinyin.Pinyin(hans, a))
    // [[zhong] [guo] [ren]]

    // 包含声调
    a.Style = pinyin.Tone
    fmt.Println(pinyin.Pinyin(hans, a))
    // [[zhōng] [guó] [rén]]

    // 声调用数字表示
    a.Style = pinyin.Tone2
    fmt.Println(pinyin.Pinyin(hans, a))
    // [[zho1ng] [guo2] [re2n]]

    // 开启多音字模式
    a = pinyin.NewArgs()
    a.Heteronym = true
    fmt.Println(pinyin.Pinyin(hans, a))
    // [[zhong zhong] [guo] [ren]]
    a.Style = pinyin.Tone2
    fmt.Println(pinyin.Pinyin(hans, a))
    // [[zho1ng zho4ng] [guo2] [re2n]]

    fmt.Println(pinyin.LazyPinyin(hans, pinyin.NewArgs()))
    // [zhong guo ren]

    fmt.Println(pinyin.Convert(hans, nil))
    // [[zhong] [guo] [ren]]

    fmt.Println(pinyin.LazyConvert(hans, nil))
    // [zhong guo ren]
    
    name := ""
    for _, val := range pinyin.LazyConvert(hans, nil) {
        name += val
    }
    fmt.Println(name)
    // zhongguoren
}

2.20 获取客户端IP

package main

import (
    "flag"
    "fmt"
    "net/http"

    "github.com/gin-gonic/gin"
)

func getip(c *gin.Context) {
    // 获取客户端真实ip地址
    reqIP := c.ClientIP()
    if reqIP == "::1" {
        reqIP = "127.0.0.1"
    }
    fmt.Println("\x1b[33m[*]\x1b[0m 客户端的的IP为" + reqIP)
    c.String(http.StatusOK, "[+] 您访问的的IP为"+reqIP)
}

func main() {
    var port string
    flag.StringVar(&port, "p", "8082", "监听的端口")
    flag.Parse()
    fmt.Println("\x1b[32m[+]\x1b[0m 默认监听8082端口!")
    r := gin.Default()
    // 如果应用程序不在代理之后,“ForwardedByClientIP”应设置为 false,因此“X-Forwarded-For”将被忽略。
    // 如果在代理后面将其设置为true
    r.ForwardedByClientIP = true
    r.GET("/", getip)
    r.Run(":" + port)
}

2.21 格式化用户输入的IP

// IP的形式无非4种:逗号隔开,/和-连续的形式,以及单个IP
// 由于逗号是一个分类大方向,所以先是判断逗号的,然后根据/和-连续这两种不同形式,进行划分,分出-和/,然后/的格式单一,所以统一转换成-格式,最后转换成单个
package main

import (
    "flag"
    "fmt"
    "math/rand"
    "net"
    "regexp"
    "strconv"
    "strings"
)

// 处理ip
func ProcessIPs(ips string) (hostlist []string) {
    // 判断是否有逗号
    if strings.Contains(ips, ",") {
        // 如果有逗号将其划分多个IP表
        IPList := strings.Split(ips, ",")
        // 存放IP用与hosts变量一致
        var ips []string
        // 循环处理IP表
        for _, ip := range IPList {
            ips = parseIP(ip)
            hostlist = append(hostlist, ips...)
        }
    } else {
        hostlist = parseIP(ips)
    }
    return RemoveDuplicate(hostlist)
}

// 根据用户给出的ip形式进行分类
func parseIP(ip string) []string {
    reg := regexp.MustCompile(`[a-zA-Z]+`)
    switch {
    case strings.HasSuffix(ip, "/8"):
        // 扫描/8时,由于A段太多了,只扫网关和随机IP,避免扫描过多IP
        return parseIP8(ip)
    case strings.Contains(ip, "/"):
        // 解析 /24 /16等
        return parseIP2(ip)
    case reg.MatchString(ip):
        // 域名用lookup获取ip
        host, err := net.LookupHost(ip)
        if err != nil {
            return nil
        }
        return host
    case strings.Contains(ip, "-"):
        // 处理192.168.1.1-192.168.1.100或者192.168.1.1-24
        return parseIP1(ip)
    default:
        // 处理单个ip
        testIP := net.ParseIP(ip)
        if testIP == nil {
            return nil
        }
        return []string{ip}
    }
}

// 把 192.168.x.x/xx 转换成IP列表
func parseIP2(host string) (hosts []string) {
    // 使用 net.ParseCIDR() 方法解析给定的网段,返回网段的 IP 地址和子网掩码
    // 检查给定的网段是否正确
    ipone, ipNet, err := net.ParseCIDR(host)
    if err != nil {
        return
    }
    // 把 192.168.x.x/xx 转换成 192.168.x.x-192.168.x.x 并转成IP列表
    hosts = parseIP1(IPRange(ipone.String(), ipNet))
    return
}

// 解析ip段: 192.168.111.1-255,192.168.111.1-192.168.112.255
func parseIP1(ip string) []string {
    // 如果有逗号将其划分多个
    IPRangelist := strings.Split(ip, "-")
    // 确认该IP格式是否为正确IP
    testIP := net.ParseIP(IPRangelist[0])
    // 创建一个存储所有IP列表
    var allIP []string
    // 通过len函数来确认IPRangelist[1]是192.168.1.255形式还是数字形式
    if len(IPRangelist[1]) < 4 {
        // 处理数字形式
        // 将字符串转成数字
        Range, err := strconv.Atoi(IPRangelist[1])
        // 判断合理性
        if testIP == nil || Range > 255 || err != nil {
            return nil
        }
        // 分离IP
        SplitIP := strings.Split(IPRangelist[0], ".")
        // 转换为数字
        ip1, err1 := strconv.Atoi(SplitIP[3])
        // 拼接
        PrefixIP := SplitIP[0] + "." + SplitIP[1] + "." + SplitIP[2]
        // 判断合理性
        if ip1 > Range || err1 != nil {
            return nil
        }
        // 循环拼接IP
        for i := ip1; i <= Range; i++ {
            allIP = append(allIP, PrefixIP+"."+strconv.Itoa(i))
        }
    } else {
        // 处理192.168.1.255形式
        // 分离IP
        SplitIP1 := strings.Split(IPRangelist[0], ".")
        SplitIP2 := strings.Split(IPRangelist[1], ".")
        // 判断合理性
        if len(SplitIP1) != 4 || len(SplitIP2) != 4 {
            return nil
        }
        // 用于存放起始IP和结束IP列表
        start, end := [4]int{}, [4]int{}
        // 循环读取4段IP
        for i := 0; i < 4; i++ {
            // 转换为数字
            ip1, err1 := strconv.Atoi(SplitIP1[i])
            ip2, err2 := strconv.Atoi(SplitIP2[i])
            // 判断合理性
            if ip1 > ip2 || err1 != nil || err2 != nil {
                return nil
            }
            // 添加到起始IP和结束IP列表
            start[i], end[i] = ip1, ip2
        }
        // 通过移位运算,将地址改为数字的形式
        startNum := start[0]<<24 | start[1]<<16 | start[2]<<8 | start[3]
        endNum := end[0]<<24 | end[1]<<16 | end[2]<<8 | end[3]
        // 通过循环将数字转成地址
        for num := startNum; num <= endNum; num++ {
            ip := strconv.Itoa((num>>24)&0xff) + "." + strconv.Itoa((num>>16)&0xff) + "." + strconv.Itoa((num>>8)&0xff) + "." + strconv.Itoa((num)&0xff)
            allIP = append(allIP, ip)
        }
    }
    return allIP
}

// 获取把 192.168.x.x/xx 转换成 192.168.x.x-192.168.x.x的起始IP、结束IP
func IPRange(start string, c *net.IPNet) string {
    // 16进制子网掩码
    mask := c.Mask
    // 创建一个net.ip类型
    bcst := make(net.IP, len(c.IP))
    // 将dreams值给bcst
    copy(bcst, c.IP)
    // 获取结束IP
    for i := len(mask) - 1; i >= 0; i-- {
        bcst[i] = c.IP[i] | ^mask[i]
    }
    end := bcst.String()
    // 返回用-表示的ip段,192.168.1.1-192.168.255.255
    return fmt.Sprintf("%s-%s", start, end)
}

// 处理B段IP
func parseIP8(ip string) []string {
    // 去掉最后的/8
    realIP := ip[:len(ip)-2]
    // net.ParseIP 这个方法用来检查 ip 地址是否正确,如果不正确,该方法返回 nil
    testIP := net.ParseIP(realIP)
    // 判断该IP是否为正常IP
    if testIP == nil {
        return nil
    }
    // 获取IP的头部
    IP8head := strings.Split(ip, ".")[0]
    // 存放B段IP
    var allIP []string
    // 构造B段的随机IP表
    for a := 0; a <= 255; a++ {
        for b := 0; b <= 255; b++ {
            // 一般情况下网关为1或者254
            allIP = append(allIP, fmt.Sprintf("%s.%d.%d.%d", IP8head, a, b, 1))
            allIP = append(allIP, fmt.Sprintf("%s.%d.%d.%d", IP8head, a, b, RandInt(2, 80)))
            allIP = append(allIP, fmt.Sprintf("%s.%d.%d.%d", IP8head, a, b, RandInt(81, 170)))
            allIP = append(allIP, fmt.Sprintf("%s.%d.%d.%d", IP8head, a, b, RandInt(171, 253)))
            allIP = append(allIP, fmt.Sprintf("%s.%d.%d.%d", IP8head, a, b, 254))
        }
    }
    return allIP
}

// 去重函数
func RemoveDuplicate(old []string) []string {
    result := []string{}
    temp := map[string]struct{}{}
    for _, item := range old {
        if _, ok := temp[item]; !ok {
            temp[item] = struct{}{}
            result = append(result, item)
        }
    }
    return result
}

// 随机数
func RandInt(min, max int) int {
    if min >= max || min == 0 || max == 0 {
        return max
    }
    return rand.Intn(max-min) + min
}

// 主函数
func main() {
    // 定义命令行参数方式
    var IPs string
    flag.StringVar(&IPs, "ip", "", "ip地址")
    // 解析命令行参数
    flag.Parse()
    // 判断是否输入IP
    if IPs == "" {
        fmt.Println("[\033[31;1m-\033[0m] 没有输入IP!")
        flag.Usage()
        return
    }
    // 对用户输入的IP参数进行格式化处理
    hosts := ProcessIPs(IPs)
    for i, val := range hosts {
        fmt.Println(i, val)
    }
}

2.22 文件写入

// 文件写入
func WriteFile(result string, filename string) {
    var text = []byte(result + "\n")
    f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        fmt.Printf("[\033[31;1m-\033[0m] 打开文件 %s 失败, %v\n", filename, err)
        return
    }
    _, err = f.Write(text)
    f.Close()
    if err != nil {
        fmt.Printf("[\033[31;1m-\033[0m] 写入文件 %s 失败, %v\n", filename, err)
    }
}

2.23 判断字符串是否在列表中

// 判断字符串是否在列表中
func strinlist(str string, str_array []string) bool {
    for _, s := range str_array{
       if str == s{
           return true
       }
   }
   return false
}

2.24 读取json文件内容并设置为结构体

// 读取json文件
func Readjsonfile(filename string) ([]jsonType, error) {
    // 设置json文件列表
    // jsonType是自定义的结构体,用来反序列化的
    var jsonlist []jsonType
    data, err := ioutil.ReadFile(filename)
    if err != nil {
        return nil, err
    }
    err = json.Unmarshal(data, &jsonlist)
    if err != nil {
        return nil, err
    }
    return jsonlist, nil
}

2.25 结构体转换为json文件

// 结构体转换为json
func Switchjson(date []AvType) error {
    jsonByteData, err := json.Marshal(date)
    if err != nil {
        return err
    }
    // 这里使用了前面 2.22 文件写入方法
    WriteFile(string(jsonByteData), "demo.json")
    return nil
}

2.26 格式化用户输入的端口

// 端口格式化与IP格式化差不多
package main

import (
    "flag"
    "fmt"
    "strconv"
    "strings"
)

// 格式化处理端口
func ParsePort(ports string) (scanPorts []int) {
    // 判断端口是否为空
    if ports == "" {
        return
    }
    // 根据逗号切割端口
    slices := strings.Split(ports, ",")
    // 循环获取端口
    for _, port := range slices {
        // 去除空白符
        port = strings.TrimSpace(port)
        // 判断去除后空白符的端口是否正确
        if port == "" {
            continue
        }
        upper := port
        // 判断端口是否有-这样连续的
        if strings.Contains(port, "-") {
            // 分离端口
            ranges := strings.Split(port, "-")
            // 判断分离出的端口是否多个
            if len(ranges) < 2 {
                continue
            }
            // 设置端口范围的开始和结束
            startPort, _ := strconv.Atoi(ranges[0])
            endPort, _ := strconv.Atoi(ranges[1])
            if startPort < endPort {
                port = ranges[0]
                upper = ranges[1]
            } else {
                port = ranges[1]
                upper = ranges[0]
            }
        }
        // 赋值
        start, _ := strconv.Atoi(port)
        end, _ := strconv.Atoi(upper)
        // 将端口赋值给scanPorts
        for i := start; i <= end; i++ {
            scanPorts = append(scanPorts, i)
        }
    }
    // 端口去重
    scanPorts = removeDuplicate(scanPorts)
    return scanPorts
}

// 去重函数
func removeDuplicate(old []int) []int {
    result := []int{}
    temp := map[int]struct{}{}
    for _, item := range old {
        if _, ok := temp[item]; !ok {
            temp[item] = struct{}{}
            result = append(result, item)
        }
    }
    return result
}

// 主函数
func main() {
    // 定义命令行参数方式
    var Ports string
    flag.StringVar(&Ports, "p", "", "端口")
    // 解析命令行参数
    flag.Parse()
    // 判断是否输入Port
    if Ports == "" {
        fmt.Println("[\033[31;1m-\033[0m] 没有输入Ports!")
        flag.Usage()
        return
    }
    // 对用户输入的IP参数进行格式化处理
    Portslist := ParsePort(Ports)
    for i, val := range Portslist {
        fmt.Println(i, val)
    }
}

2.27 快速判断文件类型

在正常情况下,我们需要判断文件类型有两种方法:

  • 根据文件的扩展名来判断,比如.jpg表示JPEG图像,.mp3表示MP3音频等
    • 优点:简单快速
    • 缺点:容易被伪造或者缺失
  • 根据文件内容的特征来判断,比如JPEG图像的前几个字节是FF D8 FFMP3音频的前几个字节是ID3等。
    • 优点:准确可靠
    • 缺点:需要读取文件内容并进行分析

而在Go语言的标准库net/http包中提供了一个简单的判断文件类型的方法DetectContentType(),该方法是读取文件内容的前512个字节内容,返回一个MIME类型字符串。它使用了mimesniff算法,根据一组预定义的规则来匹配文件内容的特征和对应的MIME类型。这个方法既不依赖于文件扩展名,也不需要完整地读取文件内容,因此既快速又准确。同时我们可以使用mime.ExtensionsByType获取该类型可能的后缀名:

package main

import (
    "fmt"
    "log"
    "mime"
    "net/http"
    "os"
)

// 处理错误方法
func HandlingErrors(err error, funname string) {
    if err != nil {
        fmt.Println("[\033[31;1m-\033[0m] ", funname, "Error:", err)
        log.Panic(err)
    }
}
func main() {
    // 打开一个 MP3 文件
    file, err := os.Open("a.jpg")
    if err != nil {
        fmt.Println(err)
        return
    }
    // 关闭文件
    defer file.Close()

    // 读取文件的前 512 个字节到一个缓冲区
    buffer := make([]byte, 512)
    n, err := file.Read(buffer)
    if err != nil {
        HandlingErrors(err, "file.Read")
    }

    // 调用 http.DetectContentType 方法判断文件类型,并传入了缓冲区中的数据,这个方法会返回一个字符串表示文件的 MIME 类型
    // 实际上,如果字节数超过 512,该函数也只会使用前 512 个字节
    contentType := http.DetectContentType(buffer[:n])
    // 返回文件类型可能的文件后缀名
    ext, err := mime.ExtensionsByType(contentType)
    if err != nil {
        HandlingErrors(err, "mime.ExtensionsByType")
    }
    // 输出文件类型
    fmt.Println("[\033[0;38;5;214m!\033[0m] 文件类型为:", contentType)
    // 输出文件类型可能的文件后缀名
    fmt.Println("[\033[0;38;5;214m!\033[0m]", contentType, "类型可能的后缀名:", ext)
}

2.28 搭建http文件下载服务

package main

import (
    "flag"
    "fmt"
    "io/fs"
    "io/ioutil"
    "net/http"
    "os"
    "strconv"
)

// 获取文件信息
func getfile() ([]fs.FileInfo, error) {
    directory := "./"
    files, err := os.Open(directory)
    if err != nil {
        fmt.Println("打开目录时出错:", err)
        return nil, err
    }
    defer files.Close()

    fileInfos, err := files.Readdir(-1)
    if err != nil {
        fmt.Println("读取目录时出错:", err)
        return nil, err
    }
    return fileInfos, nil
}

// 显示首页
func index(rw http.ResponseWriter, r *http.Request) {
    files, err := getfile()
    if err != nil {
        fmt.Fprintln(rw, err)
    }
    html := ""
    for _, val := range files {
        html = html + "<a href='download?filename=" + val.Name() + "'>" + val.Name() + "</a></br>"
    }
    fmt.Fprintln(rw, html)

}

// 下载功能
func download(rw http.ResponseWriter, r *http.Request) {
    //获取请求参数
    fn := r.FormValue("filename")
    //设置响应头
    header := rw.Header()
    header.Add("Content-Type", "application/octet-stream")
    header.Add("Content-Disposition", "attachment;filename="+fn)
    //使用ioutil包读取文件
    b, _ := ioutil.ReadFile(fn)
    //写入到响应流中
    rw.Write(b)
}

func main() {
    // 设置端口
    var port int
    flag.IntVar(&port, "p", 9090, "自定义端口")
    // 解析命令行参数
    flag.Parse()
    if port <= 0 || port > 65535 {
        fmt.Printf("[x] 该端口不合规!\n")
        return
    }
    fmt.Println("[!] 服务端口为:" + strconv.Itoa(port))
    http.HandleFunc("/", index)
    http.HandleFunc("/download", download)
    err := http.ListenAndServe(":"+strconv.Itoa(port), nil)
    if err != nil {
        fmt.Printf("[x] http服务器失败,err:%v\n", err)
        return
    }
}

2.29 判断为空方法

func main() {
    // 判断字符串为空
    str := ""
    if str != "" {
        fmt.Println("字符串为空")
    }

    // 判断数组或者切片为空
    List := []string{}
    if len(List) != 0 {
        fmt.Println("数组为空")
    }

    // 判断map为空
    Map := make(map[string]int)
    if len(Map) != 0 {
        fmt.Println("数组为空")
    }
}

2.30 以行的方式读取文件内的字符串

// 读取文件并以[]string形式返回内容
func ReadingLines(filename string) []string {
    // 设置结果变量
    var result []string
    // 打开文件
    file, err := os.Open(filename)
    if err != nil {
        return result
    }
    defer file.Close()
    // 开始读取文件
    scanner := bufio.NewScanner(file)
    // 循环读取
    for scanner.Scan() {
        val := scanner.Text()
        // 判断是否为空
        if val == "" {
            continue
        }
        // 拼接
        result = append(result, val)
    }
    // 判断是否存在终止错误
    if err := scanner.Err(); err != nil {
        return result
    }
    return result
}
avatar
小C&天天

修学储能 先博后渊


今日诗句