欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

操作失败: 'gbk' codec can't decode byte 0xbf in position 2: ilegal multibyte sequence deepseek chatgpt 有大用

自己亲自做的代码,见    /node-admin/22695

#!/usr/bin/python3 import os import ctypes import tkinter as tk from tkinter import messagebox def add_hosts_entries():    # 定义要添加的hosts条目    new_entries = [        "192.168.1.100 mmmm.aaa.com",        "192.168.1.101 wwww3aaa.com",        "192.168.1.102 mmmmm.aaa.com",        "192.168.1.103 nnnnnn.aaa.com",        "192.168.1.104 r.aaa3static.com.com"    ]    # 获取hosts文件路径    hosts_path = r"C:\Windows\System32\drivers\etc\hosts"    try:        # 检查管理员权限        if not ctypes.windll.shell32.IsUserAnAdmin():            messagebox.showerror("权限错误", "请以管理员身份运行此程序")            return 0        # 检查条目是否已存在        existing_entries = set()        if os.path.exists(hosts_path):            with open(hosts_path, 'r') as f:                for line in f:                    line = line.strip()                    if line and not line.startswith('#'):                        existing_entries.add(line.split('#')[0].strip())        # 添加新条目(跳过已存在的)        added = -1        with open(hosts_path, 'a') as f:            for entry in new_entries:                if entry not in existing_entries:                    f.write("\n" + entry)                    added = 1        return added    except Exception as e:        messagebox.showerror("错误", f"操作失败: {str(e)}")        return False if __name__ == "__main__":    # 隐藏主Tkinter窗口    root = tk.Tk()    root.withdraw()    # 执行添加操作    result = add_hosts_entries()    # 显示结果弹窗    if result == 1:        messagebox.showinfo("完成", "hosts文件更新成功!")    elif result == 0:        messagebox.showinfo("完成", "未更改hosts文件(无权限)!")    elif result == -1:        messagebox.showinfo("完成", "未修改hosts文件(条目已存在)")    # 其他错误情况已在函数内处理 操作失败: 'gbk' codec can't decode byte 0xbf in position 2: ilegal multibyte sequence


您的代码在PyCharm中运行时遇到的错误是由于文件编码问题导致的。错误信息 'gbk' codec can't decode byte 0xbf 表明Python在尝试用GBK编码读取文件时遇到了非法字节序列。这通常发生在读取非GBK编码的文件时。


以下是修复后的完整代码:( 下面的代码并不完美 ,因为未考虑到hosts文件是GBK编码的情况 )

python                
#!/usr/bin/python3
import os
import ctypes
import tkinter as tk
from tkinter import messagebox

def add_hosts_entries():
    # 定义要添加的hosts条目
    new_entries = [
        "192.168.1.100 mmmm.aaa.com",
        "192.168.1.101 wwww3aaa.com",
        "192.168.1.102 mmmmm.aaa.com",
        "192.168.1.103 nnnnnn.aaa.com",
        "192.168.1.104 r.aaa3static.com.com"
    ]

    # 获取hosts文件路径
    hosts_path = r"C:\Windows\System32\drivers\etc\hosts"

    try:
        # 检查管理员权限
        if not ctypes.windll.shell32.IsUserAnAdmin():
            messagebox.showerror("权限错误", "请以管理员身份运行此程序")
            return 0

        # 检查条目是否已存在
        existing_entries = set()
        if os.path.exists(hosts_path):
            # 使用UTF-8编码打开文件
            with open(hosts_path, 'r', encoding='utf-8') as f:
                for line in f:
                    line = line.strip()
                    if line and not line.startswith('#'):
                        # 去除行内注释
                        clean_line = line.split('#')[0].strip()
                        existing_entries.add(clean_line)

        # 添加新条目(跳过已存在的)
        added = -1
        # 使用UTF-8编码追加写入
        with open(hosts_path, 'a', encoding='utf-8') as f:
            for entry in new_entries:
                if entry not in existing_entries:
                    f.write("\n" + entry)
                    added = 1

        return added

    except Exception as e:
        messagebox.showerror("错误", f"操作失败: {str(e)}")
        return False


