【VS2019】【PyQt】 Warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。(附自己写的Python脚本完成文件编码批量转换)

本文介绍了在VS2019中遇到的编码问题,特别是C4819警告,以及如何通过Python脚本批量转换文件编码。作者指出,VS2019新建文件默认编码为GB2312,导致与QtCreator配合时出现编码混乱。文章提供了一个Python脚本,用于将文件转换为UTF-8-BOM或其他编码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【内容更新】

刚刚发现了大佬的做法 记visual studio2019中文乱码解决,在此啪啪啪地打自己脸。大佬的解决方法可以说是非常的舒服了,打脸打的心服口服。
博客的旧内容(扇脸)就不改了,感兴趣的可以看看下面的打脸内容,或者直接拉到文尾试用一下Python脚本。正常来说这脚本应该不会跑飞的,跑出意外的话多半是chardet.detect()判断编码出错导致转码失败。
疯狂打脸
虽然在VS2019里头添加新文件,其编码仍然为ANSI(也就是GB2312),不是utf-8,但这个问题可以去 扩展→管理扩展安装插件去解决。安装这个插件可能会出现这个问题 VS2019插件“Force UTF-8(No Bom)”造成输出乱码,这个我目前没啥好的解决方法,我在代码中加入简单粗暴的一句 system(“chcp 65001”) 修改程序当前代码页让程序不输出乱码。


我这里就不放出“有问题请留言”之类的话了,因为我也不是别人有提问就一定会去帮忙的大善人,而且万一别人的问题我还解决不了的话那就更打脸,所以想留言就留吧虽然我不一定会回。






这个问题,影响了我很长一段时间,很恶心很恶心,我用我那贫瘠的知识去分析,去想,去思考,这“当前代码页(936)”到底是个什么东西,到底在哪,为什么改不掉,为什么就不能让我选择代码页,我甚至在项目的属性页里头去设置了可能有用的东西,但还是不顶用,大半天在下饭都快把我自己给喂的撑死

项目属性配置尝试修改代码页修改失败






网上很多的垃圾办法是,在VS2019去设置 “高级保存选项” 去修改源文件的编码(而且十个至少六个是这种解决方法就非常的让人烦躁),说是垃圾办法,是因为这完全就治标不治本。
我当前情况是在VS2019撸码撸函数,然后把文件拖进QtCreator去跑去看实际运行结果。有时就会来个编码不正确的问题,一两次还好说,经常这样就很烦的了。
QtCreator编码错误
这就只能去改文件编码,那就去改吧,一个一个地全改成UTF-8-BOM(不改成utf-8是因为VS2019小天才在编译过程中并不能识别这份编码)。敲代码敲着敲着,感觉需要弄多几个类,于是在VS2019里头添加了新的文件。你猜猜那些新文件的编码是什么?没错,是GB2312,中文编码,厉害吧,(下面截图中的ANSI为系统编码,我也不太好说这就是中文编码,但至少它并不是utf-8编码)。
这就直接造成了项目文件的编码混乱:你的一个项目里,使用的编码至少有utf-8、UTF-8-BOM、GB2312,而GB2312编码的文件拖进QtCreator时会不识别要重新选合适的编码(上面那张图就是QtCreator不识别了)

VS2019添加新文件
NotePad++查看文件编码





扯的天南地北,回到标题。这里讨论下为什么会出现这个烦人到极致的C4819:
Windows的软件分为两类,一类是Unicode的,另一类是非Unicode的(这个说法是从别的地方看到的,但标签已经关了,也懒得去翻,就不标明出处了)
个人观点是VS2019是非Unicode软件,程序运行时采用的代码页已经锁死在936上了,这想改也不好改,因为这是和系统设置关联的。反复咀嚼官方给出的C4819的解决方法,直接得出结论:如果你的文件,编码是utf-8,那趁早改成别的编码,或者改用VSCode,因为VS2019不识别utf-8的文件。
修改区域设置
或者用别的说法:如果你有一份文件,里头用了阿拉伯语西班牙语之类的奇奇怪怪的语言,那么这份文件也只能在相对应的编码中才能正确识别,否则只会是乱码,所以这个文件如果直接拖进VS2019,那么势必是乱码的。那么,要是参考上图官方给出的做法,把“区域设置”的“中文”改成阿拉伯语之类的语言,那么会怎么样呢?这我没去尝试(改这东西有可能会翻车不敢乱动,顺便一说下面的Beta别去选,那是比鸡肋还鸡肋的无用之物),但猜测改了那个系统设置之后VS2019能够识别那份文件,也猜测VS2019的代码页从936 “成功” 改成了其他的值。为什么强调是“成功”呢? 因为这个代码页不是你自由选择的,是由系统设置决定的,而且最关键的是,你不能让它选为65001(utf-8编码) ,也就是这厮注定是识别不了utf-8编码的文件,或许有插件可以?没怎么了解过,所以才说自己知识贫瘠。





