修改Android Studio项目配置JDK路径和项目Gradle路径的GUI工具

news2024/11/18 10:20:55

概述

本工具提供了一个基于Python Tkinter的图形用户界面(GUI),用于帮助用户搜索并更新Android Studio项目中的config.properties文件里的java.home路径,以及workspace.xml文件中的last_opened_file_path路径。该工具旨在简化手动查找和编辑这些配置文件的过程,提高工作效率。

系统要求

  • Python 3.x
  • Tkinter库(通常随Python一起安装)

安装步骤

  1. 确保你的系统上已经安装了Python 3.x。
  2. 将上述提供的Python脚本保存到一个文件中,例如命名为config_editor.py
  3. 打开命令行工具(如CMD、PowerShell或终端)。
  4. 导航到包含config_editor.py文件的目录。
  5. 运行脚本:
     
    import tkinter as tk
    from tkinter import scrolledtext
    import os
    import xml.etree.ElementTree as ET
    import json
    
    # 定义查找配置配置文件的函数
    def find_properties_files(directory):
        found_files = []
        for root, dirs, files in os.walk(directory):
            for file in files:
                if file.lower() == 'config.properties':
                    found_files.append(os.path.join(root, file))
        return found_files
    
    # 定义读取java.home的函数
    def read_java_home(file_path):
        try:
            with open(file_path, 'r', encoding='utf-8') as file:
                for line in file:
                    if line.lower().startswith('java.home='):
                        return line.strip()
        except Exception as e:
            log_text.insert(tk.END, f"读取配置文件 {file_path} 失败: {e}\n")
        return None
    
    # 定义写入java.home的函数
    def write_java_home(file_path, new_line):
        try:
            with open(file_path, 'r+', encoding='utf-8') as file:
                lines = file.readlines()
                file.seek(0)
                file.truncate()
                found = False
                for line in lines:
                    if line.lower().startswith('java.home='):
                        file.write(new_line + '\n')
                        found = True
                    else:
                        file.write(line)
                if not found:
                    file.write(new_line + '\n')
        except Exception as e:
            log_text.insert(tk.END, f"写入配置文件 {file_path} 失败: {e}\n")
    
    # 搜索按钮点击事件
    def on_search():
        directory = search_entry.get().strip()
        if not directory:
            directory = os.getcwd()
    
        log_text.delete(1.0, tk.END)
    
        found_files = find_properties_files(directory)
        if not found_files:
            status_label.config(text="没有找到任何config.properties配置文件")
            log_text.insert(tk.END, "没有找到任何config.properties配置文件\n")
        else:
            status_label.config(text=f"找到 {len(found_files)} 个config.properties配置文件")
            log_text.insert(tk.END, f"找到 {len(found_files)} 个config.properties配置文件\n")
            for file_path in found_files:
                log_text.insert(tk.END, f"处理配置文件: {file_path}\n")
    
    # 更新按钮点击事件
    def on_update():
        new_value = entry_new_value.get().strip()
        if not new_value:
            #log_text.insert(tk.END, "新的java.home路径不能为空\n")
            status_label.config(text=f"新的java.home路径不能为空")
            return
    
        log_text.delete(1.0, tk.END)
    
        directory = search_entry.get().strip()
        if not directory:
            directory = os.getcwd()
    
        log_text.insert(tk.END, f"目标路径: {directory}\n")
    
        found_files = find_properties_files(directory)
        if not found_files:
            status_label.config(text="没有找到任何config.properties配置文件")
            log_text.insert(tk.END, "没有找到任何config.properties配置文件\n")
        else:
            status_label.config(text=f"找到 {len(found_files)} 个config.properties配置文件")
            log_text.insert(tk.END, f"找到 {len(found_files)} 个config.properties配置文件\n")
            for file_path in found_files:
                log_text.insert(tk.END, f"处理配置文件: {file_path}\n")
                current_java_home = read_java_home(file_path)
                if current_java_home:
                    log_text.insert(tk.END, f"配置文件路径: {file_path}, 当前值: {current_java_home}, 已更新: java.home={new_value}\n")
                else:
                    log_text.insert(tk.END, f"配置文件路径: {file_path}, 未找到java.home属性, 已更新: java.home={new_value}\n")
                write_java_home(file_path, f"java.home={new_value}")
    
    # 搜索workspace.xml配置文件
    def on_workspace_xml_search():
        directory = search_entry.get().strip()
        if not directory:
            directory = os.getcwd()
    
        log_text.delete(1.0, tk.END)
    
        found_files = []
        for root, dirs, files in os.walk(directory):
            for file in files:
                if file.lower() == 'workspace.xml':
                    found_files.append(os.path.join(root, file))
    
        if not found_files:
            log_text.insert(tk.END, "没有找到workspace.xml配置文件\n")
        else:
            status_label.config(text=f"找到 {len(found_files)} 个workspace.xml配置文件")
            log_text.insert(tk.END, f"找到 {len(found_files)} 个workspace.xml配置文件\n")
            for file_path in found_files:
                log_text.insert(tk.END, f"处理配置文件: {file_path}\n")
    
    # 更新workspace.xml配置文件
    def on_workspace_xml_update():
        directory = search_entry.get().strip()
        if not directory:
            directory = os.getcwd()
    
        log_text.delete(1.0, tk.END)
    
    import json
    import os
    import tkinter as tk
    from lxml import etree
    
    # 更新workspace.xml配置文件
    def on_workspace_xml_update():
        directory = search_entry.get().strip()
        if not directory:
            directory = os.getcwd()
    
        # 获取新的 last_opened_file_path
        new_last_opened_file_path = new_last_opened_file_path_entry.get().strip()
        if not new_last_opened_file_path:
            messagebox.showerror("错误", "新的last_opened_file_path不能为空")
            
            return
    
        # 确保路径使用正斜杠
        new_last_opened_file_path = new_last_opened_file_path.replace("\\", "/")
    
        # 查找workspace.xml配置文件
        found_files = []
        for root, dirs, files in os.walk(directory):
            for file in files:
                if file.lower() == 'workspace.xml':
                    found_files.append(os.path.join(root, file))
    
        if not found_files:
            messagebox.showinfo("信息", "没有找到workspace.xml配置文件")
            return
    
        for workspace_xml_path in found_files:
            log_text.insert(tk.END, f"处理配置文件: {workspace_xml_path}\n")
    
            try:
                # 读取并解析XML配置文件
                parser = etree.XMLParser(strip_cdata=False)  # 保持CDATA部分不变
                tree = etree.parse(workspace_xml_path, parser)
                root = tree.getroot()
    
                # 查找PropertiesComponent组件
                properties_component = root.find(".//component[@name='PropertiesComponent']")
                if properties_component is None:
                    log_text.insert(tk.END, "找不到 PropertiesComponent 组件\n")
                    continue
    
                # 提取CDATA内容
                cdata_content = properties_component.text
                if not cdata_content or not cdata_content.strip().startswith("<![CDATA[") or not cdata_content.strip().endswith("]]>"):
                    log_text.insert(tk.END, "找不到 PropertiesComponent 组件或其 JSON 数据\n")
                    continue
    
                # 去掉CDATA标记
                key_to_string_json = cdata_content.strip()[len("<![CDATA["):-len("]]>")].strip()
                log_text.insert(tk.END, f"原始 keyToString JSON 数据: {key_to_string_json}\n")
    
                # 使用json.loads解析JSON数据
                key_to_string_dict = json.loads(key_to_string_json, strict=False)
    
                # 获取旧的 last_opened_file_path
                old_last_opened_file_path = key_to_string_dict.get('keyToString', {}).get('last_opened_file_path', '')
                log_text.insert(tk.END, f"修改前: last_opened_file_path={old_last_opened_file_path}\n")
    
                # 更新last_opened_file_path
                key_to_string_dict.setdefault('keyToString', {})['last_opened_file_path'] = new_last_opened_file_path
                log_text.insert(tk.END, f"修改后: last_opened_file_path={new_last_opened_file_path}\n")
    
                # 生成新的 JSON 数据
                # 保持原始 JSON 数据的格式
                new_key_to_string_json = json.dumps(key_to_string_dict, ensure_ascii=False, indent=None, separators=(',', ': '))
    
                # 构造新的CDATA内容
                new_cdata_content = "<![CDATA[" + new_key_to_string_json + "]]>"
    
                # 更新CDATA内容
                properties_component.text = new_cdata_content
    
                # 写回workspace.xml配置文件
                tree.write(workspace_xml_path, encoding='utf-8', xml_declaration=True, pretty_print=True)
    
                log_text.insert(tk.END, f"已更新或添加last_opened_file_path: {new_last_opened_file_path} 到 {workspace_xml_path}\n")
            except json.JSONDecodeError as e:
                log_text.insert(tk.END, f"JSON 解析错误: {e}\n")
            except Exception as e:
                log_text.insert(tk.END, f"处理配置文件 {workspace_xml_path} 失败: {e}\n")
    import re
    import os
    import tkinter as tk
    from tkinter import messagebox
    
    # 更新workspace.xml配置文件
    def on_workspace_xml_update():
        directory = search_entry.get().strip()
        if not directory:
            directory = os.getcwd()
    
        # 获取新的 last_opened_file_path
        new_last_opened_file_path = new_last_opened_file_path_entry.get().strip()
        if not new_last_opened_file_path:
            #messagebox.showerror("错误", "新的last_opened_file_path不能为空")
            status_label.config(text=f"新的last_opened_file_path不能为空")
            return
    
        # 确保路径使用正斜杠
        new_last_opened_file_path = new_last_opened_file_path.replace("\\", "/")
    
        # 查找workspace.xml配置文件
        found_files = []
        for root, dirs, files in os.walk(directory):
            for file in files:
                if file.lower() == 'workspace.xml':
                    found_files.append(os.path.join(root, file))
    
        if not found_files:
            messagebox.showinfo("信息", "没有找到workspace.xml配置文件")
            return
    
        for workspace_xml_path in found_files:
            # 读取配置文件内容
            with open(workspace_xml_path, 'r', encoding='utf-8') as file:
                content = file.read()
    
            # 查找包含 "last_opened_file_path" 的 JSON 字符串
            pattern = r'"last_opened_file_path"\s*:\s*"([^"]+)"'
            match = re.search(pattern, content)
    
            if match:
                # 替换 "last_opened_file_path" 的值
                old_value = match.group(1)
                content = re.sub(pattern, f'"last_opened_file_path": "{new_last_opened_file_path}"', content)
    
                # 写回配置文件
                with open(workspace_xml_path, 'w', encoding='utf-8') as file:
                    file.write(content)
    
                log_text.insert(tk.END, f"已将 {old_value} 替换为 {new_last_opened_file_path} 在 {workspace_xml_path}\n")
            else:
                log_text.insert(tk.END, f"未找到 last_opened_file_path 在 {workspace_xml_path}\n")
    
    
    
    
    
    import tkinter as tk
    from tkinter import scrolledtext
    import tkinter.font as tkFont
    import os
    import re
    
    # RGB值
    background_rgb = (43, 42, 51)
    output_bg_rgb = (31, 31, 31)
    output_fg_rgb = (255, 255, 255)  # 白色
    button_bg_rgb = (31, 31, 31)  # 按钮背景颜色
    button_fg_rgb = (0, 128, 0)  # 按钮文本颜色
    entry_bg_rgb = (31, 31, 31)  # 输入框背景颜色
    entry_fg_rgb = (255, 255, 255)  # 输入框文本颜色
    label_bg_rgb = (43, 42, 51)  # 标签背景颜色
    label_fg_rgb = (255, 255, 255)  # 标签文本颜色
    
    # 辅助函数
    def create_label(parent, text, **kwargs):
        return tk.Label(
            parent,
            text=text,
            font=large_font,
            fg=f"#{label_fg_rgb[0]:02X}{label_fg_rgb[1]:02X}{label_fg_rgb[2]:02X}",
            bg=f"#{label_bg_rgb[0]:02X}{label_bg_rgb[1]:02X}{label_bg_rgb[2]:02X}",
            **kwargs
        )
    
    def create_entry(parent, **kwargs):
        return tk.Entry(
            parent,
            font=large_font,
            fg=f"#{entry_fg_rgb[0]:02X}{entry_fg_rgb[1]:02X}{entry_fg_rgb[2]:02X}",
            bg=f"#{entry_bg_rgb[0]:02X}{entry_bg_rgb[1]:02X}{entry_bg_rgb[2]:02X}",
            **kwargs
        )
    
    def create_button(parent, text, command, **kwargs):
        return tk.Button(
            parent,
            text=text,
            font=large_font,
            fg=f"#{button_fg_rgb[0]:02X}{button_fg_rgb[1]:02X}{button_fg_rgb[2]:02X}",
            bg=f"#{button_bg_rgb[0]:02X}{button_bg_rgb[1]:02X}{button_bg_rgb[2]:02X}",
            command=command,
            **kwargs
        )
    
    # 日志记录
    def log(message):
        log_text.insert(tk.END, message + "\n")
        log_text.see(tk.END)  # 自动滚动到底部
    # 创建主窗口
    root = tk.Tk()
    # 定义一个更大的字体(不加粗)
    large_font = tkFont.Font(family="宋体", size=13)  # 调整字体大小,但不加粗
    root.title("修改android-studio项目配置JDK路径和项目gradle路径")
    #root.title("Config Properties & Workspace XML Editor")
    
    # 设置背景颜色
    root.configure(bg=f"#{background_rgb[0]:02X}{background_rgb[1]:02X}{background_rgb[2]:02X}")
    
    # 定义一个更大的字体(不加粗)
    large_font = tkFont.Font(family="宋体", size=13)  # 调整字体大小,但不加粗
    
    # 创建GUI组件
    create_label(root, "请输入目录路径 (留空则使用当前路径),搜索config.properties中java.home值").pack(pady=5)
    search_entry = create_entry(root, width=50)
    search_entry.pack(pady=5)
    
    # 搜索config.properties按钮
    search_button = create_button(root, "搜索android-studio项目配置JDK路径", on_search)
    search_button.pack(pady=5)
    
    # 输入新的java.home值
    create_label(root, "请输入新的java.home值=android-studio项目自定义配置JDK路径").pack(pady=9)
    entry_new_value = create_entry(root, width=50)
    entry_new_value.pack(pady=5)
    
    # 更新config.properties按钮
    update_button = create_button(root, "更新android-studio配置JDK路径", on_update)
    update_button.pack(pady=5)
    
    # 分隔符
    tk.Frame(height=2, bd=1, relief=tk.SUNKEN).pack(fill=tk.X, padx=5, pady=5)
    
    # 搜索workspace.xml按钮
    workspace_xml_search_button = create_button(root, "搜索workspace.xml", on_workspace_xml_search)
    workspace_xml_search_button.pack(pady=5)
    
    # 输入新的last_opened_file_path
    create_label(root, "请输入新的last_opened_file_path=你的android-studio的gradle路径").pack(pady=5)
    new_last_opened_file_path_entry = create_entry(root, width=50)
    new_last_opened_file_path_entry.pack(pady=5)
    
    # 更新workspace.xml按钮
    workspace_xml_update_button = create_button(root, "更新workspace.xml=配置android-studio项目的gradle路径", on_workspace_xml_update)
    workspace_xml_update_button.pack(pady=5)
    
    # 状态标签
    status_label = create_label(root, "")
    status_label.pack(pady=5)
    
    # 日志文本框
    log_text = scrolledtext.ScrolledText(
        root,
        width=80,
        height=20,
        wrap=tk.WORD,
        font=large_font,
        fg=f"#{output_fg_rgb[0]:02X}{output_fg_rgb[1]:02X}{output_fg_rgb[2]:02X}",
        bg=f"#{output_bg_rgb[0]:02X}{output_bg_rgb[1]:02X}{output_bg_rgb[2]:02X}"
    )
    log_text.pack(pady=5)
    
    # 运行主循环
    root.mainloop()
     

