From 6ab4a2786eefab3d898ab31f62ffa7ec24ab0f0c Mon Sep 17 00:00:00 2001 From: hejl Date: Thu, 29 May 2025 13:07:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=90=8D=E7=A7=B0=E7=BF=BB?= =?UTF-8?q?=E8=AF=91=E5=AE=8C=E6=88=90=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../framework/services/fast_xml_parser.dart | 74 +++++++++++++++++++ .../lib/framework/services/file_service.dart | 65 +++++++++++----- 2 files changed, 122 insertions(+), 17 deletions(-) create mode 100644 win_text_editor/lib/framework/services/fast_xml_parser.dart diff --git a/win_text_editor/lib/framework/services/fast_xml_parser.dart b/win_text_editor/lib/framework/services/fast_xml_parser.dart new file mode 100644 index 0000000..906b49b --- /dev/null +++ b/win_text_editor/lib/framework/services/fast_xml_parser.dart @@ -0,0 +1,74 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:xml/xml.dart'; + +class FastXmlParser { + /// 批量解析XML文件根节点属性 + static Future>> batchParse( + List filePaths, { + int maxFastParseBytes = 1024, + }) async { + return await Future.wait(filePaths.map((path) => _parseWithFallback(path, maxFastParseBytes))); + } + + static Future> parse(String filePath, {int maxFastParseBytes = 512}) async { + return _parseWithFallback(filePath, maxFastParseBytes); + } + + /// 带降级的解析流程 + static Future> _parseWithFallback(String path, int maxBytes) async { + try { + // 优先尝试快速解析 + return await _fastParseRootAttributes(path, maxBytes); + } catch (e) { + // 快速解析失败时降级到DOM解析 + return await _domParseRootAttributes(path); + } + } + + /// 快速解析方案(正则匹配) + static Future> _fastParseRootAttributes(String path, int maxBytes) async { + final file = File(path); + final raf = await file.open(); + try { + // 仅读取文件开头部分 + final buffer = await raf.read(maxBytes); + final content = utf8.decode(buffer); + + // 使用正则提取开始标签属性 + final startTag = RegExp( + r'(?:<\?xml[^?>]*\?>[\s\r\n]*)?<([^\s>]+)([^>]*)>', + caseSensitive: false, + ).firstMatch(content); + if (startTag == null) throw Exception('No start tag found'); + + final attrs = _parseAttributes(startTag.group(2)!); + return _extractRequiredAttributes(attrs); + } finally { + await raf.close(); + } + } + + /// DOM解析降级方案 + static Future> _domParseRootAttributes(String path) async { + final content = await File(path).readAsString(); + final document = XmlDocument.parse(content); + final attrs = document.rootElement.attributes.fold>( + {}, + (map, attr) => map..[attr.name.qualified] = attr.value, + ); + return _extractRequiredAttributes(attrs); + } + + /// 辅助方法:解析属性字符串 + static Map _parseAttributes(String attrStr) { + return RegExp(r'(\w+)="([^"]*)"') + .allMatches(attrStr) + .fold>({}, (map, match) => map..[match.group(1)!] = match.group(2)!); + } + + /// 辅助方法:提取目标属性 + static Map _extractRequiredAttributes(Map attrs) { + return {'chineseName': attrs['chineseName'] ?? '', 'objectId': attrs['objectId'] ?? ''}; + } +} diff --git a/win_text_editor/lib/framework/services/file_service.dart b/win_text_editor/lib/framework/services/file_service.dart index 0e8a06b..9c247a3 100644 --- a/win_text_editor/lib/framework/services/file_service.dart +++ b/win_text_editor/lib/framework/services/file_service.dart @@ -1,32 +1,63 @@ import 'dart:io'; import 'package:win_text_editor/framework/controllers/logger.dart'; import 'package:win_text_editor/framework/models/file_node.dart'; +import 'package:win_text_editor/framework/services/fast_xml_parser.dart'; import 'package:xml/xml.dart'; class FileService { + static const _specialExtensions = [ + '.uftfunction', + '.uftservice', + '.uftatomfunction', + '.uftatomservice', + '.uftfactorfunction', + '.uftfactorservice', + '.uftstructure', + ]; + static Future getSpecialFileName(String filePath) async { + final extension = filePath.substring(filePath.lastIndexOf('.')); + if (!_specialExtensions.contains(extension)) { + return null; + } + + try { + final result = await FastXmlParser.parse(filePath); + return ('[${result['objectId']}]${result['chineseName']}'); + } catch (e) { + Logger().debug('Error reading special file: $e'); + } + return null; + } + /// 延时加载目录内容(不递归) static Future> listDirectory(String path, {int parentDepth = 0}) async { - final dir = Directory(path); - final List entities = await dir.list().toList(); + final dir = Directory(path); + final List entities = await dir.list().toList(); final List nodes = []; + // final stopwatch = Stopwatch()..start(); - for (final entity in entities) { - final isDirectory = await FileSystemEntity.isDirectory(entity.path); - final displayName = isDirectory - ? await getModuleDisplayName(entity.path) - : null; - - nodes.add(FileNode( - name: displayName ?? entity.path.split(Platform.pathSeparator).last, - path: entity.path, - isDirectory: isDirectory, - depth: parentDepth + 1, - )); - } + for (final entity in entities) { + final isDirectory = await FileSystemEntity.isDirectory(entity.path); + final displayName = + isDirectory + ? await getModuleDisplayName(entity.path) + : await getSpecialFileName(entity.path); - return nodes; -} + nodes.add( + FileNode( + name: displayName ?? entity.path.split(Platform.pathSeparator).last, + path: entity.path, + isDirectory: isDirectory, + depth: parentDepth + 1, + ), + ); + } + + // stopwatch.stop(); + // Logger().debug('执行耗时: ${stopwatch.elapsedMilliseconds} 毫秒 (ms)'); + return nodes; + } static Future getModuleDisplayName(String dirPath) async { try {