于是自己花了一天的时间去写了个py脚本(大部分时间花在了QT界面上),在需要的时候把文件编码批量转成UTF-8-BOM或者其他编码。虽然不怎么想把自己一天的劳动成果就这么放在博客上,但还是放上去好了,毕竟也参考过不少陌生人的博客、知乎。下面的Python脚本不出意外是可以正常执行的(需要Qt库,自己去装吧)

代码量很大,耦合度还算可以,设计了三个控件类一个主窗口类。
控件类可以直接使用,可以直接拖到有需要的地方(虽然封装的不怎么样)。XJ_TreeView(树视图)的话我觉得我写的还可以(蜜汁自信?),使用起来也比较方便,至少使用过程中不再去关心内容添加修改的细节了(只完成了少量功能,但对我来说够用了)。另外两个控件类就随便写写的,主要是为了减轻主窗口类的负担,让主窗口类的内部的逻辑清晰一点(但实际上还是很乱,至少变量名取的乱七八糟让人烦躁)。
主窗口类的内部耦合度可以说是很高很高的了,夹杂着的东西乱到让人怀疑人生,反正我已经完全不想去动这个类了。想从主窗口类里头剥离出单独的功能可以说不现实,像是想学习“py转换编码”、“文件读取保存”、“盒布局”的话还不如直接去查。
我也不认为有人会有耐心把我的代码仔细分析完。脚本代码量350左右,而我平时看别人博客超过二三十行代码我就没心情去翻

py脚本运行结果

'''
【XJ自制脚本】
这个脚本花了一整天完成的。
因为VS2019和QtCreator来回拖文件而且文件编码还不一致,导致了每次运行前都要手动选择编码(否则就显示乱码)。
一次两次就算了,但反复提示重选编码。实在受不了,就花了一天时间去写这个东西。
运行效果个人感觉还行,能跑,作为以后常用的工具使用。
'''

import chardet
import sys
import os
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt,QModelIndex,QItemSelectionModel
from PyQt5.QtGui import QStandardItemModel, QStandardItem,QFont
from PyQt5.QtWidgets import *


class XJ_TreeView(QTreeView):
    class XJ_Iter:
        def __init__(self,iter):
            self.__iter=iter

        def AppendRow(self,data):#添加数据(一个列表
            lst=[]
            for i in data:
                lst.append(QStandardItem(str(i)))
                lst[-1].setEditable(False)
            self.__iter.appendRow(lst)
            return XJ_TreeView.XJ_Iter(lst[0])
        
        def Copy(self):
            return XJ_TreeView.XJ_Iter(self.__iter)
            
        def Back(self):#返回上一级(返回失败则返回false
            if(type(self.__iter)==QStandardItemModel):
                return False
            if(self.__iter.parent()==None):
                self.__iter=self.__iter.model()
            else:
                self.__iter=self.__iter.parent()
            return True
            
        def Next(self,i):#进入下一级(进入失败则返回false
            if(0<=i<self.__iter.rowCount()):
                if(type(self.__iter)!=QStandardItemModel):
                    self.__iter=self.__iter.child(i,0)
                else:
                    self.__iter=self.__iter.itemFromIndex(self.__iter.index(i,0))
                return True
            else:
                return False
                
        def GetData(self):#获取数据(一个列表
            if(type(self.__iter)==QStandardItemModel):
                return None
            result=[]
            model=self.__iter.model()
            index=self.__iter.index()
            i=0
            while(index.isValid()):
                result.append(model.itemFromIndex(index).text())
                i+=1
                index=index.siblingAtColumn(i)
            return result
            
        def SetData(self,i,data):#设置第i个单元格的内容(设置失败则返回false
            if(type(self.__iter)==QStandardItemModel):
                return False
            model=self.__iter.model()
            index=self.__iter.index().siblingAtColumn(i)
            if(index.isValid()==False):
                
