5 Commits
v1.0.0 ... main

Author SHA1 Message Date
39fab2cb16 docs: 添加常见问题与解决方案文档
记录 v1.1.x 版本遇到的 bug 及解决方案:
1. Windows bat 换行符问题(LF → CRLF)
2. Windows bat 中文乱码问题(UTF-8 → GBK)
3. Python logger 作用域问题(UnboundLocalError)
4. 日志等级未按配置文件设置

包含:
- 问题描述
- 原因分析
- 解决方案
- 预防措施
- 开发环境配置建议
2026-03-20 18:11:46 +08:00
e1333ccb78 v1.1.2 修复:启动脚本使用 ANSI (GBK) 编码
修复问题:
- Windows CMD 默认使用 ANSI 编码(GBK)
- UTF-8 编码的 bat 文件在中文 Windows 上会显示乱码

修改内容:
- 启动监控.bat 转换为 GBK 编码
- 使用 chcp 936 设置代码页为简体中文
2026-03-20 18:04:32 +08:00
e3b36d958d v1.1.1 修复:UnboundLocalError logger 作用域问题
修复问题:
- main() 函数内 logger = setup_logging() 导致作用域错误
- 改用 _apply_log_config() 函数更新日志等级,不重新赋值 logger
2026-03-20 17:50:43 +08:00
3b6a5fe2a0 v1.1.0 修复:转换启动脚本为 Windows CRLF 换行符 2026-03-20 17:18:53 +08:00
f4569093d7 v1.1.0 修复:启动脚本和日志等级配置
修复问题:
1. 启动监控.bat 添加窗口设置(title/mode/color),修复 Windows 换行符问题
2. 日志等级现在按配置文件 [logging] level 设置
3. 移除启动脚本的 Python 依赖自动安装功能

优化:
- 启动脚本初始化时设置窗口标题、大小和颜色
- 日志配置支持从配置文件动态读取等级
2026-03-20 16:55:11 +08:00
3 changed files with 314 additions and 51 deletions

View File