主窗口布局

  • 输入目录路径:用户可以在这里输入Android Studio项目的根目录路径。如果留空,则默认使用当前工作目录。
  • 搜索config.properties:点击此按钮将搜索指定目录下的config.properties文件,并显示当前的java.home值。
  • 输入新的java.home:用户可以在此输入新的JDK路径。
  • 更新config.properties:点击此按钮将更新config.properties文件中的java.home值为用户指定的新路径。
  • 搜索workspace.xml:点击此按钮将搜索指定目录下的workspace.xml文件,并显示当前的last_opened_file_path值。
  • 输入新的last_opened_file_path:用户可以在此输入新的Gradle路径。
  • 更新workspace.xml:点击此按钮将更新workspace.xml文件中的last_opened_file_path值为用户指定的新路径。
  • 日志文本框:显示操作过程中的信息和结果。

使用步骤

  1. 启动程序:运行config_editor.py后,会弹出一个窗口。
  2. 输入目录路径(可选):在“请输入目录路径 (留空则使用当前路径)”输入框中输入Android Studio项目的根目录路径。如果留空,则默认使用当前工作目录。
  3. 搜索config.properties:点击“搜索android-studio项目配置JDK路径”按钮。程序会在指定目录下查找config.properties文件,并显示当前的java.home值。
  4. 更新java.home
    • 在“请输入新的java.home值”输入框中输入新的JDK路径。
    • 点击“更新android-studio配置JDK路径”按钮,程序会更新config.properties文件中的java.home值。
  5. 搜索workspace.xml:点击“搜索workspace.xml”按钮。程序会在指定目录下查找workspace.xml文件,并显示当前的last_opened_file_path值。
  6. 更新last_opened_file_path
    • 在“请输入新的last_opened_file_path”输入框中输入新的Gradle路径。
    • 点击“更新workspace.xml=配置android-studio项目的gradle路径”按钮,程序会更新workspace.xml文件中的last_opened_file_path值。
  7. 查看日志:所有操作的结果都会显示在日志文本框中,包括成功消息和错误信息。