<think>嗯,用户想要一个用PyQt5制作的Python打包成APK的程序,界面要类似auto-py-to-exe,但不使用它,而且所有基本功能都要有。首先,我需要理清楚用户的具体需求。 用户提到要仿照auto-py-to-exe的布局,所以可能需要一个标签页式的界面,把不同的配置选项分类展示。但PyQt5的布局设计可能需要用QTabWidget来实现分页。然后需要包含文件路径、保存路径、名称、图标这些放在界面前面,可能需要放在第一页或者显眼的位置。 接下来,基本功能都要加入。这里可能包括选择Python脚本、输出目录、程序名称、图标,还有生成APK的按钮。另外,用户可能还需要一些高级选项,比如控制台窗口的显示、打包成一个文件还是文件夹,添加文件等。不过用户没有明确说明是否需要这些高级功能,但提到“所有基本功能”,所以可能需要包括。 不过,Python打包成APK通常需要使用像BeeWare或Kivy这样的工具,而auto-py-to-exe是将Python打包成exe的,所以用户可能有些混淆。或者用户可能想要的是打包成Android应用,这时候需要确认是否使用Buildozer或者类似工具。这里可能需要进一步澄清,但用户可能希望用类似pyinstaller的方式,但目标是生成APK。不过实际上,Python打包APK通常需要其他工具链,比如Buildozer或Pyqtdeploy。 但用户可能并不了解这些,他们可能只是想要一个图形界面来配置打包参数,然后调用底层的命令行工具。比如,如果是用Buildozer的话,需要生成spec文件或执行buildozer命令。所以这个程序的核心功能可能是一个GUI前端,用于生成配置并执行打包命令。 接下来,需要考虑如何用PyQt5布局这些元素。可能需要QLineEdit用于路径输入,QPushButton触发文件选择对话框,QLabel作为说明。保存路径可能需要一个QFileDialog来选择目录。图标的话,可能需要选择图片文件,比如.png或.ico。 然后,如何处理打包逻辑。用户不使用auto-py-to-exe,所以需要自己实现打包逻辑。如果目标是APK,可能需要调用Buildozer或者其他工具的命令行。例如,生成一个buildozer.spec文件,然后运行buildozer android debug命令。这时候,GUI需要收集用户输入的参数,入spec文件,然后执行命令。 但用户可能对具体流程不太清楚,所以需要明确步骤。首先,用户需要安装Buildozer和依赖,比如Cython、Android SDK、NDK等。然后,GUI程序生成spec文件,并执行打包命令,可能需要在后台线程中运行,避免界面卡顿。 另外,界面布局方面,需要将常用的选项放在前面,比如主脚本、应用名称、包名、版本、图标、输出目录等。高级选项可以放在另一个标签页,比如权限、文件、依赖项等。 可能遇到的问题包括路径中包含空格或特殊字符,需要正确处理。另外,打包APK需要Android环境配置,用户可能没有正确安装,这时候程序需要给出提示或帮助配置。 总结下来,步骤大概是: 1. 设计PyQt5界面,分标签页,基础选项放在第一页。 2. 实现文件选择、目录选择的功能,用QFileDialog。 3. 收集用户输入的参数,生成配置文件(如buildozer.spec)。 4. 调用命令行工具执行打包,可能需要用subprocess模块。 5. 处理打包过程中的输出,显示进度或日志。 需要注意的是,直接使用Buildozer的话,用户需要预先安装并配置好环境,否则程序无法运行。此外,跨平台问题可能要考虑,比如在Windows下可能需要WSL或者额外的配置。 可能用户没有意识到打包APK比打包exe复杂得多,需要依赖Android SDK等,所以程序中可能需要包含环境检查的功能,或者给出提示信息。 最后,代码示例可能需要展示PyQt5的基本结构,文件选择,以及调用子进程执行命令的部分,比如点击按钮后运行buildozer命令。同时,需要注意在子线程中执行长时间任务,避免阻塞GUI线程。</think>以下是一个使用PyQt5实现Python脚本打包APK的GUI程序基础框架(需配合Buildozer等工具使用): ```python import sys import subprocess from PyQt5.QtWidgets import * from PyQt5.QtCore import QThread, pyqtSignal class PackagingThread(QThread): output_signal = pyqtSignal(str) def __init__(self, command): super().__init__() self.command = command def run(self): process = subprocess.Popen(self.command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) for line in iter(process.stdout.readline, ''): self.output_signal.emit(line.strip()) class MainWindow(QMainWindow): def __init__(self): super().__init__() self.initUI() self.setWindowTitle("Py2APK Converter") def initUI(self): # 主容器 main_widget = QWidget() self.setCentralWidget(main_widget) layout = QVBoxLayout(main_widget) # 标签页 tabs = QTabWidget() basic_tab = QWidget() self.setup_basic_tab(basic_tab) tabs.addTab(basic_tab, "基本配置") # 日志输出 self.log_output = QTextEdit() self.log_output.setReadOnly(True) layout.addWidget(tabs) layout.addWidget(self.log_output) def setup_basic_tab(self, tab): layout = QFormLayout(tab) # 主文件选择 self.main_file = QLineEdit() btn_main_file = QPushButton("浏览...") btn_main_file.clicked.connect(lambda: self.select_file("Python脚本 (*.py)", self.main_file)) file_layout = QHBoxLayout() file_layout.addWidget(self.main_file) file_layout.addWidget(btn_main_file) # 输出目录 self.output_dir = QLineEdit() btn_output_dir = QPushButton("浏览...") btn_output_dir.clicked.connect(lambda: self.select_directory(self.output_dir)) dir_layout = QHBoxLayout() dir_layout.addWidget(self.output_dir) dir_layout.addWidget(btn_output_dir) # 应用信息 self.app_name = QLineEdit("MyApp") self.package_name = QLineEdit("org.example.myapp") self.version = QLineEdit("0.1") self.icon_path = QLineEdit() btn_icon = QPushButton("浏览...") btn_icon.clicked.connect(lambda: self.select_file("图标文件 (*.png)", self.icon_path)) # 打包按钮 btn_build = QPushButton("开始打包") btn_build.clicked.connect(self.start_packaging) # 添加控件 layout.addRow("主脚本文件:", file_layout) layout.addRow("输出目录:", dir_layout) layout.addRow("应用名称:", self.app_name) layout.addRow("包名:", self.package_name) layout.addRow("版本:", self.version) layout.addRow("应用图标:", self.icon_path) layout.addRow(btn_icon) layout.addRow(btn_build) def select_file(self, file_type, target): path, _ = QFileDialog.getOpenFileName(self, "选择文件", "", file_type) if path: target.setText(path) def select_directory(self, target): path = QFileDialog.getExistingDirectory(self, "选择目录") if path: target.setText(path) def start_packaging(self): # 获取配置参数 config = { "main_file": self.main_file.text(), "output_dir": self.output_dir.text(), "app_name": self.app_name.text(), "package_name": self.package_name.text(), "version": self.version.text(), "icon": self.icon_path.text() } # 验证输入 if not all(config.values()): QMessageBox.warning(self, "错误", "所有必填项!") return # 生成buildozer命令(示例) build_cmd = [ "buildozer", "android", "debug", "deploy", "run" ] # 启动打包线程 self.thread = PackagingThread(build_cmd) self.thread.output_signal.connect(self.update_log) self.thread.start() def update_log(self, text): self.log_output.append(text) if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_()) ``` **使用说明:** 1. 需要先安装依赖: ```bash pip install pyqt5 buildozer ``` 2. 需要配置Android打包环境(需提前安装Android SDK/NDK) **功能说明:** - 仿auto-py-to-exe的界面布局 - 包含主文件选择、输出目录选择等核心功能 - 支持应用名称、包名、版本号等基础配置 - 支持图标文件选择(需符合Android要求) - 显示打包过程日志 - 使用独立线程执行打包任务避免界面卡顿 **扩展建议:** 1. 添加高级配置选项卡(权限设置、依赖项配置等) 2. 实现buildozer.spec文件的自动生成 3. 添加环境检查功能 4. 支持多平台打包配置 5. 增加进度条显示 6. 添加打包完成后的提示和输出目录打开功能 **注意事项:** - Android打包需要复杂的依赖环境,建议在Linux环境下操作 - 需要配置buildozer的依赖项(Android SDK/NDK等) - 实际打包命令需要根据buildozer规范进行调整 - 图标文件需要符合Android应用图标规范 建议在实际使用中结合buildozer的规范要求,将GUI收集的参数转换为对应的buildozer.spec配置,并处理打包过程中的异常情况。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值