iotest.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/base64"
  5. "flag"
  6. "fmt"
  7. "io/ioutil"
  8. "math"
  9. "math/rand"
  10. "os"
  11. "path"
  12. "path/filepath"
  13. "strconv"
  14. "sync/atomic"
  15. "time"
  16. "git.wecise.com/wecise/common/matrix/logger"
  17. )
  18. // 一个持续并发文件读写验证的程序
  19. // 在指定目录下写入一些随机内容的文本文件
  20. // 写入完成后读取并验证写入文件内容的正确性
  21. // 验证正确后在指定的延时时间后将文件删除
  22. // 文件尺寸可以在指定的范围内随机生成
  23. // 所有可指定变量以命令行参数形式传入,并设有默认值
  24. // 每秒在控制台输出验证成功的文件计数信息
  25. // 验证内容不一致时保留文件不删除,提示验证失败的文件路径,程序结束。
  26. func init() {
  27. logger.SetFormat("yyyy-MM-dd HH:mm:ss [pid] [level] msg", "\n")
  28. logger.SetRollingFile("", "iotest.log", -1, 1*1024*1024, math.MaxInt64, 1)
  29. }
  30. func writefile(filePath string, content []byte) (err error) {
  31. dir := path.Dir(filePath)
  32. f, e := os.Stat(dir)
  33. if os.IsNotExist(e) || !f.IsDir() {
  34. if err = os.MkdirAll(dir, os.ModePerm); err != nil {
  35. return
  36. }
  37. }
  38. // 写入文件
  39. err = ioutil.WriteFile(filePath, content, 0777)
  40. return
  41. }
  42. func readfile(filePath string) ([]byte, error) {
  43. return ioutil.ReadFile(filePath)
  44. }
  45. func main() {
  46. // 设置命令行参数
  47. rootPath := flag.String("root-path", "_test", "文件目录")
  48. delay := flag.Duration("delay", 30*time.Second, "删除延迟时间")
  49. concurLimit := flag.Int("concur-limit", 10, "最大并发数")
  50. fileSizeMin := flag.Int("file-size-min", 1024, "最小文件尺寸")
  51. fileSizeMax := flag.Int("file-size-max", 10240, "最大文件尺寸")
  52. flag.Parse()
  53. // 初始化随机数生成器
  54. rand.Seed(time.Now().UnixNano())
  55. type fileinfo struct {
  56. filepath string
  57. filesize int
  58. checksum uint64
  59. content string
  60. }
  61. checkChan := make(chan *fileinfo, *concurLimit)
  62. logger.Info("开始验证")
  63. // 并发写入文件
  64. go func() {
  65. writeChan := make(chan struct{}, *concurLimit)
  66. for i := 0; ; i++ {
  67. // 并发控制
  68. writeChan <- struct{}{}
  69. go func(i int) {
  70. defer func() {
  71. <-writeChan
  72. }()
  73. // 随机生成文件名和文件内容
  74. dirName := strconv.Itoa(rand.Intn(100))
  75. fileName := strconv.Itoa(i) + ".txt"
  76. filePath := filepath.Join(*rootPath, dirName, fileName)
  77. fileBinarySize := (rand.Intn(*fileSizeMax-*fileSizeMin) + *fileSizeMin) / 4 * 3 // 二进制长度
  78. // 随机生成文件名和文件内容
  79. bs := make([]byte, fileBinarySize)
  80. rand.Read(bs)
  81. content := base64.RawURLEncoding.EncodeToString(bs)
  82. // 写入文件
  83. if err := writefile(filePath, []byte(content)); err != nil {
  84. logger.Error("写入文件", filePath, "失败:", err)
  85. return
  86. }
  87. // 写入完成
  88. checkChan <- &fileinfo{
  89. filepath: filePath,
  90. filesize: len(content),
  91. content: content,
  92. }
  93. }(i)
  94. }
  95. }()
  96. var successCount int32
  97. // 并发验证和删除文件
  98. go func() {
  99. for fi := range checkChan {
  100. go func(fi *fileinfo) {
  101. // 读取文件
  102. content, err := readfile(fi.filepath)
  103. if err != nil {
  104. logger.Error("读取文件", fi.filepath, "失败:", err)
  105. return
  106. }
  107. // 验证文件内容是否正确
  108. expectedSize := fi.filesize
  109. if len(content) != expectedSize || !bytes.Equal(content, []byte(fi.content)) {
  110. logger.Error("验证失败", fi.filepath, fmt.Sprintf("文件内容与期望值不一致,写入内容为:\n%s\n读出内容为:\n%s", string(content), fi.content))
  111. os.Exit(1)
  112. return
  113. }
  114. // 验证成功,统计计数
  115. atomic.AddInt32(&successCount, 1)
  116. // 延迟删除文件
  117. time.AfterFunc(*delay, func() {
  118. if err := os.Remove(fi.filepath); err != nil {
  119. logger.Error("删除文件", fi.filepath, "失败:", err)
  120. }
  121. })
  122. }(fi)
  123. }
  124. }()
  125. t := time.NewTicker(2 * time.Second)
  126. for {
  127. select {
  128. case <-t.C:
  129. // 输出计数信息
  130. logger.Info("验证成功的文件数:", successCount)
  131. }
  132. }
  133. }