注意事项

  • 确保你有足够的权限来读取和写入指定的文件。
  • 在更新配置文件之前,请备份原始文件,以防意外发生。
  • 请确保输入的路径是正确的,并且路径存在。
  • 如果路径或文件名包含特殊字符,请确保它们被正确转义或引用。

通过以上步骤,你可以轻松地管理和更新Android Studio项目的配置文件,从而确保项目使用的JDK和Gradle路径是正确的。希望这个工具能帮助你提高开发效率!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

shell脚本_永久环境变量和字符串操作

一、永久环境变量 1. 常见的环境变量 2. 设置永久环境变量 3.1.将脚本加进PATH变量的目录中 3.2.添加进环境变量里 3.2.修改用户的 shell 配置文件 二、字符串操作 1. 字符串拼接 2. 字符串切片 3. 字符串查找 4. 字符串替换 5. 字符串大小写转换 6. 字符串分割 7…

操作系统进程管理实验

父子进程 用系统调用fork()函数实现子进程的创建&#xff0c;熟悉进程创建的执行过程。 #include <stdio.h> #include <stdlib.h> #include <unistd.h>int main() {// 打印主进程的 PIDprintf("hello, world (pid: %d)\n", (int)getpid());// 创…

DB Type

P位 p 1时段描述符有效&#xff0c;p 0时段描述符无效 Base Base被分成了三个部分&#xff0c;按照实际拼接即可 G位 如果G 0 说明描述符中Limit的单位是字节&#xff0c;如果是G 1 &#xff0c;那么limit的描述的单位是页也就是4kb S位 S 1 表示代码段或者数据段描…

