fscan/Common/parsers/FileReader.go
ZacharyZcR 2f9c213e80 refactor: 系统性清理common包中的死代码和未使用变量
主要清理内容:
- logging包:移除DetailedFormatter、JSONFormatter及相关方法
- output包:清理Manager和Statistics中的未使用方法
- parsers包:移除各Parser中的Validate()和GetStatistics()方法
- proxy包:清理Factory和Global中的所有未使用函数
- ProgressManager:移除未使用的进度条方法和字段
- globals:清理未使用的status变量

技术改进:
- 使用deadcode和golangci-lint工具系统性检测
- 保持代码结构清晰,添加清理注释
- 修复相关依赖引用问题
- 确保编译通过和功能正常

代码减少:移除约40个死代码函数和多个未使用字段
2025-08-06 08:14:00 +08:00

291 lines
7.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package parsers
import (
"bufio"
"context"
"fmt"
"os"
"strings"
"sync"
"time"
)
// FileReader 高性能文件读取器
type FileReader struct {
mu sync.RWMutex
cache map[string]*FileResult // 文件缓存
maxCacheSize int // 最大缓存大小
enableCache bool // 是否启用缓存
maxFileSize int64 // 最大文件大小
timeout time.Duration // 读取超时
enableValidation bool // 是否启用内容验证
}
// FileResult 文件读取结果
type FileResult struct {
Lines []string `json:"lines"`
Source *FileSource `json:"source"`
ReadTime time.Duration `json:"read_time"`
ValidLines int `json:"valid_lines"`
Errors []error `json:"errors,omitempty"`
Cached bool `json:"cached"`
}
// NewFileReader 创建文件读取器
func NewFileReader(options *FileReaderOptions) *FileReader {
if options == nil {
options = DefaultFileReaderOptions()
}
return &FileReader{
cache: make(map[string]*FileResult),
maxCacheSize: options.MaxCacheSize,
enableCache: options.EnableCache,
maxFileSize: options.MaxFileSize,
timeout: options.Timeout,
enableValidation: options.EnableValidation,
}
}
// FileReaderOptions 文件读取器选项
type FileReaderOptions struct {
MaxCacheSize int // 最大缓存文件数
EnableCache bool // 启用文件缓存
MaxFileSize int64 // 最大文件大小(字节)
Timeout time.Duration // 读取超时
EnableValidation bool // 启用内容验证
TrimSpace bool // 自动清理空白字符
SkipEmpty bool // 跳过空行
SkipComments bool // 跳过注释行(#开头)
}
// DefaultFileReaderOptions 默认文件读取器选项
func DefaultFileReaderOptions() *FileReaderOptions {
return &FileReaderOptions{
MaxCacheSize: 10,
EnableCache: true,
MaxFileSize: 50 * 1024 * 1024, // 50MB
Timeout: 30 * time.Second,
EnableValidation: true,
TrimSpace: true,
SkipEmpty: true,
SkipComments: true,
}
}
// ReadFile 读取文件内容
func (fr *FileReader) ReadFile(filename string, options ...*FileReaderOptions) (*FileResult, error) {
if filename == "" {
return nil, NewParseError("FILE_ERROR", "文件名为空", filename, 0, ErrEmptyInput)
}
// 检查缓存
if fr.enableCache {
if result := fr.getFromCache(filename); result != nil {
result.Cached = true
return result, nil
}
}
// 合并选项
opts := fr.mergeOptions(options...)
// 创建带超时的上下文
ctx, cancel := context.WithTimeout(context.Background(), fr.timeout)
defer cancel()
// 异步读取文件
resultChan := make(chan *FileResult, 1)
errorChan := make(chan error, 1)
go func() {
result, err := fr.readFileSync(filename, opts)
if err != nil {
errorChan <- err
} else {
resultChan <- result
}
}()
// 等待结果或超时
select {
case result := <-resultChan:
// 添加到缓存
if fr.enableCache {
fr.addToCache(filename, result)
}
return result, nil
case err := <-errorChan:
return nil, err
case <-ctx.Done():
return nil, NewParseError("TIMEOUT", "文件读取超时", filename, 0, ctx.Err())
}
}
// =============================================================================================
// 已删除的死代码未使用ReadFiles 并发读取多个文件的方法
// =============================================================================================
// readFileSync 同步读取文件
func (fr *FileReader) readFileSync(filename string, options *FileReaderOptions) (*FileResult, error) {
startTime := time.Now()
// 检查文件
fileInfo, err := os.Stat(filename)
if err != nil {
return nil, NewParseError("FILE_ERROR", "文件不存在或无法访问", filename, 0, err)
}
// 检查文件大小
if fileInfo.Size() > fr.maxFileSize {
return nil, NewParseError("FILE_ERROR",
fmt.Sprintf("文件过大: %d bytes, 最大限制: %d bytes", fileInfo.Size(), fr.maxFileSize),
filename, 0, nil)
}
// 打开文件
file, err := os.Open(filename)
if err != nil {
return nil, NewParseError("FILE_ERROR", "无法打开文件", filename, 0, err)
}
defer file.Close()
// 创建结果
result := &FileResult{
Lines: make([]string, 0),
Source: &FileSource{
Path: filename,
Size: fileInfo.Size(),
ModTime: fileInfo.ModTime(),
},
}
// 读取文件内容
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
lineNum := 0
validLines := 0
for scanner.Scan() {
lineNum++
line := scanner.Text()
// 处理行内容
if processedLine, valid := fr.processLine(line, options); valid {
result.Lines = append(result.Lines, processedLine)
validLines++
}
}
// 检查扫描错误
if err := scanner.Err(); err != nil {
return nil, NewParseError("READ_ERROR", "文件扫描失败", filename, lineNum, err)
}
// 更新统计信息
result.Source.LineCount = lineNum
result.Source.ValidLines = validLines
result.ValidLines = validLines
result.ReadTime = time.Since(startTime)
return result, nil
}
// processLine 处理单行内容
func (fr *FileReader) processLine(line string, options *FileReaderOptions) (string, bool) {
// 清理空白字符
if options.TrimSpace {
line = strings.TrimSpace(line)
}
// 跳过空行
if options.SkipEmpty && line == "" {
return "", false
}
// 跳过注释行
if options.SkipComments && strings.HasPrefix(line, "#") {
return "", false
}
// 内容验证
if options.EnableValidation && fr.enableValidation {
if !fr.validateLine(line) {
return "", false
}
}
return line, true
}
// validateLine 验证行内容
func (fr *FileReader) validateLine(line string) bool {
// 基本验证:检查是否包含特殊字符或过长
if len(line) > 1000 { // 单行最大1000字符
return false
}
// 检查是否包含控制字符
for _, r := range line {
if r < 32 && r != 9 && r != 10 && r != 13 { // 排除tab、换行、回车
return false
}
}
return true
}
// mergeOptions 合并选项
func (fr *FileReader) mergeOptions(options ...*FileReaderOptions) *FileReaderOptions {
opts := DefaultFileReaderOptions()
if len(options) > 0 && options[0] != nil {
opts = options[0]
}
return opts
}
// getFromCache 从缓存获取结果
func (fr *FileReader) getFromCache(filename string) *FileResult {
fr.mu.RLock()
defer fr.mu.RUnlock()
if result, exists := fr.cache[filename]; exists {
// 检查文件是否有更新
if fileInfo, err := os.Stat(filename); err == nil {
if fileInfo.ModTime().After(result.Source.ModTime) {
// 文件已更新,从缓存中移除
delete(fr.cache, filename)
return nil
}
}
return result
}
return nil
}
// addToCache 添加到缓存
func (fr *FileReader) addToCache(filename string, result *FileResult) {
fr.mu.Lock()
defer fr.mu.Unlock()
// 检查缓存大小
if len(fr.cache) >= fr.maxCacheSize {
// 移除最旧的条目简单的LRU策略
var oldestFile string
var oldestTime time.Time
for file, res := range fr.cache {
if oldestFile == "" || res.Source.ModTime.Before(oldestTime) {
oldestFile = file
oldestTime = res.Source.ModTime
}
}
delete(fr.cache, oldestFile)
}
fr.cache[filename] = result
}
// =============================================================================================
// 已删除的死代码未使用ClearCache 和 GetCacheStats 方法
// =============================================================================================