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 并发读取多个文件 func (fr *FileReader) ReadFiles(filenames []string, options ...*FileReaderOptions) (map[string]*FileResult, error) { if len(filenames) == 0 { return nil, NewParseError("FILE_ERROR", "文件列表为空", "", 0, ErrEmptyInput) } opts := fr.mergeOptions(options...) results := make(map[string]*FileResult) resultsChan := make(chan struct { filename string result *FileResult err error }, len(filenames)) // 并发读取文件 var wg sync.WaitGroup semaphore := make(chan struct{}, 4) // 限制并发数 for _, filename := range filenames { wg.Add(1) go func(fname string) { defer wg.Done() semaphore <- struct{}{} // 获取信号量 defer func() { <-semaphore }() // 释放信号量 result, err := fr.ReadFile(fname, opts) resultsChan <- struct { filename string result *FileResult err error }{fname, result, err} }(filename) } // 等待所有协程完成 go func() { wg.Wait() close(resultsChan) }() // 收集结果 var errors []error for res := range resultsChan { if res.err != nil { errors = append(errors, res.err) } else { results[res.filename] = res.result } } // 如果有错误且所有文件都失败,返回第一个错误 if len(errors) > 0 && len(results) == 0 { return nil, errors[0] } return results, nil } // 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 清空缓存 func (fr *FileReader) ClearCache() { fr.mu.Lock() defer fr.mu.Unlock() fr.cache = make(map[string]*FileResult) } // GetCacheStats 获取缓存统计 func (fr *FileReader) GetCacheStats() map[string]interface{} { fr.mu.RLock() defer fr.mu.RUnlock() return map[string]interface{}{ "cache_size": len(fr.cache), "max_cache_size": fr.maxCacheSize, "cache_enabled": fr.enableCache, } }