
Luna宿主的工程文件路径目前不支持中文,存放在中文路径下打开会报错,然后研究了一下找到了解决办法,用的是目录链接
实际上之前这个帖子【https://flying-daw.com/threads/1889/】的方法应该也是可以用的,我另外做了个python工具,操作起来会更快捷一些
做了个说明的视频:
代码全文:
实际上之前这个帖子【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()
