顶层是UI层,放在frames文件夹下。
中层是服务层,放在services文件夹下。
下层是jvm运行环境以及C++库提供的基础支持。C++库在dllInterface文件夹下。
由服务层调用C++库并注册事件响应,提供基本功能,UI层响应用户的操作并发送事件进行调用。
├─MainClass.java 主启动类,初始化依赖并发出启动事件
├─utils 公用工具类
| ├─......
├─services
| ├─CheckHotKeyService.java 全局快捷键服务,注册和检测键盘快捷键
| ├─DaemonService.java 守护进程服务,开启和停止守护进程
| ├─DatabaseService.java 数据库维护服务,负责文件搜索和同步
| ├─OpenFileService.java 打开可执行文件服务
| ├─TranslateService.java 翻译服务
| ├─plugin
| | ├─system
| | | ├─Plugin.java 插件对象
| | | └PluginService.java 插件服务,提供插件的查询和方法调用
| ├─download
| | ├─BasicAuthenticator.java
| | ├─DownloadManager.java
| | └DownloadService.java 下载服务,负责下载文件
| ├─utils 仅供service调用工具类
| | ├─......
├─frames
| ├─PluginMarket.form
| ├─PluginMarket.java 插件市场UI界面
| ├─SearchBar.java 搜索框界面
| ├─SetDownloadProgress.java
| ├─SettingsFrame.form
| ├─SettingsFrame.java 设置UI界面
| ├─TaskBar.java Windows任务栏图标
| ├─components 通用Swing组件
| | ├─LoadingPanel.java
| | ├─MouseDragInfo.java
| | └RoundBorder.java
├─event
| ├─handler
| | ├─Event.java 事件基类
| | ├─EventManagement.java 事件处理工具
| | ├─impl 具体事件实现
| | | ├─......
├─dllInterface
| ├─gpu
| | ├─GPUAccelerator.java GPU加速工具包装类
| | ├─GPUApiCategory.java GPU加速API框架枚举类
| | ├─IGPUAccelerator.java GPU加速框架接口
| | ├─CudaAccelerator.java NVIDIA CUDA加速工具
| | └OpenclAccelerator.java OpenCL加速工具
| ├─EmptyRecycleBin.java 清空回收站工具
| ├─FileMonitor.java 文件改动监测工具
| ├─GetHandle.java 检测windows资源管理器并进行互操作工具
| ├─GetWindowsKnownFolder.java 获取Windows默认文件夹,如开始菜单,详见MSDN(SHGetKnownFolderPath)
| ├─HotkeyListener.java Windows全局快捷键注册工具
| ├─IsLocalDisk.java 检测硬盘是否为本地硬盘以及NTFS文件系统工具
├─configs
| ├─AllConfigs.java 全局配置中心
| ├─ConfigEntity.java 配置对象
| ├─AdvancedConfigEntity.java 高级配置对象
| ├─Constants.java 全局常量
| └ProxyInfo.java 网络代理对象,如http socks5
├─annotation
| ├─EventListener.java 事件监听注解,添加该注解可以将函数注册为对应事件的回调函数
| └EventRegister.java 事件处理注解,添加该注解可以将函数注册为相应事件的处理函数。注意:一个事件只能有一个处理函数,可以有多个回调函数。
事件处理系统详见Event_Management
public static void main(String[] args) {
try {
// 设置所有系统属性
setSystemProperties();
if (!System.getProperty("os.arch").contains("64")) {
JOptionPane.showMessageDialog(null, "Not 64 Bit", "ERROR", JOptionPane.ERROR_MESSAGE);
throw new RuntimeException("Not 64 Bit");
}
// 从tmp中更新插件(File-Engine上次启动更新的插件jar文件)
updatePlugins();
// 创建所有必要文件夹
initFoldersAndFiles();
// 从resources中释放所有的依赖
releaseAllDependence();
Class.forName("org.sqlite.JDBC");
// 初始化本地dll
initializeDllInterface();
// 扫描所有类,加载带有@EventRegister和@EventListener的事件处理器和事件监听器,并初始化事件处理系统
initEventManagement();
// 更新File-Engine启动器(File-Engine上次启动检查更新下载的File-Engine.exe文件)
updateLauncher();
// 清空tmp
FileUtil.deleteDir(new File("tmp"));
// 发出SetConfigsEvent事件并等待处理完成
setAllConfigs();
// 发出CheckConfigsEvent事件检查可能出错的配置并纠正
checkConfigs();
// 初始化数据库连接
initDatabase();
// 初始化全部完成,发出启动系统事件,AllConfigs配置中心处理完成BootSystemEvent事件之后,启动所有服务
if (sendBootSystemSignal()) {
JOptionPane.showMessageDialog(null, "Boot system failed", "ERROR", JOptionPane.ERROR_MESSAGE);
throw new RuntimeException("Boot System Failed");
}
// 检查版本更新
checkVersion();
// 进入主循环(检查进程已启动时间,当超过2天之后发出UpdateDatabaseEvent事件更新数据库)
mainLoop();
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
-
-
AllConfigs
-
全局配置中心,在这里读取所有的配置,并响应SetConfigsEvent事件,各服务监听该事件响应配置变化。当BootSystemEvent事件发出后,配置中心第一个处理该事件,读取所有的配置,并发出其他启动事件。
-
注册和监听的主要事件
/** * 系统启动事件,当此事件发出将会进行初始化 * @param event 启动事件 */ @EventRegister(registerClass = BootSystemEvent.class) private static void bootSystemEvent(Event event) { EventManagement eventManagement = EventManagement.getInstance(); eventManagement.putEvent(new StartMonitorDiskEvent()); eventManagement.putEvent(new ShowTrayIconEvent()); eventManagement.putEvent(new LoadAllPluginsEvent("plugins")); eventManagement.putEvent(new SetSwingLaf()); if (isFirstRunApp) { checkRunningDirAtDiskC(); } } /** * 读取所有配置 * @param event 读取配置事件 */ @EventRegister(registerClass = SetConfigsEvent.class) private static void setAllConfigsEvent(Event event) { SetConfigsEvent setConfigsEvent = (SetConfigsEvent) event; AllConfigs allConfigs = getInstance(); if (setConfigsEvent.getConfigs() == null) { // MainClass初始化 allConfigs.readAllSettings(); setConfigsEvent.setConfigs(allConfigs.configEntity); } else { // 添加高级设置参数 Map<String, Object> configsJson = allConfigs.getSettingsJSON(); allConfigs.readAdvancedConfigs(configsJson); ConfigEntity tempConfigEntity = setConfigsEvent.getConfigs(); tempConfigEntity.setAdvancedConfigEntity(allConfigs.configEntity.getAdvancedConfigEntity()); // 更新设置 if (allConfigs.noNullValue(tempConfigEntity)) { allConfigs.correctInvalidConfigs(tempConfigEntity); allConfigs.configEntity = tempConfigEntity; allConfigs.saveAllSettings(); } else { throw new NullPointerException("configEntity中有Null值"); } } }
-
-
-
-
UI层的实现。包含搜索框,设置窗口,任务栏,插件市场窗口的实现。以及一些通用控件。
-
UI层使用Java Swing实现,以及Intellij idea中的GUI Designer来构建。
-
-
搜索框的具体实现,搜索框输入后将会先发出PrepareSearchTaskEvent准备搜索任务并进行预搜索,等待用户输入超时后将会发出StartSearchEvent开始进行搜索,并开启mergeResultsThread线程不断从DatabaseService.tempResults获取结果并显示。
-
mergeResultsThread同时会检查插件有没有发来结果,如果有也会一并合并。
-
-
- 任务栏的具体实现,有打开设置,重启,退出三个选项。
-
- 插件市场窗口的具体实现,可下载插件。
-
- 设置窗口的具体实现,当窗口关闭时将会检查各项设置是否有效并发出SetConfigsEvent,随后由AllConfigs配置中心响应。
-
-
LoadingPanel:通用组件,加载窗口的实现。
-
MouseDragInfo:通用组件,鼠标从搜索框拖动到资源管理器时显示的窗口。
-
RoundBorder:通用组件,圆角边框的具体实现。
-
-
-
-
服务层的实现。包含下载服务,插件加载服务,键盘快捷键监听服务,数据库服务,多语言UI翻译服务。
-
服务启动如果需要使用其他服务互相调用来初始化,需要监听一个BootSystemEvent事件,在该事件发出前各服务不应该互相调用或者被上层调用,在该事件发出后再对服务中的字段进行初始化,不要写在构造函数中,防止循环依赖导致无法启动。
-
所有的服务都应该为单例模式,在程序中只拥有一个实例。
-
-
下载服务的具体实现,下载文件并在下载完成后执行回调。
-
DownloadManager:下载文件信息的封装。作为发送StartDownloadEvent事件的参数。
-
注册和监听的事件:
-
@EventRegister(registerClass = StartDownloadEvent.class) private static void startDownloadEvent(Event event) { StartDownloadEvent startDownloadTask = (StartDownloadEvent) event; getInstance().downLoadFromUrl(startDownloadTask.downloadManager); } @EventRegister(registerClass = StartDownloadEvent2.class) private static void startDownloadEvent2(Event event) { StartDownloadEvent2 startDownloadEvent2 = (StartDownloadEvent2) event; getInstance().downLoadFromUrl(startDownloadEvent2.downloadManager); } @EventRegister(registerClass = StopDownloadEvent.class) private static void stopDownloadEvent(Event event) { StopDownloadEvent stopDownloadTask = (StopDownloadEvent) event; getInstance().cancelDownload(stopDownloadTask.downloadManager); } @EventRegister(registerClass = StopDownloadEvent2.class) private static void stopDownloadEvent2(Event event) { StopDownloadEvent2 stopDownloadEvent2 = (StopDownloadEvent2) event; getInstance().cancelDownload(stopDownloadEvent2.downloadManager); }
StartDownloadEvent和StartDownloadEvent2并无本质区别,区别在于构造函数,StartDownloadEvent2不需要直接传入DownloadManager,方便插件进行调用,StopDownloadEvent和StopDownloadEvent2同理。
传入StartDownloadEvent需要使用DownloadManager类描述下载文件信息。
-
-
-
public class DownloadManager { public final String url; public final String savePath; public final String fileName; private volatile double progress = 0.0; private volatile boolean isUserInterrupted = false; private volatile Constants.Enums.DownloadStatus downloadStatus; private Proxy proxy = null; private final Authenticator authenticator = null;
public DownloadManager(String url, String fileName, String savePath) {
this.url = url;
this.fileName = fileName;
this.savePath = savePath;
this.downloadStatus = Constants.Enums.DownloadStatus.DOWNLOAD_NO_TASK;
ProxyInfo proxyInfo = AllConfigs.getInstance().getProxy();
setProxy(proxyInfo.type, proxyInfo.address, proxyInfo.port, proxyInfo.userName, proxyInfo.password);
}
}
DownloadManager类中包含**下载地址url**,**保存路径savePath**,**文件名fileName**,**下载进度progress**,**下载状态downloadStatus**
通过DownloadManager可以获取下载的基本信息。
- #### PluginService
- 插件服务,为项目提供插件加载卸载以及基本调用的接口。获取插件的一些基本信息
- Plugin:插件对外暴露的接口。
- 注册和监听的事件
```java
@EventRegister(registerClass = GetPluginByNameEvent.class)
private static void getPluginByNameEvent(Event event) {
GetPluginByNameEvent event1 = (GetPluginByNameEvent) event;
PluginInfo pluginInfoByName = getInstance().getPluginInfoByName(event1.pluginName);
event1.setReturnValue(pluginInfoByName);
}
@EventRegister(registerClass = GetPluginByIdentifierEvent.class)
private static void getPluginByIdentifier(Event event) {
GetPluginByIdentifierEvent event1 = (GetPluginByIdentifierEvent) event;
PluginInfo pluginInfoByIdentifier = getInstance().getPluginInfoByIdentifier(event1.identifier);
event1.setReturnValue(pluginInfoByIdentifier);
}
@EventRegister(registerClass = AddPluginsCanUpdateEvent.class)
private static void addPluginsCanUpdateEvent(Event event) {
getInstance().addPluginsCanUpdate(((AddPluginsCanUpdateEvent) event).pluginName);
}
@EventRegister(registerClass = LoadAllPluginsEvent.class)
private static void loadAllPluginsEvent(Event event) {
getInstance().loadAllPlugins(((LoadAllPluginsEvent) event).pluginDirPath);
checkPluginInfo();
}
@EventRegister(registerClass = RemoveFromPluginsCanUpdateEvent.class)
private static void removeFromPluginsCanUpdateEvent(Event event) {
getInstance().removeFromPluginsCanUpdate(((RemoveFromPluginsCanUpdateEvent) event).pluginName);
}
@EventListener(listenClass = SetConfigsEvent.class)
private static void setPluginsCurrentThemeEvent(Event event) {
var configs = AllConfigs.getInstance().getConfigMap();
getInstance().configsChanged((Integer) configs.get("defaultBackground"), (Integer) configs.get("labelColor"), (Integer) configs.get("borderColor"), configs);
}
@EventListener(listenClass = SearchBarReadyEvent.class)
private static void onSearchBarReady(Event event) {
SearchBarReadyEvent searchBarReadyEvent = (SearchBarReadyEvent) event;
getInstance().onSearchBarVisible(searchBarReadyEvent.showingType);
}
@EventListener(listenClass = RestartEvent.class)
private static void restartEvent(Event event) {
getInstance().unloadAllPlugins();
}
@EventRegister(registerClass = EventProcessedBroadcastEvent.class)
private static void broadcastEventProcess(Event event) {
EventProcessedBroadcastEvent eventProcessed = (EventProcessedBroadcastEvent) event;
PluginService pluginService = getInstance();
for (PluginInfo each : pluginService.pluginInfoSet) {
each.plugin.eventProcessed(eventProcessed.c, eventProcessed.eventInstance);
}
}
```
PluginService中主要对外的事件为GetPluginByNameEvent和GetPluginByIdentifierEvent事件,这两个事件可以获取插件名和插件关键字获取对应的插件对象。
```java
public static class PluginInfo {
public final Plugin plugin;
public final String name;
public final String identifier;
private PluginInfo(Plugin plugin, String name, String identifier) {
this.plugin = plugin;
this.name = name;
this.identifier = identifier;
}
@Override
public String toString() {
return name;
}
}
```
```java
public class Plugin {
public final String name;
public final String identifier;
private final Object instance;
private final ConcurrentHashMap<String, Method> methodHashMap = new ConcurrentHashMap<>();
private static final HashSet<String> methodList = new HashSet<>();
}
```
Plugin类中包含所有插件的方法,通过反射进行调用。
```java
@SuppressWarnings("unchecked")
private <T> T invokeByKey(String key, Object... args) {
if (methodHashMap.containsKey(key)) {
try {
return (T) methodHashMap.get(key).invoke(instance, args);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return null;
}
@SuppressWarnings("unchecked")
private <T> T invokeByKeyNoExcept(String key, Object... args) {
if (methodHashMap.containsKey(key)) {
try {
return (T) methodHashMap.get(key).invoke(instance, args);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
public void loadPlugin(Map<String, Object> configs) {
String key = "loadPlugin" + Arrays.toString(new Class<?>[]{Map.class});
invokeByKey(key, configs);
}
...
```
每个函数的意义请参考插件开发文档或插件模板API上的函数注释。
[XUANXUQAQ/File-Engine-Plugin-Template: A File-Engine plugin template (github.com)](https://github.com/XUANXUQAQ/File-Engine-Plugin-Template)
- #### CheckHotKeyService
- 键盘快捷键的监听服务,当键盘快捷键点击后将会发出ShowSearchBarEvent打开搜索框。
- 注册和监听的事件
```java
@EventRegister(registerClass = CheckHotKeyAvailableEvent.class)
private static void checkHotKeyAvailableEvent(Event event) {
var event1 = (CheckHotKeyAvailableEvent) event;
event1.setReturnValue(getInstance().isHotkeyAvailable(event1.hotkey));
}
@EventListener(listenClass = SetConfigsEvent.class)
private static void registerHotKeyEvent(Event event) {
getInstance().registerHotkey(AllConfigs.getInstance().getConfigEntity().getHotkey());
}
@EventListener(listenClass = RestartEvent.class)
private static void stopListen(Event event) {
getInstance().stopListen();
}
```
CheckHotKeyService是通过配置中心AllConfigs发出的配置更新事件来进行响应。CheckHotKeyAvailableEvent事件用于检测快捷键是否有效,用于设置界面保存设置时发出检查快捷键是否有效。
- #### DatabaseService
- 数据库服务,提供数据库的搜索,添加,删除等基本操作。当搜索框发出StartSearchEvent后,数据库将会通过关键字进行搜索,并将结果返回给搜索框进行显示。
- 注册和监听的主要事件:
```java
@EventRegister(registerClass = PrepareSearchEvent.class)
private static void prepareSearchEvent(Event event) {
if (IsDebug.isDebug()) {
System.out.println("进行预搜索并添加搜索任务");
}
var startWaiting = System.currentTimeMillis();
final long timeout = 3000;
var databaseService = getInstance();
while (databaseService.getStatus() != Constants.Enums.DatabaseStatus.NORMAL) {
if (System.currentTimeMillis() - startWaiting > timeout) {
System.err.println("prepareSearch,等待数据库状态超时");
break;
}
Thread.onSpinWait();
}
// 检查prepareTaskMap中是否有过期任务
for (var eachTask : prepareTasksMap.entrySet()) {
if (System.currentTimeMillis() - eachTask.getValue().taskCreateTimeMills > SearchTask.maxTaskValidThreshold) {
prepareTasksMap.remove(eachTask.getKey());
}
}
var prepareSearchEvent = (PrepareSearchEvent) event;
var searchInfo = prepareSearchKeywords(prepareSearchEvent.searchText, prepareSearchEvent.searchCase, prepareSearchEvent.keywords);
var searchTask = prepareSearch(searchInfo);
prepareTasksMap.put(searchInfo, searchTask);
event.setReturnValue(searchTask);
}
@EventRegister(registerClass = StartSearchEvent.class)
private static void startSearchEvent(Event event) {
if (((StartSearchEvent) event).searchText.get().length() > Constants.MAX_SEARCH_TEXT_LENGTH) {
System.err.println("关键字太长,取消搜索");
return;
}
DatabaseService databaseService = getInstance();
final long startWaiting = System.currentTimeMillis();
final long timeout = 3000;
while (databaseService.getStatus() != Constants.Enums.DatabaseStatus.NORMAL) {
if (System.currentTimeMillis() - startWaiting > timeout) {
System.out.println("等待数据库状态为NORMAL超时");
return;
}
Thread.onSpinWait();
}
var startSearchEvent = (StartSearchEvent) event;
var searchInfo = prepareSearchKeywords(startSearchEvent.searchText, startSearchEvent.searchCase, startSearchEvent.keywords);
var searchTask = prepareTasksMap.get(searchInfo);
if (searchTask == null) {
searchTask = prepareSearch(searchInfo);
}
databaseService.startSearchInThreadPool(searchTask);
event.setReturnValue(searchTask);
}
@EventRegister(registerClass = InitializeDatabaseEvent.class)
private static void initAllDatabases(Event event) {
SQLiteUtil.initAllConnections();
}
@EventRegister(registerClass = InitializeDatabaseEvent.class)
private static void initAllDatabases(Event event) {
SQLiteUtil.initAllConnections();
}
@EventRegister(registerClass = StartMonitorDiskEvent.class)
private static void startMonitorDiskEvent(Event event) {
startMonitorDisks();
}
@EventListener(listenClass = SetConfigsEvent.class)
private static void setGpuDevice(Event event) {
isEnableGPUAccelerate = AllConfigs.getInstance().getConfigEntity().isEnableGpuAccelerate();
if (isEnableGPUAccelerate) {
synchronized (DatabaseService.class) {
var device = AllConfigs.getInstance().getConfigEntity().getGpuDevice();
if (!GPUAccelerator.INSTANCE.setDevice(device)) {
System.err.println("gpu设备" + device + "无效");
}
}
}
}
```
核心事件为PrepareSearchEvent和StartSearchEvent,用于启动搜索。PrepareSearchEvent用于预搜索,提前于StartSearchEvent发出,用于提前搜索桌面,开始菜单快捷方式,以及GPU加速启用时的搜索。
StartMonitorDiskEvent事件发出后将会开启文件监控,记录文件的新增和删除的变化,并同步到数据库以及缓存中。
InitializeDatabaseEvent事件发出后将会初始化数据库,打开所有的数据库连接并创建需要的表。
- ### utils
- 基本工具类
- #### Bit
- 大数位运算模块,用于运算超过long位数的位运算。由于File-Engine使用异步搜索来进行数据库的查询,通过多个表以及优先级的任务划分后会产生几百个小任务,所以通过该类来进行任务的完成标记。
- #### clazz.scan
- ClassScannerUtil:注解扫描工具,扫描带有@EventRegister和@EventListener注解的方法,并进行注册。
- #### connection
- PreparedStatementWrapper
- 用于包裹PreparedStatement,通过继承JDBC4PreparedStatement并重写AutoCloseable的close方法,实现引用计数的功能,File-Engine拥有闲时自动关闭数据库的功能。通过引用计数来实现对数据库的使用进行监控,防止外部还有数据库使用时数据库被关闭导致崩溃。
```java
/**
* 通过复写AutoCloseable接口的close方法实现引用计数,确保在关闭数据库时没有被使用
* 必须使用 try-with-source语法
*/
class PreparedStatementWrapper extends JDBC4PreparedStatement {
private final AtomicInteger connectionUsingCounter;
public PreparedStatementWrapper(SQLiteConnection conn, String sql, AtomicInteger connectionUsingCounter) throws SQLException {
super(conn, sql);
this.connectionUsingCounter = connectionUsingCounter;
this.connectionUsingCounter.incrementAndGet();
}
@Override
public void close() throws SQLException {
super.close();
connectionUsingCounter.decrementAndGet();
}
}
```
- StatementWrapper
- 用于包裹Statement,通过继承JDBC4Statement并重写AutoCloseable的close方法实现引用计数的功能。
```java
/**
* 通过复写AutoCloseable接口的close方法实现引用计数,确保在关闭数据库时没有被使用
* 必须使用 try-with-source语法
*/
class StatementWrapper extends JDBC4Statement {
private final AtomicInteger connectionUsingCounter;
public StatementWrapper(SQLiteConnection conn, AtomicInteger connectionUsingCounter) {
super(conn);
this.connectionUsingCounter = connectionUsingCounter;
this.connectionUsingCounter.incrementAndGet();
}
@Override
public void close() throws SQLException {
super.close();
connectionUsingCounter.decrementAndGet();
}
}
```
- SQLiteUtil
- sqlite数据库的管理工具,实现数据库的打开关闭基本功能,以及闲时关闭数据库的功能。
- 对外提供的函数:
```java
/**
* 打开所有连接
*/
public static void openAllConnection() {
...
}
/**
* 不要用于大量数据的select查询,否则可能会占用大量内存
*
* @param sql select语句
* @return 已编译的PreparedStatement
* @throws SQLException 失败
*/
public static PreparedStatement getPreparedStatement(String sql, String key) throws SQLException {
if (isConnectionNotInitialized(key)) {
var root = key + ":\\";
if (FileUtil.isFileNotExist(root) || !IsLocalDisk.INSTANCE.isDiskNTFS(root)) {
throw new SQLException(root + " disk is invalid.");
} else {
File data = new File(currentDatabaseDir, key + ".db");
initConnection("jdbc:sqlite:" + data.getAbsolutePath(), key);
}
}
ConnectionWrapper connectionWrapper = getFromConnectionPool(key);
return new PreparedStatementWrapper((SQLiteConnection) connectionWrapper.connection, sql, connectionWrapper.connectionUsingCounter);
}
/**
* 用于需要重复运行多次指令的地方
*
* @return Statement
* @throws SQLException 失败
*/
public static Statement getStatement(String key) throws SQLException {
if (isConnectionNotInitialized(key)) {
var root = key + ":\\";
if (FileUtil.isFileNotExist(root) || !IsLocalDisk.INSTANCE.isDiskNTFS(root)) {
throw new SQLException(root + " disk is invalid.");
} else {
File data = new File(currentDatabaseDir, key + ".db");
initConnection("jdbc:sqlite:" + data.getAbsolutePath(), key);
}
}
ConnectionWrapper wrapper = getFromConnectionPool(key);
return new StatementWrapper((SQLiteConnection) wrapper.connection, wrapper.connectionUsingCounter);
}
public static void initAllConnections() {
initAllConnections("data");
}
public static void initAllConnections(String dir) {
...
}
```
SQLite对外提供Statement和PreparedStatement,DatabaseService使用SQLite进行sql操作。
- #### file
- FileUtil:文件处理工具类,清空文件夹,获取上级目录,判断是否为文件等基础功能。
- MoveDesktopFiles:移动桌面文件到File-Engine的Files文件夹下。
- #### gson
- GsonUtil:google json处理工具类。
- #### system.properties
- IsDebug
- 判断File-Engine是否处于debug模式下,当jvm启动参数中包含 **-DFile_Engine_Debug=true** 时返回true。当File-Engine处于debug模式下会输出很多调试信息。
- IsPreview
- 判断File-Engine是否处于preview模式下,当处于preview模式时,将会忽略版本信息,始终判断稳定版为最新版本,在发布不稳定的新特性版本时使用。
- #### CachedThreadPoolUtil
- 缓存线程池工具类,用于启动和管理线程。目前线程池拥有两个分支,主分支master中只有一个线程池platformThreadPool,virtual-thread-feature分支实现了虚拟线程池,未来可能会将virtual-thread-feature分支合并到主分支。
- #### ColorUtil
- 颜色工具类,判断字符串hex值是否能转换到RGB颜色,以及获取高亮颜色,高对比度颜色,判断颜色是亮色还是暗色,颜色和字符串转换功能。
- #### DpiUtil
- 获取windows系统的缩放级别(dpi)。
- #### GetIconUtil
- 获取图标工具类,当搜索框显示文件时,通过GetIconUtil获取文件的图标,并显示在结果左方。
- #### Md5Util
- 获取文件的MD5值,用于File-Engine更新资源和依赖,当版本更新后将会通过比对user/文件夹中现有的依赖文件和File-Engine中保存的依赖文件来更新资源。
- #### OpenFileUtil
- 打开文件工具类,当在搜索框上点击Enter或者双击鼠标左键后将会调用OpenFileUtil中的方法来打开文件。
- #### PathMatchUtil
- 文件名关键字匹配工具类,由databaseService进行调用。
- #### PinyinUtil
- File-Engine支持拼音搜索,通过将文字转换为拼音来进行搜索。
- #### ProcessUtil
- 进程控制工具类,判断进程是否存在,等待进程。
- #### RegexUtil
- 正则表达式工具类,获取并缓存正则表达式。
- #### RobotUtil
- 鼠标键盘控制工具类。
- #### StartupUtil
- 开机启动工具类,用于判断开机启动是否生效,添加和删除开机启动。
- #### SystemInfoUtil
- 系统信息工具类,用于获取系统的内存信息,判断系统内存用量。
## C++库部分
- ### fileMonitor
- 监控文件的变化,文件删除或是增加会被记录,然后添加进数据库。
- ### fileSearcherUSN
- 搜索磁盘上的文件,创建索引。 ~~搜索时同时会创建共享内存,如果硬盘速度太慢导致存储时间太长,可以通过resultPipe先读取共享内存,同时等待数据库保存完成~~,共享内存功能已弃用,新版本将会在创建索引时切换到临时数据库,继续提供搜索功能。
- ### getAscII(已弃用)
- **新版本通过Java实现,不再使用JNI调用该原生库。**
```java
public class StringUtf8SumUtil {
public static int getStringSum(String fileName) {
if (fileName == null || fileName.isEmpty()) {
return 0;
}
var bytes = fileName.getBytes(StandardCharsets.UTF_8);
int sum = 0;
for (byte aByte : bytes) {
if (aByte > 0) {
sum += aByte;
}
}
return sum;
}
}
```
- 获取文件名的每个字符,将char值相加并返回。
- File-Engine的数据库通过41个表保存文件数据。分别是list0-list40,list0保存文件名ascii和在0-100范围内的文件。list1保存100-200的范围内的文件,以此类推。
- ### getDpi
- 获取windows系统的缩放级别,适配系统的分辨率和DPI,使程序在高分辨率屏幕下显示不模糊和错位。
- ### getHandle
- 实现与explorer.exe相关的操作,贴靠在explorer.exe下方,让explorer跳转到其他路径,File-Engine普通模式与贴靠模式的切换,搜索框拖动到文件夹以创建快捷方式,以及检测窗口是否全屏等与Windows 交互功能的实现。
- ### getWindowsKnownFolder
- 获取Windows默认文件夹的路径,如开始菜单,因为大部分程序都在开始菜单,因此作为优先搜索的路径。该函数为下方Windows API接口的封装。
- [SHGetKnownFolderPath function (shlobj_core.h) - Win32 apps | Microsoft Learn](https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath)
- ### hotkeyListener
- 键盘快捷键监听,实现点击键盘快捷键后打开搜索框,以及对Ctrl双击,Shift双击的全局检测。
- ### isLocalDisk
- 检查磁盘是不是本地磁盘或者U盘,以及检测文件系统是否为NTFS。
- ### launcherWrap
- File-Engine的启动器以及守护进程。
- ### resultPipe(已弃用)
- **新版本采用临时数据库的方式实现索引时提供搜索服务,不再采用共享内存。**
- 读取fileSearcherUSN创建的共享内存,实现在创建索引时也能进行搜索。
- 共享内存将会在索引创建完成后关闭。
- ### cudaAccelerator
- NVIDIA GPU CUDA加速引擎,通过并行计算实现高速搜索字符串。
- ### openclAccelerator
- 基于opencl框架实现的通用GPU加速引擎。
- ### sqliteJDBC
- sqlite的jni接口,实现java调用sqlite.dll。
## MainClass
主启动类,对系统进行初始化,释放资源,设置系统属性,发出系统启动事件BootSystemEvent