获取当前程序运行时的栈大小[C语言]

废话前言 一晃已经毕业了4年&#xff0c;也在某个时间点&#xff0c;从面试者转变成了面试官。 进行第一次面试的时候&#xff0c;我好像比候选人还慌张&#xff0c;压根不知道问什么&#xff0c;好在是同行业&#xff0c;看着简历问了一些协议内容以及模块设计思路&#xff0…

新160个crackme - 098-DueList.4

运行分析 需破解Name和Code PE分析 ASM汇编程序&#xff0c;32位&#xff0c;无壳 静态分析&动态调试 ida搜索找到关键字符串 ida动态调试&#xff0c;逻辑如上 算法分析 Name concealstr_1 SU7CSJKF09NCSDO9SDF09SDRLVK7809S4NF str_2 A1LSK2DJF4HGP3QWO5EIR6UTYZ8MXN…

ETH钱包地址如何获取 如何购买比特币

首先我们要先注册一个交易所 Gate.io&#xff08;推荐&#xff09;: 点我注册 1、注册很简单&#xff0c;通过手机号就可以进行注册了。 2、获取ETH钱包地址 注册好之后&#xff0c;如图所示&#xff0c;点击“统一账户” 3、通过搜索栏搜索ETH&#xff0c;如下图所示 4、点…