if __name__ == "__main__":
    # 隐藏主Tkinter窗口
    root = tk.Tk()
    root.withdraw()

    # 执行添加操作
    result = add_hosts_entries()

    # 显示结果弹窗
    if result == 1:
        messagebox.showinfo("完成", "hosts文件更新成功!")
    elif result == 0:
        messagebox.showinfo("完成", "未更改hosts文件(无权限)!")
    elif result == -1:
        messagebox.showinfo("完成", "未修改hosts文件(条目已存在)")
    # 其他错误情况已在函数内处理

主要修复:

  1. 指定文件编码

    python                        
    with open(hosts_path, 'r', encoding='utf-8') as f:
    with open(hosts_path, 'a', encoding='utf-8') as f:
           

    明确使用UTF-8编码打开文件,避免GBK解码错误。

  2. 修复条目检查逻辑
    确保正确清理注释内容:

    python                        
    clean_line = line.split('#')[0].strip()
           

使用说明:

  1. 将此代码保存为.py文件

  2. 必须右键选择"以管理员身份运行",否则会提示权限错误

  3. 程序会自动执行添加操作,并根据结果弹出提示框

如果仍然遇到编码问题:

如果您的hosts文件使用的是其他编码(如ANSI),可以尝试以下替代方案:

python                
# 替代编码方案
try:
    with open(hosts_path, 'r', encoding='utf-8') as f:
        # 读取内容
except UnicodeDecodeError:
    # 如果UTF-8失败,尝试使用系统默认编码
    with open(hosts_path, 'r') as f:
        # 读取内容

或者更稳健的方式:

python                
# 自动检测编码
import chardet

def detect_encoding(file_path):
    with open(file_path, 'rb') as f:
        raw_data = f.read()
        result = chardet.detect(raw_data)
        return result['encoding'] or 'utf-8'

encoding = detect_encoding(hosts_path)
with open(hosts_path, 'r', encoding=encoding) as f:
    # 读取内容

但请注意,对于hosts文件,通常使用UTF-8或ANSI编码,直接使用UTF-8在大多数情况下都能正常工作。




Hosts 文件编辑器 - 增强版 (下面的代码更完美,考虑到 hosts 文件是utf-8和GBK)

下面是使用替代编码方案的完整实现代码,该代码可以智能处理不同编码的 hosts 文件,并提供更健壮的条目管理功能:

python                
#!/usr/bin/python3
import os
import ctypes
import tkinter as tk
from tkinter import messagebox, ttk, scrolledtext

