强制LUNA宿主工程使用中文路径的方法(附Python工具)

ZhaoYu

侦察机
KONTAKT VIP
配乐人星公民
初级 VIP
正式用户
🧱星陨矿
31,648
🧊星能体
172
🍀星灵素
0
🏵️星元核
0
Luna宿主的工程文件路径目前不支持中文,存放在中文路径下打开会报错,然后研究了一下找到了解决办法,用的是目录链接

实际上之前这个帖子【https://flying-daw.com/threads/1889/】的方法应该也是可以用的,我另外做了个python工具,操作起来会更快捷一些

做了个说明的视频:

代码全文:
Python:
import os
import subprocess
from tkinter import *
from tkinter import filedialog, messagebox
from tkinterdnd2 import DND_FILES, TkinterDnD


def normalize_path(path: str) -> str:
    """统一路径格式为反斜杠"""
    path = path.strip().strip('"').replace("/", "\\")
    return os.path.normpath(path)


def enable_indexing(path: str):
    """解除禁止索引属性,让程序可读写内容"""
    try:
        subprocess.run(f'attrib -I "{path}"', shell=True)
    except Exception as e:
        messagebox.showwarning("警告", f"索引属性设置失败:{e}")


def is_subpath(parent: str, child: str) -> bool:
    """判断 child 是否位于 parent 内部(跨盘符安全)"""
    parent = normalize_path(parent)
    child = normalize_path(child)

    # 如果盘符不同,必定不可能是子路径
    if os.path.splitdrive(parent)[0].lower() != os.path.splitdrive(child)[0].lower():
        return False

    # 同盘符情况下再比较路径层级
    try:
        return os.path.commonpath([parent]) == os.path.commonpath([parent, child])
    except ValueError:
        return False


def create_junction(start_dir: str, target_dir: str, link_name: str) -> bool:
    """在起点目录中创建目录联接(junction)"""
    start_dir = normalize_path(start_dir)
    target_dir = normalize_path(target_dir)

    # 基础检查
    if not os.path.isdir(start_dir):
        messagebox.showerror("错误", f"链接起点不存在或不是文件夹:\n{start_dir}")
        return False

    if not os.path.isdir(target_dir):
        messagebox.showerror("错误", f"链接终点不存在或不是文件夹:\n{target_dir}")
        return False

    # 安全检查 1:起点和终点不能相同
    if start_dir == target_dir:
        messagebox.showerror("错误", "链接起点和终点不能是同一个文件夹。")
        return False

    # 安全检查 2:终点不能位于起点内部
    if is_subpath(start_dir, target_dir):
        messagebox.showerror("错误", "终点文件夹不能位于起点文件夹内部,否则会造成循环引用。")
        return False

    # 安全检查 3:起点不能位于终点内部
    if is_subpath(target_dir, start_dir):
        messagebox.showerror("错误", "起点文件夹不能位于终点文件夹内部,否则会造成循环引用。")
        return False

    # 生成联接路径
    link_path = normalize_path(os.path.join(start_dir, link_name))

    # 安全检查 4:起点目录中不能已有同名文件夹
    if os.path.exists(link_path):
        messagebox.showwarning("提示", f"链接起点中已存在同名路径:\n{link_path}")
        return False

    # 创建联接
    cmd = f'chcp 65001 & mklink /J "{link_path}" "{target_dir}"'
    completed = subprocess.run(
        cmd,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True,
        shell=True
    )

    if completed.returncode != 0:
        messagebox.showerror(
            "错误",
            f"创建目录联接失败:\n{completed.stderr}\n\n"
            f"请确认路径合法且当前用户有权限在起点目录中创建链接。"
        )
        return False

    # 自动解除索引限制
    enable_indexing(link_path)

    messagebox.showinfo(
        "创建成功",
        f"已创建目录联接:\n{link_path}\n\n"
        f"该目录实际指向:\n{target_dir}\n\n"
        f"索引访问已自动启用,可正常读写。"
    )
    return True


def choose_start_folder():
    folder = filedialog.askdirectory(title="选择链接起点文件夹(软件识别路径)")
    if folder:
        start_var.set(folder)


def choose_target_folder():
    folder = filedialog.askdirectory(title="选择链接终点文件夹(实际存放路径)")
    if folder:
        target_var.set(folder)
        auto_fill_link_name(folder)


def drop_start(event):
    path = event.data.strip("{}")
    if os.path.isdir(path):
        start_var.set(path)
    else:
        messagebox.showerror("错误", "拖拽的不是文件夹。")


def drop_target(event):
    path = event.data.strip("{}")
    if os.path.isdir(path):
        target_var.set(path)
        auto_fill_link_name(path)
    else:
        messagebox.showerror("错误", "拖拽的不是文件夹。")


def auto_fill_link_name(path: str):
    """自动填入终点文件夹名称作为链接名称"""
    folder_name = os.path.basename(normalize_path(path))
    link_name_var.set(folder_name)


def on_create_link():
    start_dir = start_var.get().strip()
    target_dir = target_var.get().strip()
    link_name = link_name_var.get().strip()

    if not start_dir:
        messagebox.showerror("错误", "请先选择链接起点文件夹(软件识别路径)。")
        return
    if not target_dir:
        messagebox.showerror("错误", "请先选择链接终点文件夹(实际存放路径)。")
        return
    if not link_name:
        messagebox.showerror("错误", "链接名称不能为空。")
        return

    create_junction(start_dir, target_dir, link_name)


# ---------------- GUI ----------------
root = TkinterDnD.Tk()
root.title("路径联接桥 (Junction Bridge)")
root.geometry("760x360")
root.configure(bg="#f4f4f4")
root.resizable(False, False)

# 顶部标题区
title_frame = Frame(root, bg="#f4f4f4")
title_frame.pack(pady=(18, 8), fill="x")

Label(
    title_frame,
    text="路径联接桥 (Junction Bridge)",
    font=("Microsoft YaHei", 20, "bold"),
    bg="#f4f4f4",
    fg="#222"
).pack(anchor="w", padx=30)

Label(
    title_frame,
    text="在原路径下创建目录联接,让数据实际存放在其他路径",
    font=("Microsoft YaHei", 11),
    bg="#f4f4f4",
    fg="#666"
).pack(anchor="w", padx=30)

# 主内容区(统一左对齐)
main_frame = Frame(root, bg="#f4f4f4")
main_frame.pack(fill="both", expand=True, padx=30, pady=(10, 15))

# 链接起点A
start_label = Label(
    main_frame,
    text="链接起点A(软件识别路径):",
    font=("Microsoft YaHei", 10),
    bg="#f4f4f4"
)
start_label.grid(row=0, column=0, sticky="w")

start_var = StringVar()
start_entry = Entry(main_frame, textvariable=start_var, width=52, font=("Microsoft YaHei", 10))
start_entry.grid(row=1, column=0, padx=(0, 8), pady=6, sticky="we")

start_entry.drop_target_register(DND_FILES)
start_entry.dnd_bind('<<Drop>>', drop_start)

start_btn = Button(main_frame, text="选择...", command=choose_start_folder, width=9)
start_btn.grid(row=1, column=1, pady=6, sticky="e")

# 链接终点B
target_label = Label(
    main_frame,
    text="链接终点B(实际存放路径):",
    font=("Microsoft YaHei", 10),
    bg="#f4f4f4"
)
target_label.grid(row=2, column=0, sticky="w", pady=(10, 0))

target_var = StringVar()
target_entry = Entry(main_frame, textvariable=target_var, width=52, font=("Microsoft YaHei", 10))
target_entry.grid(row=3, column=0, padx=(0, 8), pady=6, sticky="we")

target_entry.drop_target_register(DND_FILES)
target_entry.dnd_bind('<<Drop>>', drop_target)

target_btn = Button(main_frame, text="选择...", command=choose_target_folder, width=9)
target_btn.grid(row=3, column=1, pady=6, sticky="e")

# 链接名称 + 创建按钮同一行
name_label = Label(
    main_frame,
    text="链接名称(终点文件夹自动获取,可修改):",
    font=("Microsoft YaHei", 10),
    bg="#f4f4f4"
)
name_label.grid(row=4, column=0, sticky="w", pady=(12, 0))

link_name_var = StringVar()
link_name_entry = Entry(main_frame, textvariable=link_name_var, width=30, font=("Microsoft YaHei", 10))
link_name_entry.grid(row=5, column=0, padx=(0, 8), pady=6, sticky="w")

create_btn = Button(
    main_frame,
    text="创建目录联接",
    width=10,
    bg="#4CAF50",
    fg="white",
    font=("Microsoft YaHei", 11, "bold"),
    relief="raised",
    command=on_create_link
)
create_btn.grid(row=5, column=1, pady=6, sticky="e")

# 让第0列自适应拉伸,按钮列固定
main_frame.grid_columnconfigure(0, weight=1)
main_frame.grid_columnconfigure(1, weight=0)

root.mainloop()