@@ -0,0 +1,232 @@
# 常见问题与解决方案
本文档记录远程音量控制项目在开发和部署过程中遇到的常见问题及解决方案,避免重复踩坑。
---
## 📋 问题清单
### 1. Windows 启动脚本无法运行(换行符问题)
**问题描述:**
在 Windows 上双击运行 `启动监控.bat` 时,脚本无法执行或报错。
**原因:**
Linux/Unix 使用 LF (`\n`) 换行符Windows 使用 CRLF (`\r\n`) 换行符。Git 在 Linux 环境下编辑后保存的是 LF 格式。
**解决方案:**
```bash
# 转换换行符为 CRLF
cd scripts/
sed -i 's/$/\r/' 启动监控.bat
# 验证
file 启动监控.bat
# 输出应包含with CRLF line terminators
```
**预防措施:**
-`.gitattributes` 中配置:`*.bat text eol=crlf`
- 使用支持跨平台换行符的编辑器VSCode、Notepad++
---
### 2. Windows 启动脚本中文乱码(编码问题)
**问题描述:**
在中文 Windows 上运行 `启动监控.bat` 时,中文显示为乱码。
**原因:**
Windows CMD 默认使用 ANSI 编码(中文系统为 GBK而脚本保存为 UTF-8 编码。
**解决方案:**
```bash
# 方法 1使用 Python 转换编码
python3 -c "
with open('启动监控.bat', 'r', encoding='utf-8') as f:
text = f.read()
with open('启动监控.bat', 'wb') as f:
f.write(text.encode('gbk'))
"
# 方法 2使用 iconv
iconv -f UTF-8 -t GBK 启动监控.bat > 启动监控.bat.tmp && mv 启动监控.bat.tmp 启动监控.bat
# 设置代码页为简体中文
# 在 bat 文件开头添加chcp 936 >nul
```
**bat 文件头部配置:**
```batch
@echo off
chcp 936 >nul ← 简体中文代码页
title 远程连接音量自动调节器
...
```
**预防措施:**
- Windows bat 脚本使用 ANSI (GBK) 编码保存
- 在文档中明确标注编码要求
---
### 3. Python UnboundLocalError: cannot access local variable 'logger'
**问题描述:**
运行程序时报错:
```
UnboundLocalError: cannot access local variable 'logger' where it is not associated with a value
```
**原因:**
`main()` 函数内部使用 `logger = setup_logging()` 重新赋值,导致 `logger` 变成局部变量,后续使用时作用域冲突。
**错误代码示例:**
```python
logger = setup_logging() # 全局 logger
def main():
logger = setup_logging(config_path) # ❌ 这让 logger 变成局部变量
logger.info(...) # UnboundLocalError!
```
**解决方案:**
```python
logger = setup_logging() # 全局 logger
def _apply_log_config(config_path):
"""更新日志等级,不重新赋值 logger"""
...
logger.setLevel(log_level) # 直接修改全局 logger
def main():
_apply_log_config(config_path) # ✅ 不重新赋值
logger.info(...) # 正常工作
```
**预防措施:**
- 避免在函数内部重新赋值全局 logger 变量
- 使用 `logger.setLevel()` 修改日志等级,而不是重新创建 logger
- 如必须重新赋值,使用 `global logger` 声明
---
### 4. 日志等级未按配置文件设置
**问题描述:**
配置文件中设置了 `level = DEBUG`,但日志仍然只显示 INFO 及以上级别。
**原因:**
程序启动时初始化了日志配置,但加载配置文件后没有应用配置文件中的日志等级。
**解决方案:**
```python
def setup_logging(config_path=None):
"""根据配置文件设置日志等级"""
log_level = logging.INFO # 默认等级
# 从配置文件读取日志等级
if config_path and Path(config_path).exists():
config = configparser.ConfigParser()
config.read(config_path, encoding='utf-8')
if 'logging' in config and 'level' in config['logging']:
level_str = config['logging']['level'].upper()
log_level = getattr(logging, level_str, logging.INFO)
logging.basicConfig(level=log_level, ...)
return logging.getLogger(__name__)
def _apply_log_config(config_path):
"""应用配置文件中的日志等级"""
config = configparser.ConfigParser()
config.read(config_path, encoding='utf-8')
level_str = config['logging']['level'].upper()
logger.setLevel(getattr(logging, level_str, logging.INFO))
```
**配置文件示例:**
```ini
[logging]
level = INFO
log_file = remote_volume.log
```
---
## 🛠️ 开发环境配置建议
### Git 配置
```bash
# 全局配置换行符Windows 用户)
git config --global core.autocrlf true
# 全局配置换行符Linux/Mac 用户)
git config --global core.autocrlf input
# 项目级配置(推荐)
# 在项目根目录创建 .gitattributes
echo "*.bat text eol=crlf" >> .gitattributes
echo "*.cmd text eol=crlf" >> .gitattributes
echo "*.ps1 text eol=lf" >> .gitattributes
echo "*.py text eol=lf" >> .gitattributes
```
### 编辑器配置
**VSCode 设置:**
```json
{
"files.eol": "\n",
"files.encoding": "utf8",
"[batch]": {
"files.encoding": "gbk",
"files.eol": "\r\n"
}
}
```
**Notepad++ 设置:**
- 菜单 → 编码 → 选择 ANSI针对 bat 文件)
- 菜单 → 编辑 → EOL 转换 → 转换为 Windows 格式CRLF
---
## 📚 版本修复记录
| 版本 | 修复内容 | 日期 |
|------|---------|------|
| v1.1.0 | 启动脚本添加窗口设置,移除依赖自动安装 | 2026-03-20 |
| v1.1.1 | 修复 logger 作用域 UnboundLocalError | 2026-03-20 |
| v1.1.2 | 修复 bat 文件中文乱码UTF-8 → GBK | 2026-03-20 |
---
## 🔍 排查步骤
遇到类似问题时的排查流程:
1. **检查文件编码**
```bash
file 文件名.bat
# 或
chardet 文件名.bat
```
2. **检查换行符**
```bash
file 文件名.bat
# 查看是否包含with CRLF line terminators
```
3. **检查 Python 作用域**
- 搜索函数内是否有 `logger =` 赋值
- 检查是否缺少 `global logger` 声明
4. **检查日志配置**
- 确认配置文件路径正确
- 确认 `[logging] level` 格式正确
---
*最后更新2026-03-20*

View File

@@ -1,39 +1,29 @@
@echo off
chcp 65001 >nul
title 远程连接音量自动调节器 -By:LeeQwQ
mode con cols=65 lines=18
color 0B
chcp 936 >nul
cls
echo ========================================
echo 远程连接音量自动调节器
echo 远程连接音量自动调节器
echo Remote Volume Monitor
echo ========================================
echo.
REM 检查 Python
REM 检查 Python
python --version >nul 2>&1
if errorlevel 1 (
echo [错误] 未找到 Python请先安装 Python 3.8+
echo [错误] 未找到 Python请先安装 Python 3.8+
pause
exit /b 1
)
REM 检查依赖
echo [检查] 验证依赖库...
python -c "import pycaw" >nul 2>&1
if errorlevel 1 (
echo [安装] 正在安装依赖库...
pip install pycaw comtypes wmi
)
python -c "import wmi" >nul 2>&1
if errorlevel 1 (
echo [安装] 正在安装 WMI 库...
pip install wmi
)
echo.
echo [启动] 开始监控远程连接...
echo [提示] 按 Ctrl+C 停止监控
echo [启动] 开始监控远程连接...
echo [提示] 按 Ctrl+C 停止监控
echo.
REM 启动监控程序(从 scripts 目录调用 src 和 config
REM 启动监控程序(从 scripts 目录调用 src 和 config
python "%~dp0..\src\remote_volume_monitor.py" --config "%~dp0..\config\config.ini"
pause

View File

@@ -20,19 +20,54 @@ from pathlib import Path
# 日志配置
# ============================================================================
log_dir = Path('logs')
log_dir.mkdir(exist_ok=True)
log_file = log_dir / 'remote_volume.log'
def setup_logging(config_path=None):
"""根据配置文件设置日志等级"""
log_dir = Path('logs')
log_dir.mkdir(exist_ok=True)
log_file = log_dir / 'remote_volume.log'
logging.basicConfig(
level=logging.DEBUG,
# 默认日志等级
log_level = logging.INFO
# 从配置文件读取日志等级
if config_path and Path(config_path).exists():
try:
config = configparser.ConfigParser()
config.read(config_path, encoding='utf-8')
if 'logging' in config and 'level' in config['logging']:
level_str = config['logging']['level'].upper()
log_level = getattr(logging, level_str, logging.INFO)
except Exception as e:
pass # 读取失败使用默认等级
# 配置日志
logging.basicConfig(
level=log_level,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(log_file, encoding='utf-8'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
)
return logging.getLogger(__name__)
def _apply_log_config(config_path):
"""根据配置文件更新日志等级(不重新创建 logger"""
if not Path(config_path).exists():
return
try:
config = configparser.ConfigParser()
config.read(config_path, encoding='utf-8')
if 'logging' in config and 'level' in config['logging']:
level_str = config['logging']['level'].upper()
log_level = getattr(logging, level_str, logging.INFO)
logger.setLevel(log_level)
logger.info(f"📝 日志等级:{level_str}")
except Exception as e:
pass # 读取失败保持当前等级
logger = setup_logging()
# ============================================================================
@@ -534,6 +569,7 @@ def main():
return
config = configparser.ConfigParser()
config_path = None
if args.config:
config_path = Path(args.config)
if not config_path.exists():
@@ -541,11 +577,16 @@ def main():
sys.exit(1)
config.read(config_path, encoding='utf-8')
logger.info(f"✓ 已加载:{config_path}")
# 重新配置日志等级(使用配置文件中的日志等级)
_apply_log_config(str(config_path))
else:
default_config = Path(__file__).parent.parent / 'config' / 'config.ini'
if default_config.exists():
config.read(default_config, encoding='utf-8')
logger.info(f"✓ 已加载默认:{default_config}")
config_path = str(default_config)
# 重新配置日志等级(使用配置文件中的日志等级)
_apply_log_config(config_path)
else:
config['volume'] = {'remote_volume': str(args.volume)}