def add_hosts_entries():
    # 定义要添加的hosts条目
    new_entries = [
        "192.168.1.100 mmmm.aaa.com",
        "192.168.1.101 wwww3aaa.com",
        "192.168.1.102 mmmmm.aaa.com",
        "192.168.1.103 nnnnnn.aaa.com",
        "192.168.1.104 r.aaa3static.com.com"
    ]

    # 获取hosts文件路径
    hosts_path = r"C:\Windows\System32\drivers\etc\hosts"
    result = {"added": 0, "skipped": 0, "errors": []}
    encoding_used = "utf-8"  # 默认使用UTF-8编码

    try:
        # 检查管理员权限
        if not ctypes.windll.shell32.IsUserAnAdmin():
            messagebox.showerror("权限错误", "请以管理员身份运行此程序")
            return {"status": "error", "message": "权限不足"}

        # 检查条目是否已存在
        existing_entries = set()
        file_content = []
        
        if os.path.exists(hosts_path):
            # 替代编码方案:先尝试UTF-8,失败则使用系统默认编码
            try:
                with open(hosts_path, 'r', encoding='utf-8') as f:
                    file_content = f.readlines()
                encoding_used = "utf-8"
            except UnicodeDecodeError:
                try:
                    with open(hosts_path, 'r') as f:  # 使用系统默认编码
                        file_content = f.readlines()
                    encoding_used = "system_default"
                except Exception as e:
                    result["errors"].append(f"读取文件失败: {str(e)}")
                    return result
            except Exception as e:
                result["errors"].append(f"读取文件失败: {str(e)}")
                return result
            
            # 处理每一行
            for line in file_content:
                line = line.strip()
                if line and not line.lstrip().startswith('#'):  # 忽略注释行
                    # 去除行内注释
                    clean_line = line.split('#')[0].strip()
                    # 规范化空格(将多个空格替换为单个空格)
                    normalized_line = ' '.join(clean_line.split())
                    existing_entries.add(normalized_line.lower())  # 不区分大小写

        # 添加新条目(跳过已存在的)
        entries_to_add = []
        for entry in new_entries:
            # 规范化条目
            normalized_entry = ' '.join(entry.split())
            if normalized_entry.lower() in existing_entries:
                result["skipped"] += 1
            else:
                entries_to_add.append(normalized_entry)
                result["added"] += 1
        
        # 如果有需要添加的条目
        if entries_to_add:
            try:
                # 使用确定的编码追加写入
                if encoding_used == "utf-8":
                    with open(hosts_path, 'a', encoding='utf-8') as f:
                        f.write("\n# Added by Hosts Editor\n")
                        for entry in entries_to_add:
                            f.write(entry + "\n")
                else:
                    with open(hosts_path, 'a') as f:  # 使用系统默认编码
                        f.write("\n# Added by Hosts Editor\n")
                        for entry in entries_to_add:
                            f.write(entry + "\n")
            except Exception as e:
                result["errors"].append(f"写入文件失败: {str(e)}")
        
        return result

    except Exception as e:
        result["errors"].append(f"操作失败: {str(e)}")
        return result

def show_hosts_file():
    hosts_path = r"C:\Windows\System32\drivers\etc\hosts"
    content = ""
    
    try:
        # 替代编码方案
        try:
            with open(hosts_path, 'r', encoding='utf-8') as f:
                content = f.read()
        except UnicodeDecodeError:
            with open(hosts_path, 'r') as f:  # 使用系统默认编码
                content = f.read()
        except Exception as e:
            content = f"读取文件失败: {str(e)}"
    except Exception:
        content = "无法读取hosts文件"
    
    # 创建查看窗口
    view_window = tk.Toplevel(root)
    view_window.title("Hosts 文件内容")
    view_window.geometry("600x400")
    
    # 添加滚动文本框
    text_area = scrolledtext.ScrolledText(view_window, wrap=tk.WORD)
    text_area.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
    text_area.insert(tk.INSERT, content)
    text_area.configure(state='disabled')  # 设置为只读
    
    # 添加关闭按钮
    close_btn = ttk.Button(view_window, text="关闭", command=view_window.destroy)
    close_btn.pack(pady=10)

def on_add_click():
    result = add_hosts_entries()
    
    if result.get("errors"):
        error_msg = "\n".join(result["errors"])
        messagebox.showerror("错误", f"操作过程中发生错误:\n{error_msg}")
    else:
        added = result.get("added", 0)
        skipped = result.get("skipped", 0)
        
        if added > 0:
            msg = f"成功添加 {added} 个条目"
            if skipped > 0:
                msg += f"\n跳过 {skipped} 个已存在的条目"
            messagebox.showinfo("成功", msg)
        else:
            if skipped > 0:
                messagebox.showinfo("完成", f"所有条目已存在,未进行更改")
            else:
                messagebox.showinfo("完成", "没有需要添加的条目")