【HOT100第五天】搜索二维矩阵 II,相交链表,反转链表,回文链表

240.搜索二维矩阵 II 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。每列的元素从上到下升序排列。 先动手写写最简单方法&#xff0c;二重循环。 class Solution { public:bool searchMa…

.NET 9与C# 13革新:新数据类型与语法糖深度解析

记录&#xff08;Record&#xff09;类型 使用方式&#xff1a; public record Person(string FirstName, string LastName); 适用场景&#xff1a;当需要创建不可变的数据结构&#xff0c;且希望自动生成 GetHashCode 和 Equals 方法时。不适用场景&#xff1a;当数据结构需…

冠层四流近似模型的发展历史

1. Kunbelka-Munk theory This is the earlist model using a two-stream approximation d I d z − ( k s ) I s J d J d z ( k s ) J − s I \begin{aligned} &\frac{dI}{dz} -(ks)IsJ\\ &\frac{dJ}{dz} (ks)J - sI \end{aligned} ​dzdI​−(ks)IsJdzdJ​(…

MySQL-关联查询和子查询

目录 一、笛卡尔积 二、表连接 1、内部连接 1.1 等值连接 1.2 非等值连接 2、外部链接 2.1 左外连接-LEFT JOIN 2.2 右外连接-RIGHT JOIN 2.3 全关联-FULL JOIN/UNION 三、子查询 1、嵌套子查询 2、相关子查询 3、insert和select语句添加数据 4、update和select语…

云计算虚拟化-kvm创建虚拟机

作者介绍&#xff1a;简历上没有一个精通的运维工程师。希望大家多多关注作者&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 虚拟化&#xff0c;简单来说就是把一台服务器/PC电脑&#xff0c;虚拟成多台独立的虚拟机&#xff0c;每台虚拟机之间相互隔…

计算机编程中的设计模式及其在简化复杂系统设计中的应用

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 计算机编程中的设计模式及其在简化复杂系统设计中的应用 计算机编程中的设计模式及其在简化复杂系统设计中的应用 计算机编程中的…

编程考古-计算机发展(中)

晶体管计算机时代 尽管真空管技术标志着计算机步入了现代化的门槛&#xff0c;但其固有的局限性——庞大的体积、高昂的能耗、频繁的故障以及不菲的成本——极大地阻碍了其普及与实际应用。 晶体管的早期 Point-contact transistor 点接触晶体管 1947年&#xff0c;贝尔实验…

vue2+3 —— Day5/6

自定义指令 自定义指令 需求&#xff1a;当页面加载时&#xff0c;让元素获取焦点&#xff08;一进页面&#xff0c;输入框就获取焦点&#xff09; 常规操作&#xff1a;操作dom “dom元素.focus()” 获取dom元素还要用ref 和 $refs <input ref"inp" type&quo…

报错 No available slot found for the embedding model

报错内容 Server error: 503 - [address0.0.0.0:12781, pid304366] No available slot found for the embedding model. We recommend to launch the embedding model first, and then launch the LLM models. 目前GPU占用情况如下 解决办法: 关闭大模型, 先把 embedding mode…

Maven 构建项目

Maven 是一个项目管理和构建工具&#xff0c;主要用于 Java 项目。它简化了项目的构建、依赖管理、报告生成、发布等一系列工作。 构建自动化&#xff1a;Maven 提供了一套标准化的构建生命周期&#xff0c;包括编译、测试、打包、部署等步骤&#xff0c;通过简单的命令就可以执…

【C++笔记】C++三大特性之多态

【C笔记】C三大特性之多态 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C笔记 文章目录 【C笔记】C三大特性之多态前言一.多态1.1 多态的概念1.2 虚函数1.3 虚函数的重写/覆盖1.4 多态的定义及实现 二.虚函数重写的⼀些其他问题2.1 协变(…

【项目实战】基于 LLaMA-Factory 通过 LoRA 微调 Qwen2

【项目实战】基于 LLaMAFactory 通过 LoRA 微调 Qwen2 一、项目介绍二、环境准备1、环境准备2、安装LLaMa-Factory3、准备模型数据集3.1 模型准备3.2 数据集准备 三、微调1、启动webui2、选择参数3、训练 四、测试五、总结 一、项目介绍 LLaMA-Factory是一个由北京航空航天大学…

内容占位符:Kinetic Loader HTML+CSS 使用CSS制作三角形原理

内容占位符 前言 随着我们对HTML和CSS3的学习逐渐深入&#xff0c;相信大家都已经掌握了网页制作的基础知识&#xff0c;包括如何使用HTML标记构建网页结构&#xff0c;以及如何运用CSS样式美化页面。为了进一步巩固和熟练这些技能&#xff0c;今天我们一起来完成一个有趣且实…

SpringSecurity 鉴权认证入门讲解

​ Spring Security 是 Spring 家族中的一个安全管理框架。相比与另外一个安全框架Shiro&#xff0c;它提供了更丰富的功能&#xff0c;社区资源也比Shiro丰富。 ​ 一般来说中大型的项目都是使用SpringSecurity 来做安全框架。小项目有Shiro的比较多&#xff0c;因为相比与Sp…