csv.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. package utils
  2. import (
  3. "encoding/csv"
  4. "fmt"
  5. "log"
  6. "net"
  7. "os"
  8. "strconv"
  9. "time"
  10. )
  11. const (
  12. defaultOutput = "result.csv"
  13. maxDelay = 9999 * time.Millisecond
  14. minDelay = 0 * time.Millisecond
  15. )
  16. var (
  17. InputMaxDelay = maxDelay
  18. InputMinDelay = minDelay
  19. Output = defaultOutput
  20. PrintNum = 10
  21. )
  22. // 是否打印测试结果
  23. func NoPrintResult() bool {
  24. return PrintNum == 0
  25. }
  26. // 是否输出到文件
  27. func noOutput() bool {
  28. return Output == "" || Output == " "
  29. }
  30. type PingData struct {
  31. IP *net.IPAddr
  32. Sended int
  33. Received int
  34. Delay time.Duration
  35. }
  36. type CloudflareIPData struct {
  37. *PingData
  38. recvRate float32
  39. DownloadSpeed float64
  40. }
  41. func (cf *CloudflareIPData) getRecvRate() float32 {
  42. if cf.recvRate == 0 {
  43. pingLost := cf.Sended - cf.Received
  44. cf.recvRate = float32(pingLost) / float32(cf.Sended)
  45. }
  46. return cf.recvRate
  47. }
  48. func (cf *CloudflareIPData) toString() []string {
  49. result := make([]string, 6)
  50. result[0] = cf.IP.String()
  51. result[1] = strconv.Itoa(cf.Sended)
  52. result[2] = strconv.Itoa(cf.Received)
  53. result[3] = strconv.FormatFloat(float64(cf.getRecvRate()), 'f', 2, 32)
  54. result[4] = strconv.FormatFloat(cf.Delay.Seconds()*1000, 'f', 2, 32)
  55. result[5] = strconv.FormatFloat(cf.DownloadSpeed/1024/1024, 'f', 2, 32)
  56. return result
  57. }
  58. func ExportCsv(data []CloudflareIPData) {
  59. if noOutput() || len(data) == 0 {
  60. return
  61. }
  62. fp, err := os.Create(Output)
  63. if err != nil {
  64. log.Fatalf("创建文件[%s]失败:%v", Output, err)
  65. return
  66. }
  67. defer fp.Close()
  68. w := csv.NewWriter(fp) //创建一个新的写入文件流
  69. _ = w.Write([]string{"IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)"})
  70. _ = w.WriteAll(convertToString(data))
  71. w.Flush()
  72. }
  73. func convertToString(data []CloudflareIPData) [][]string {
  74. result := make([][]string, 0)
  75. for _, v := range data {
  76. result = append(result, v.toString())
  77. }
  78. return result
  79. }
  80. type PingDelaySet []CloudflareIPData
  81. func (s PingDelaySet) FilterDelay() (data PingDelaySet) {
  82. if InputMaxDelay > maxDelay || InputMinDelay < minDelay {
  83. return s
  84. }
  85. for _, v := range s {
  86. if v.Delay > InputMaxDelay { // 平均延迟上限
  87. break
  88. }
  89. if v.Delay < InputMinDelay { // 平均延迟下限
  90. continue
  91. }
  92. data = append(data, v) // 延迟满足条件时,添加到新数组中
  93. }
  94. return
  95. }
  96. func (s PingDelaySet) Len() int {
  97. return len(s)
  98. }
  99. func (s PingDelaySet) Less(i, j int) bool {
  100. iRate, jRate := s[i].getRecvRate(), s[j].getRecvRate()
  101. if iRate != jRate {
  102. return iRate < jRate
  103. }
  104. return s[i].Delay < s[j].Delay
  105. }
  106. func (s PingDelaySet) Swap(i, j int) {
  107. s[i], s[j] = s[j], s[i]
  108. }
  109. // 下载速度排序
  110. type DownloadSpeedSet []CloudflareIPData
  111. func (s DownloadSpeedSet) Len() int {
  112. return len(s)
  113. }
  114. func (s DownloadSpeedSet) Less(i, j int) bool {
  115. return s[i].DownloadSpeed > s[j].DownloadSpeed
  116. }
  117. func (s DownloadSpeedSet) Swap(i, j int) {
  118. s[i], s[j] = s[j], s[i]
  119. }
  120. func (s DownloadSpeedSet) Print() {
  121. if NoPrintResult() {
  122. return
  123. }
  124. if len(s) <= 0 { // IP数组长度(IP数量) 大于 0 时继续
  125. fmt.Println("\n[信息] 完整测速结果 IP 数量为 0,跳过输出结果。")
  126. return
  127. }
  128. dateString := convertToString(s) // 转为多维数组 [][]String
  129. if len(dateString) < PrintNum { // 如果IP数组长度(IP数量) 小于 打印次数,则次数改为IP数量
  130. PrintNum = len(dateString)
  131. }
  132. headFormat := "%-16s%-5s%-5s%-5s%-6s%-11s\n"
  133. dataFormat := "%-18s%-8s%-8s%-8s%-10s%-15s\n"
  134. for i := 0; i < PrintNum; i++ { // 如果要输出的 IP 中包含 IPv6,那么就需要调整一下间隔
  135. if len(dateString[i][0]) > 15 {
  136. headFormat = "%-40s%-5s%-5s%-5s%-6s%-11s\n"
  137. dataFormat = "%-42s%-8s%-8s%-8s%-10s%-15s\n"
  138. break
  139. }
  140. }
  141. fmt.Printf(headFormat, "IP 地址", "已发送", "已接收", "丢包率", "平均延迟", "下载速度 (MB/s)")
  142. for i := 0; i < PrintNum; i++ {
  143. fmt.Printf(dataFormat, dateString[i][0], dateString[i][1], dateString[i][2], dateString[i][3], dateString[i][4], dateString[i][5])
  144. }
  145. if !noOutput() {
  146. fmt.Printf("\n完整测速结果已写入 %v 文件,可使用记事本/表格软件查看。\n", Output)
  147. }
  148. }