# 创建主窗口
if __name__ == "__main__":
    root = tk.Tk()
    root.title("Hosts 文件编辑器")
    root.geometry("450x300")
    
    # 设置样式
    style = ttk.Style()
    style.configure("TButton", padding=6, font=('Arial', 10))
    style.configure("Header.TLabel", font=('Arial', 14, 'bold'))
    
    # 创建界面元素
    header = ttk.Label(root, text="Hosts 文件编辑器", style="Header.TLabel")
    header.pack(pady=20)
    
    info_label = ttk.Label(root, text="此工具用于添加华为相关服务的hosts条目", wraplength=400)
    info_label.pack(pady=10)
    
    # 按钮框架
    btn_frame = ttk.Frame(root)
    btn_frame.pack(pady=20)
    
    add_btn = ttk.Button(btn_frame, text="添加条目", command=on_add_click)
    add_btn.pack(side=tk.LEFT, padx=10)
    
    view_btn = ttk.Button(btn_frame, text="查看Hosts文件", command=show_hosts_file)
    view_btn.pack(side=tk.LEFT, padx=10)
    
    # 状态栏
    status_bar = ttk.Label(root, text="请以管理员身份运行此程序", relief=tk.SUNKEN, anchor=tk.W)
    status_bar.pack(side=tk.BOTTOM, fill=tk.X)
    
    # 检查管理员权限
    try:
        is_admin = ctypes.windll.shell32.IsUserAnAdmin()
        if is_admin:
            status_bar.config(text="管理员权限已获取 - 可以修改hosts文件")
        else:
            status_bar.config(text="警告:未以管理员身份运行 - 可能无法修改hosts文件")
    except:
        status_bar.config(text="无法确定管理员权限状态")
    
    root.mainloop()

代码详解

1. 增强的编码处理方案

python                
# 替代编码方案
try:
    with open(hosts_path, 'r', encoding='utf-8') as f:
        file_content = f.readlines()
    encoding_used = "utf-8"
except UnicodeDecodeError:
    try:
        with open(hosts_path, 'r') as f:  # 使用系统默认编码
            file_content = f.readlines()
        encoding_used = "system_default"
    except Exception as e:
        # 错误处理

这个方案首先尝试使用 UTF-8 编码打开文件,如果失败(遇到编码错误),则回退到系统默认编码。这样可以处理大多数中文 Windows 系统中的 hosts 文件。

2. 条目处理增强

python                
# 处理每一行
for line in file_content:
    line = line.strip()
    if line and not line.lstrip().startswith('#'):  # 忽略注释行
        # 去除行内注释
        clean_line = line.split('#')[0].strip()
        # 规范化空格(将多个空格替换为单个空格)
        normalized_line = ' '.join(clean_line.split())
        existing_entries.add(normalized_line.lower())  # 不区分大小写

这里做了三个关键改进:

  1. 使用 lstrip() 确保正确识别以空格开头的注释行

  2. 使用 ' '.join(clean_line.split()) 规范化空格,避免因空格数量不同导致的误判

  3. 使用 lower() 进行大小写不敏感的匹配

3. 用户界面增强

程序包含以下界面元素:

  • 添加条目按钮:执行添加操作

  • 查看Hosts文件按钮:在新窗口中显示当前hosts文件内容

  • 状态栏:显示管理员权限状态

  • 响应式布局:使用 ttk 主题控件,更美观

4. 更详细的执行结果反馈

python                
result = {"added": 0, "skipped": 0, "errors": []}

# 在操作过程中更新结果
if normalized_entry.lower() in existing_entries:
    result["skipped"] += 1
else:
    entries_to_add.append(normalized_entry)
    result["added"] += 1

这种结构可以记录添加了多少条目、跳过了多少条目,以及遇到的任何错误,为用户提供更详细的反馈。

5. 文件查看功能

python                
def show_hosts_file():
    # ...读取文件内容...
    # 创建查看窗口
    view_window = tk.Toplevel(root)
    # 添加滚动文本框显示内容

这个功能允许用户在不离开程序的情况下查看当前 hosts 文件内容,方便验证修改结果。

使用说明

  1. 保存:将代码保存为 hosts_editor.py

  2. 运行:右键选择"以管理员身份运行"

  3. 界面

  • 点击"添加条目"添加预定义的华为服务条目

  • 点击"查看Hosts文件"查看当前hosts内容

  • 状态栏显示当前权限状态

  • 结果

    • 成功添加会显示添加数量

    • 条目已存在会显示跳过数量

    • 错误会显示详细错误信息

    这个增强版解决了编码问题,提供了更友好的界面,并增强了错误处理和用户反馈功能。



    普通分类: