从 0 实现一个文件搜索工具 (Java 项目)

背景

各文件系统下, 都有提供文件查找的功能, 但是一般而言搜索速度很慢
在这里插入图片描述
本项目仿照 everything 工具, 实现本地文件的快速搜索

实现功能

  1. 选择指定本地目录, 根据输入的信息, 进行搜索, 显示指定目录下的匹配文件信息
  2. 文件夹包含中文时, 支持汉语拼音搜索 (全拼 / 首字母匹配)

相关技术

Java + Servlet + Pinyin4j
JDBC + SQLite (SQLite 相对于 MySQL 更加轻量, 并且引入 jar 包即可使用, 不必安装配套应用)
JavaFx

数据库设计

在这里插入图片描述

SQLite 创建 SQL 的语句如下

create table if not exists file_meta (id INTEGER primary key autoincrement,name varchar(50) not null,path varchar(512) not null,is_directory boolean not null,pinyin varchar(100) not null,pinyin_first varchar(50) not null,size BIGINT not null,last_modified timestamp not null
);

项目的基本框架

在这里插入图片描述

前端页面

在这里插入图片描述

app.fxml 文件

显示界面的图画化结构

<?xml version="1.0" encoding="UTF-8"?><?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?><?import javafx.geometry.Insets?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<GridPane fx:controller="gui.GUIController" fx:id="gridPane" vgap="10" alignment="center" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"><children ><Button fx:id="button"  onMouseClicked="#choose" prefWidth="90" text="选择目录" GridPane.rowIndex="0" GridPane.columnIndex="0"></Button><Label fx:id="label" text="当前未选择目录" GridPane.rowIndex="0" GridPane.columnIndex="0"><GridPane.margin><Insets left="100"></Insets></GridPane.margin></Label><TextField fx:id="textField" prefWidth="900" GridPane.rowIndex="1" GridPane.columnIndex="0" ></TextField><TableView fx:id="tableView" prefWidth="900" prefHeight="700" GridPane.rowIndex="2" GridPane.columnIndex="0"><columns><TableColumn prefWidth="220" text="文件名"><cellValueFactory><PropertyValueFactory property="name"></PropertyValueFactory></cellValueFactory></TableColumn><TableColumn prefWidth="400" text="路径"><cellValueFactory><PropertyValueFactory property="path"></PropertyValueFactory></cellValueFactory></TableColumn><TableColumn prefWidth="100" text="大小"><cellValueFactory><PropertyValueFactory property="sizeText"></PropertyValueFactory></cellValueFactory></TableColumn><TableColumn prefWidth="180" text="修改时间"><cellValueFactory><PropertyValueFactory property="lastModifiedText"></PropertyValueFactory></cellValueFactory></TableColumn></columns></TableView></children>
</GridPane>

GUIController 类

与 app.fxml 文件配套使用, 该类离实现了 界面中按键的绑定事件, 以及对搜索框内容进行监听, 当搜索框内容改变时, 重新搜索, 并将结果返回到查询结果显示处 (实现动态搜索功能)

public class GUIController implements Initializable {@FXMLprivate Label label;@FXMLprivate GridPane gridPane;@FXMLprivate Button button;@FXMLprivate TextField textField;@FXMLprivate TableView<FileMeta> tableView;private SearchService searchService = null;@Overridepublic void initialize(URL location, ResourceBundle resources) {// 在这里对 输入框 加一个监听器// 需要指定对 text 这个内容属性进行监听// textField.textProperty() 获取输入框里的内容textField.textProperty().addListener(new ChangeListener<String>() {/***  会在用户每次修改 输入框内容 的时候, 被自动调用到* @param observable* @param oldValue 输入框被修改之前的值* @param newValue 输入框被修改之后的值*/@Overridepublic void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {// 此处要干的事情, 是根据新的值, 重新进行查询操作freshTable(newValue);}});}private void freshTable(String query) {// 重新查询数据库, 把查询结果, 设置到表格中if(searchService == null) {System.out.println("searchService 尚未初始化, 不能查询!");return;}// 把之前表里的内容清空掉ObservableList<FileMeta> fileMetas = tableView.getItems();fileMetas.clear();List<FileMeta> results = searchService.search(query);fileMetas.addAll(results);}/*** 使用该方法, 作为鼠标点击事件的回调函数* @param mouseEvent*/public void choose(MouseEvent mouseEvent) {// 创建一个 目录选择器DirectoryChooser directoryChooser = new DirectoryChooser();// 把该对话框显示出来Window window = gridPane.getScene().getWindow();File file = directoryChooser.showDialog(window);if(file == null) {System.out.println("用户选择的路径为空");} else {System.out.println(file.getAbsolutePath());}// 把用户选择的路径,显示到 label 中label.setText(file.getAbsolutePath());// 如果不是首次扫描, 就应该停止上次扫描任务, 执行本次扫描任务if(searchService != null) {searchService.shutdown();}// 对用户选择的路径进行扫描, 初始化searchService = new SearchService();searchService.init(file.getAbsolutePath());}
}

GUIClient

继承 Application 方法, 为界面启动类, 调用 javafx 提供的 launch 方法来启动整个程序

public class GUIClient extends Application {/*** 程序启动时, 会立即执行的方法* @param primaryStage* @throws Exception*/@Overridepublic void start(Stage primaryStage) throws Exception {// 加载 fxml 文件, 把 fxml 文件里的内容, 给设置到舞台中Parent parent = FXMLLoader.load(GUIClient.class.getClassLoader().getResource("app.fxml"));primaryStage.setScene(new Scene(parent, 1000, 800));primaryStage.setTitle("文件搜索工具");// 准备工作完成, 显示场景界面primaryStage.show();}public static void main(String[] args) {// 调用 javafx 提供的 launch 方法来启动整个程序launch(args);}
}

后端代码

实体类

FileMeta

本类对应着数据库的 file_meta 表
因为没引入 lombok, 因此只能手写 Setter 和 Getter 方法

// 本类的示例就代表 file_meta 表里的每个记录.
public class FileMeta {private int id;private String name;private String path;private boolean isDirectory;// 这里存储的 size 是字节, 但是界面上输出的不应该以字节位单位, k, m, gprivate long size;// 这个存储的是时间戳(机器能看懂)private long lastModified;// 这个是进行格式化转换之后的时间格式(人能看懂的)
//    private long lastModifiedText;// 构造方法public FileMeta(String name, String path, boolean isDirectory, long size, long lastModified) {this.name = name;this.path = path;this.isDirectory = isDirectory;this.size = size;this.lastModified = lastModified;}public FileMeta(File f) {this(f.getName(), f.getParent(), f.isDirectory(), f.length(), f.lastModified());}public String getPinyin() {return PinyinUtil.get(name, true);}public String getPinyinFirst() {return PinyinUtil.get(name, false);}public String getSizeText() {// 常见单位: Byte, KB, MB, GB, TB// 如果 size < 1024, 使用 Byte// 如果 1024 <= size < 1024*1024, 使用 MB// ...double curSize = size;String[] units = {"Byte", "KB", "MB", "GB", "TB"};for(int i=0;i<units.length;i++) {if(curSize < 1024) {return String.format("%.2f " + units[i], new BigDecimal(curSize));}curSize /= 1024;}return String.format("%.2f TB", new BigDecimal(curSize));}public String getLastModifiedText() {DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");return dateFormat.format(lastModified);}// -------------------------------public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPath() {return path;}public void setPath(String path) {this.path = path;}public boolean isDirectory() {return isDirectory;}public void setDirectory(boolean directory) {isDirectory = directory;}public long getSize() {return size;}public void setSize(long size) {this.size = size;}public long getLastModified() {return lastModified;}public void setLastModified(long lastModified) {this.lastModified = lastModified;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;FileMeta fileMeta = (FileMeta) o;return isDirectory == fileMeta.isDirectory  && name.equals(fileMeta.name) && path.equals(fileMeta.path);}@Overridepublic int hashCode() {return Objects.hash(name, path, isDirectory);}
}

DBUtil

本类封装 JDBC 的 连接/关闭/管理 操作

public class DBUtil {// 使用 单例模式(懒汉模式) 来提供 DataSourceprivate static volatile DataSource dataSource = DBUtil.getDataSource();// 创建数据源: Datasourcepublic static DataSource getDataSource() {if (dataSource == null) { //外层 if 判断是否要加锁 (加锁是要消耗资源的, if判断一下比 synchronized 加一次锁消耗资源要少的多)synchronized (DBUtil.class) {if(dataSource == null ) { //内层 if 判断是否要创建 DataSourcedataSource = new SQLiteDataSource();((SQLiteDataSource)dataSource).setUrl("jdbc:sqlite://D:/AAASpringBootProject/sqlite/fileSearcher.db");}}}return dataSource;}// 建立连接public static Connection getConnection() throws SQLException {return dataSource.getConnection();}// 断开连接public static void close(Connection connection, Statement statement, ResultSet resultSet) {if(resultSet != null) {try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}if(statement != null) {try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if(connection != null ) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}
}

FileDao 类

通过该类来实现数据库的增删改查操作

// 通过这个类来封装针对 file_meta 表的操作
public class FileDao {// 1.初始化数据库 (建表)public void initDB() {// 1) 先能够读取到 db.sql 中的 SQL 语句// 2) 根据 SQL 语句调用 jdbc 执行操作Connection connection = null;Statement statement = null;try {connection = DBUtil.getConnection();// 使用 connection.createStatement() 来执行建库建表 sqlstatement = connection.createStatement();String[] sqls = getInitSql();for(String sql : sqls) {System.out.println("[initDB] sql:" + sql);statement.executeUpdate(sql); //该方式用来执行一些基本不变的sql语句}} catch (SQLException | IOException e) {e.printStackTrace();} finally {DBUtil.close(connection, statement, null);}}// 从 db.sql 中读取文件内容// 一个 sql 语句对应一个 String, 多个 sql 语句对应 String[]private String[] getInitSql() throws IOException {// 用这个 StringBuilder 来存储最终结果StringBuilder stringBuilder = new StringBuilder();// 此处需要动态获取到 db.sql 文件的路径, 而不是一个写死的绝对路径(运行在别人的电脑上的)try(InputStream inputStream = FileDao.class.getClassLoader().getResourceAsStream("db.sql")) {// 这里是字节流到字符流的转换(对字符能轻松的进行操作, 对字节的操作要难得多)try(InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf8")) {while(true) {// char 类型读取不到 -1, 也就没有文件读取结束的标记了, 所以这里使用 int 来接收int ch = inputStream.read(); //inputStream.read() 读取到文件结束符会返回 -1if( ch == -1) break;  //文件读取完毕stringBuilder.append((char) ch);}}} catch (IOException e) {e.printStackTrace();}// sql 语句以 ';' 结束, 我们就以 ';' 来拆分字符串, 一句 sql 就是一个 Stringreturn stringBuilder.toString().split(";");}// 2.插入文件/目录数据到数据库中//   此处提供"批量插入"操作public void add(List<FileMeta> fileMetas) {Connection connection = null;PreparedStatement statement = null;try {connection = DBUtil.getConnection();// 关闭自动提交功能// (一次插入多条数据, 如果一个一个插,数据库就要打开-关闭-打开-关闭... 因此一次插入多条数据, 会减小数据库的资源消耗)connection.setAutoCommit(false);String sql = "insert into file_meta values(null, ?, ?, ?, ?, ?, ?, ?)";statement = connection.prepareStatement(sql);for(FileMeta fileMeta : fileMetas) {// 把当前 FileMeta 对象, 替换到 SQL 语句中.statement.setString(1,fileMeta.getName());statement.setString(2,fileMeta.getPath());statement.setBoolean(3, fileMeta.isDirectory());statement.setString(4,fileMeta.getPinyin());statement.setString(5,fileMeta.getPinyinFirst());statement.setLong(6, fileMeta.getSize());statement.setTimestamp(7, new Timestamp(fileMeta.getLastModified()));// 使用 addBatch 把构造好的片段连接起来// addBatch 会把已经构造好的 SQL 保存起来, 同时又会允许重新构造一个新的 SQL 出来statement.addBatch();System.out.println("[insert] 插入文件: " + fileMeta.getPath() + File.separator + fileMeta.getName());}// 执行所有的 sql 片段statement.executeBatch();// 执行完毕后, 通过 commit 告诉数据库, 添加完毕, 执行上述 batch 操作(自动提交已经关闭了)connection.commit();} catch (SQLException e) {try {if(connection != null) {// 如果连接已建立, 并且出现异常, 那就是提交的内容有错误, 此时进行回滚操作connection.rollback();}} catch (SQLException ex) {ex.printStackTrace();}} finally {DBUtil.close(connection, statement, null);}}/***  3.按照特定的关键词进行查询*  此处查询 pattern , 可能是文件名的一部分, 可能是文件名拼音的一部分, 也可能是拼音首字母的一部分 ...* @param pattern 根据 pattern 查询数据库匹配内容* @return*/public List<FileMeta> searchByPattern(String pattern) {List<FileMeta> fileMetas = new ArrayList<>();Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try {connection = DBUtil.getConnection();String sql = "select name, path, is_directory, size, last_modified from file_meta " +" where name like ? or pinyin like ? or pinyin_first like ? " +" order by path, name";statement = connection.prepareStatement(sql);statement.setString(1,"%" + pattern + "%");statement.setString(2,"%" + pattern + "%");statement.setString(3,"%" + pattern + "%");resultSet = statement.executeQuery();while(resultSet.next()) {String name = resultSet.getString("name");String path = resultSet.getString("path");boolean isDirectory = resultSet.getBoolean("is_directory");long size = resultSet.getLong("size");Timestamp lastModified = resultSet.getTimestamp("last_modified");FileMeta fileMeta = new FileMeta(name, path, isDirectory, size, lastModified.getTime());fileMetas.add(fileMeta);}} catch (SQLException e) {e.printStackTrace();} finally {DBUtil.close(connection, statement, resultSet);}return fileMetas;}/***  根据给定路径查询结果.* @param targetPath 给定路径* @return 该路径下的所有文件信息(一层)*/public List<FileMeta> searchByPath(String targetPath) {List<FileMeta> fileMetas = new ArrayList<>();Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try {connection = DBUtil.getConnection();String sql = "select name, path, is_directory, size, last_modified from file_meta " +" where path = ?";statement = connection.prepareStatement(sql);statement.setString(1, targetPath);resultSet = statement.executeQuery();while(resultSet.next()) {String name = resultSet.getString("name");String path = resultSet.getString("path");boolean isDirectory = resultSet.getBoolean("is_directory");long size = resultSet.getLong("size");Timestamp lastModified = resultSet.getTimestamp("last_modified");FileMeta fileMeta = new FileMeta(name, path, isDirectory, size, lastModified.getTime());fileMetas.add(fileMeta);}} catch (SQLException e) {e.printStackTrace();} finally {DBUtil.close(connection, statement, resultSet);}return fileMetas;}/***  发现某个文件已从磁盘上删除, 此时需要把对应表里的内容删除掉* @param fileMetas 删除的 文件/目录*/public void delete(List<FileMeta> fileMetas) {Connection connection = null;PreparedStatement statement = null;try {connection = DBUtil.getConnection();connection.setAutoCommit(false);  // 将自动提交关闭, 把下列批量删除操作看作一个事务进行for(FileMeta fileMeta : fileMetas) {String sql = null;if(!fileMeta.isDirectory()) {// 对文件的sql语句构造sql = "delete from file_meta where name = ? and path = ?";statement = connection.prepareStatement(sql);statement.setString(1, fileMeta.getName());statement.setString(2, fileMeta.getPath());} else {// 对目录的sql语句构造sql = "delete from file_meta where (name = ? and path = ?) or (path like ?)";statement = connection.prepareStatement(sql);statement.setString(1, fileMeta.getName());statement.setString(2, fileMeta.getPath());statement.setString(3, fileMeta.getPath() + File.separator + fileMeta.getName() + File.separator + "%");}statement.executeUpdate();System.out.println("[delete] " + fileMeta.getPath() + "\\" + fileMeta.getName());// 此处对于每个 statement 对象都要单独关闭// (每个 statement 都可能是不同的 sql 语句, 以前可以统一关闭是因为 sql 模板相同, 只是填充参数不同, 修改一下参数就可以接着用)statement.close();}// 告知数据库, 事务构造完毕, 进行统一提交connection.commit();} catch (SQLException e) {try {connection.rollback();} catch (SQLException ex) {ex.printStackTrace();}} finally {DBUtil.close(connection, null, null);}}
}

工具类

PinyinUtil

封装 Pinyin4j 的功能
汉字 => 拼音 (全拼 / 首字母)

public class PinyinUtil {/***  获取字符串的拼音** @param src  第一个参数表示要获取拼音的字符串* @param fullSpell  第二个参数表示是否是全拼.*                   比如针对"你好啊"该字符串, true 对应全拼: nihaoa, false 对应首字母: nha*                   此处针对多音字不做过多考虑, 采用第一个元素代表的发音(也是最常用的发音)* @return  字符串的拼音*/public static String get(String src, Boolean fullSpell) {// trim() 去除字符串两侧的空白字符. eg: \t  \n  \f  \v  空格 ...if(src == null || src.trim().length() == 0) {// 空字符不做处理return null;}// 针对 Pinyin4j 做一些配置, 让他将拼音 yu 使用 v 表示HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();format.setVCharType(HanyuPinyinVCharType.WITH_V);// 遍历字符串的每个字符, 针对每个字符分别进行转换, 将转换得到的拼音, 拼接到 StringBuilder 里StringBuilder stringBuilder = new StringBuilder();src = src.trim();for(int i=0;i<src.length();i++) {// 针对单个字符进行转换char ch = src.charAt(i);String[] tmp = null;try {tmp = PinyinHelper.toHanyuPinyinStringArray(ch, format);} catch (BadHanyuPinyinOutputFormatCombination e) {e.printStackTrace();}if(tmp == null || tmp.length == 0) {// 拼音转换失败, 返回空数组// 说明当前字符就不是汉字, 可能是字母,数字或符号, eg: a, b, c, 1, 2, 3// 此时保留原始字符就好stringBuilder.append(ch);}else if(fullSpell) {stringBuilder.append(tmp[0]);}else {stringBuilder.append(tmp[0].charAt(0));}}return stringBuilder.toString();}
}

功能处理

扫描文件目录, 将目录下所有文件/目录信息存储到数据库中

当选择搜索路径后, 会递归的扫描指定路径下的所有目录及文件, 并将扫描到的 所有文件/目录信息 存储到数据库中
(查数据库比查文件系统要快, 因此其实每次查找指定文件在文件系统中出现的位置, 都是查询数据库中预存的信息)

public class GUIController implements Initializable {@FXMLprivate Label label;@FXMLprivate GridPane gridPane;@FXMLprivate Button button;@FXMLprivate TextField textField;@FXMLprivate TableView<FileMeta> tableView;private SearchService searchService = null;/*** 使用该方法, 作为鼠标点击事件的回调函数* @param mouseEvent*/public void choose(MouseEvent mouseEvent) {// 创建一个 目录选择器DirectoryChooser directoryChooser = new DirectoryChooser();// 把该对话框显示出来Window window = gridPane.getScene().getWindow();// 获取选定的文件File file = directoryChooser.showDialog(window);if(file == null) {System.out.println("用户选择的路径为空");} else {System.out.println(file.getAbsolutePath());}// 把用户选择的路径,显示到 label 中label.setText(file.getAbsolutePath());// 如果不是首次扫描, 就应该停止上次扫描任务, 执行本次扫描任务if(searchService != null) {searchService.shutdown();}// 对用户选择的路径进行扫描, 初始化searchService = new SearchService();searchService.init(file.getAbsolutePath());}
}

在这里插入图片描述

搜索框内容发生改变后, 自动进行数据库搜索, 将匹配内容展示到页面

当搜索框内容改变时, 会被系统绑定的事件监听到, 重新进行数据库搜索, 并将匹配信息作为结果返回到查询结果显示处

public class GUIController implements Initializable {@FXMLprivate Label label;@FXMLprivate GridPane gridPane;@FXMLprivate Button button;@FXMLprivate TextField textField;@FXMLprivate TableView<FileMeta> tableView;private SearchService searchService = null;@Overridepublic void initialize(URL location, ResourceBundle resources) {// 在这里对 输入框 加一个监听器// 需要指定对 text 这个内容属性进行监听// textField.textProperty() 获取输入框里的内容textField.textProperty().addListener(new ChangeListener<String>() {/***  会在用户每次修改 输入框内容 的时候, 被自动调用到* @param observable* @param oldValue 输入框被修改之前的值* @param newValue 输入框被修改之后的值*/@Overridepublic void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {// 此处要干的事情, 是根据新的值, 重新进行查询操作freshTable(newValue);}});}private void freshTable(String query) {// 重新查询数据库, 把查询结果, 设置到表格中if(searchService == null) {System.out.println("searchService 尚未初始化, 不能查询!");return;}// 把之前表里的内容清空掉ObservableList<FileMeta> fileMetas = tableView.getItems();fileMetas.clear();List<FileMeta> results = searchService.search(query);fileMetas.addAll(results);}
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/331423.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Boss说,搞个深色B端系统。敢要就敢搞,宁被累死,不被吓死。

老规矩&#xff0c;先上文字说服&#xff08;洗脑&#xff09;自己&#xff0c;再附案例。 深色系B端系统是指在企业级应用中&#xff0c;使用深色主题的后台管理系统。这种设计风格主要以暗色调为主&#xff0c;如黑色、深灰色等&#xff0c;与传统的亮色主题相比&#xff0c…

Orangepi Zero2 linux系统摄像头设备文件名固定

文章目录 1. 寻找设备规则2. 使用udev规则修改挂载设备文件名称 问题&#xff1a; 在多次插拔usb摄像头或者在使用中不小心碰到或松了会导致设备文件名称变化&#xff0c;如从/dev/video1和/dev/video2变为/dev/video2和/dev/video3, 所以每次发生变化后都要充型修改代码或者重…

小红书无限加群脚本无需ROOT【使用简单无教程】

小红书无限加群脚本无需ROOT&#xff0c;包含了对应的小红书版本【使用简单无教程】 链接&#xff1a;https://pan.baidu.com/s/1HkLhahmHDFMKvqCC3Q3haA?pwd6hzf 提取码&#xff1a;6hzf

【Linux】TCP协议【中】{确认应答机制/超时重传机制/连接管理机制}

文章目录 1.确认应答机制2.超时重传机制&#xff1a;超时不一定是真超时了3.连接管理机制 1.确认应答机制 TCP协议中的确认应答机制是确保数据可靠传输的关键部分。以下是该机制的主要步骤和特点的详细解释&#xff1a; 数据分段与发送&#xff1a; 发送方将要发送的数据分成一…

Vue 3 组件基础与模板语法详解

title: Vue 3 组件基础与模板语法详解 date: 2024/5/24 16:31:13 updated: 2024/5/24 16:31:13 categories: 前端开发 tags: Vue3特性CompositionAPITeleportSuspenseVue3安装组件基础模板语法 Vue 3 简介 1. Vue 3 的新特性 Vue 3引入了许多新的特性&#xff0c;以提高框…

c++编程14——STL(3)list

欢迎来到博主的专栏&#xff1a;c编程 博主ID&#xff1a;代码小豪 文章目录 list成员类型构造、析构、与赋值iterator元素访问修改元素list的操作 list list的数据结构是一个链表&#xff0c;准确的说应该是一个双向链表。这是一个双向链表的节点结构&#xff1a; list的使用…

共享单车(八):数据库

实现后台数据库访问模块的框架&#xff0c;能够实现验证请求并响应&#xff08;支持数据库操作&#xff09;。 数据库设计 class SqlTabel //负责数据库表的创建 { public:SqlTabel(std::shared_ptr<MysqlConnection> sqlconn) :sqlconn_(sqlconn) {}bool CreateUserI…

超值分享50个DFM模型格式的素人直播资源,适用于DeepFaceLive的DFM合集

50直播模型&#xff1a;点击下载 作为直播达人&#xff0c;我在网上购买了大量直播用的模型资源&#xff0c;包含男模女模、明星脸、大众脸、网红脸及各种稀缺的路人素人模型。现在&#xff0c;我将这些宝贵的资源整理成合集分享给大家&#xff0c;需要的朋友们可以直接点击下…

电商项目之有趣的支付签名算法

文章目录 1 问题背景2 思路3 代码实现 1 问题背景 在发起支付的时候&#xff0c;一般都需要对发送的请求参数进行加密或者签名&#xff0c;下文简称这个过程为“签名”。行业内比较普遍的签发算法有&#xff1a; &#xff08;1&#xff09;按支付渠道给定的字段排序进行拼接&am…

amis 联动效果触发的几种方式

联动效果实现主要俩种方式: 1.表达式实现联动,基于组件内或数据链的变量变化的联动 比如&#xff1a; "source": "/amis/api/mock2/options/level2?name${name} " (必须是这种字符串拼接形式,在data数据映射中表达式不会触发联动) 所有初始化接口链…

Docker学习(3):镜像使用

当运行容器时&#xff0c;使用的镜像如果在本地中不存在&#xff0c;docker 就会自动从 docker 镜像仓库中下载&#xff0c;默认是从 Docker Hub 公共镜像源下载。 一、列出镜像列表 可以使用 docker images 来列出本地主机上的镜像。 各个选项说明&#xff1a; REPOSITORY&am…

UDP的报文结构和注意事项

UDP协议是在传输层的协议。 UDP无连接&#xff0c;不可靠传输&#xff0c;面向数据报&#xff0c;全双工。 UDP的报文结构 学习网络协议&#xff0c;最主要的就是报文格式。 对于UDP来说&#xff0c;应用层的数据到达&#xff0c;UDP之后&#xff0c;就会给应用层的数据报前面…

大工作量LUAD代谢重编程模型多组学(J Transl Med)

目录 1&#xff0c;单细胞早期、晚期和转移性 LUAD 的细胞动力学变化 2&#xff0c;细胞代谢重编程介导的LUAD驱动恶性转移的异质性 3&#xff0c;模型构建 S-MMR评分管线构建 4&#xff0c;S-MMR 模型的预后评估 5&#xff0c; 还开发了S-MMR 评分网络工具 6&#xff0c…

从零开始搭建Springboot项目脚手架4:保存操作日志

目的&#xff1a;通过AOP切面&#xff0c;统一记录接口的访问日志 1、加maven依赖 2、 增加日志类RequestLog 3、 配置AOP切面&#xff0c;把请求前的request、返回的response一起记录 package com.template.common.config;import cn.hutool.core.util.ArrayUtil; import cn.hu…

面试八股之JVM篇3.6——垃圾回收——强引用、弱引用、虚引用、软引用

&#x1f308;hello&#xff0c;你好鸭&#xff0c;我是Ethan&#xff0c;一名不断学习的码农&#xff0c;很高兴你能来阅读。 ✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。 &#x1f3c3;人生之义&#xff0c;在于追求&#xff0c;不在成败&#xff0c;勤通…

【机器学习系列】使用高斯贝叶斯模型进行数据分类的完整流程

目录 一、导入数据 二、选择特征 三、十折交叉验证 四、划分训练集和测试集 五、训练高斯贝叶斯模型 六、预测测试集 七、查看训练集和测试集上的分数 八、查看混合矩阵 九、输出评估指标 一、导入数据 # 根据商户数据预测其是否续约案例 import pandas #读取数据到 da…

YOLOv10 论文学习

论文链接&#xff1a;https://arxiv.org/pdf/2405.14458 代码链接&#xff1a;https://github.com/THU-MIG/yolov10 解决了什么问题&#xff1f; 实时目标检测是计算机视觉领域的研究焦点&#xff0c;目的是以较低的延迟准确地预测图像中各物体的类别和坐标。它广泛应用于自动…

结构体(位段)内存分配

结构体由多个数据类型的成员组成。那编译器分配的内存是不是所有成员的字节数总和呢&#xff1f; 首先&#xff0c;stu的内存大小并不为29个字节&#xff0c;即证明结构体内存不是所有成员的字节数和。   其次&#xff0c;stu成员中sex的内存位置不在21&#xff0c;即可推测…

CS 下载安装详解

目录 CS简介&#xff1a; CS下载地址&#xff1a; CS的安装&#xff1a; CS简介&#xff1a; CS为目前渗透中常用的一款工具&#xff0c;它的强大在于控制windows木马&#xff0c;CS主要控制windows木马。 CS下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/…

【Linux】-Zookeeper安装部署[17]

简介 apache ZooKeeper是一个分布式的&#xff0c;开放源码的分布式应用程序协调服务&#xff0c;是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件&#xff0c;提供的功能包括&#xff1a;配置维护、域名服务、分布式同步、组服务等。 除了为Hadoop和H…