1.6. 常见的源码文件编码方式及查看网页源码的编码方式
2.å¦ä½ç¨mavenå°java8åç代ç ç¼è¯ä¸ºjava6å¹³å°ç
3.easylogging源码学习笔记(6)
4.逆向pyinstaller打包的exe软件,获取python源码(6)
5.从源码构建并安装Qt6
6.Keil AC5 和 AC6的源码一些区别
6. 常见的文件编码方式及查看网页源码的编码方式
编码的起源可以追溯至早期的电报通信时代。为了解决电报线路带宽有限的源码难题,人们采用编码方式,源码将书写信息转换为二进制数字,源码通过电报线路传输。源码可爱猫java源码每个字符被转换为一个特定的源码二进制数。例如,源码大写字母A的源码二进制表示为(对应十进制)。这种二进制编码方式使得计算机能够识别和处理字符信息。源码随着互联网和全球化的源码不断发展,编码方式也变得更加复杂多样,源码以支持不同语言和字符集之间的源码输入、输出和处理。源码
计算机中最小的源码存储单位是字节。字节由8个比特(bit)组成,能表示的最大整数为(二进制)。若需要表示更大的整数,必须使用更多的字节。ASCII编码是早期的一种编码方式,使用7位二进制编码,能表示个字符。为了支持更多语言和字符,溯源码009Unicode编码应运而生,使用位二进制编码,能表示个字符,涵盖了世界上几乎所有语言的字符。UTF-8编码则是基于Unicode编码,采用变长编码方式,能够适应不同字符长度的需求。
编码的作用主要体现在以下几个方面:存储和传输、显示和打印、处理和计算以及支持国际化和多语言。编码使得字符能够被计算机识别、处理和传输,同时支持不同语言和字符集的输入和输出。Unicode编码的引入,让全球的文化、字符和符号得以统一支持,成为一种国际化的字符标准。UTF-8编码在互联网领域广泛应用,解决了不同语言字符长度不一的问题,成为网络传输的首选编码方式。
ASCII码、ISO--1、创建xml源码Unicode和UTF-8等编码方式,各有特点和适用场景。ASCII码是美国在年代制定的编码标准,使用单字节表示个字符。ISO--1是在ASCII编码基础上扩展的单字节字符集,适用于西欧语言等。Unicode编码提供了一个统一的字符集标准,UTF-8编码则采用变长技术,支持不同字符长度的字符表示。GB和GBK编码则专注于支持中文字符集,GB包含个汉字和个符号,GBK编码在此基础上扩展了更多汉字,共计个。ISO--1编码能与ASCII兼容,适用范围广泛,但在现代应用中,UTF-8成为更优选择。
了解和应用正确的编码方式对于正确显示、传输和处理字符至关重要。不同的文件类型和网页使用不同的编码方式,如TXT文件通常使用UTF-8编码,网页中的粉丝互助源码`charset`标签则直接指定了页面的字符编码。通过查看文件属性或网页源代码,可以轻松了解其编码方式,确保字符显示的准确性。
å¦ä½ç¨mavenå°java8åç代ç ç¼è¯ä¸ºjava6å¹³å°ç
ããå¨ä¸è¬çJavaåºç¨å¼åè¿ç¨ä¸ï¼å¼å人å使ç¨Javaçæ¹å¼æ¯è¾ç®åãæå¼æ¯ç¨çIDEï¼ç¼åJavaæºä»£ç ï¼åå©ç¨IDEæä¾çåè½ç´æ¥è¿è¡Java ç¨åºå°±å¯ä»¥äºãè¿ç§å¼å模å¼èåçè¿ç¨æ¯ï¼å¼å人åç¼åçæ¯Javaæºä»£ç æ件ï¼.javaï¼ï¼IDEä¼è´è´£è°ç¨Javaçç¼è¯å¨æJavaæºä»£ç ç¼è¯æå¹³å°æ å ³çåè代ç ï¼byte codeï¼ï¼ä»¥ç±»æ件çå½¢å¼ä¿åå¨ç£çä¸ï¼.classï¼ãJavaèææºï¼JVMï¼ä¼è´è´£æJavaåè代ç å 载并æ§è¡ãJavaéè¿è¿ç§æ¹å¼æ¥å®ç°å ¶âç¼åä¸æ¬¡ï¼å°å¤è¿è¡ï¼Write once, run anywhereï¼â çç®æ ãJavaç±»æ件ä¸å å«çåè代ç å¯ä»¥è¢«ä¸åå¹³å°ä¸çJVMæ使ç¨ãJavaåè代ç ä¸ä» å¯ä»¥ä»¥æ件形å¼åå¨äºç£çä¸ï¼ä¹å¯ä»¥éè¿ç½ç»æ¹å¼æ¥ä¸è½½ï¼è¿å¯ä»¥åªåå¨äºå åä¸ãJVMä¸çç±»å è½½å¨ä¼è´è´£ä»å å«åè代ç çåèæ°ç»ï¼byte[]ï¼ä¸å®ä¹åºJavaç±»ãå¨æäºæ åµä¸ï¼å¯è½ä¼éè¦å¨æççæ Javaåè代ç ï¼ææ¯å¯¹å·²æçJavaåè代ç è¿è¡ä¿®æ¹ãè¿ä¸ªæ¶åå°±éè¦ç¨å°æ¬æä¸å°è¦ä»ç»çç¸å ³ææ¯ãé¦å ä»ç»ä¸ä¸å¦ä½å¨æç¼è¯Javaæºæ件ã
ããå¨æç¼è¯Javaæºæ件
ããå¨ä¸è¬æ åµä¸ï¼å¼å人åé½æ¯å¨ç¨åºè¿è¡ä¹åå°±ç¼åå®æäºå ¨é¨çJavaæºä»£ç 并ä¸æåç¼è¯ã对æäºåºç¨æ¥è¯´ï¼Javaæºä»£ç çå 容å¨è¿è¡æ¶å»æè½ç¡®å®ãè¿ä¸ªæ¶åå°±éè¦å¨æç¼è¯æºä»£ç æ¥çæJavaåè代ç ï¼åç±JVMæ¥å è½½æ§è¡ãå ¸åçåºæ¯æ¯å¾å¤ç®æ³ç«èµçå¨çº¿è¯æµç³»ç»ï¼å¦PKU JudgeOnlineï¼ï¼å 许ç¨æ·ä¸ä¼ Java代ç ï¼ç±ç³»ç»å¨åå°ç¼è¯ãè¿è¡å¹¶è¿è¡å¤å®ãå¨å¨æç¼è¯Javaæºæ件æ¶ï¼ä½¿ç¨çåæ³æ¯ç´æ¥å¨ç¨åºä¸è°ç¨Javaç¼è¯å¨ã
ããJSR å¼å ¥äºJavaç¼è¯å¨APIãå¦æ使ç¨JDK 6çè¯ï¼å¯ä»¥éè¿æ¤APIæ¥å¨æç¼è¯Java代ç ãæ¯å¦ä¸é¢ç代ç ç¨æ¥å¨æç¼è¯æç®åçHello Worldç±»ã该Javaç±»ç代ç æ¯ä¿åå¨ä¸ä¸ªå符串ä¸çã
ãã public class CompilerTest {
ãã public static void main(String[] args) throws Exception {
ãã String source = "public class Main { public static void main(String[] args) { System.out.println(\"Hello World!\");} }";
ãã JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
ãã StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
ãã StringSourceJavaObject sourceObject = newCompilerTest.StringSourceJavaObject("Main", source);
ãã Iterable< extends JavaFileObject> fileObjects = Arrays.asList(sourceObject);
ãã CompilationTask task = compiler.getTask(null, fileManager, null,null, null, fileObjects);
ãã boolean result = task.call();
ãã if (result) {
ãã System.out.println("ç¼è¯æåã");
ãã }
ãã }
ãã
ãã static class StringSourceJavaObject extends SimpleJavaFileObject {
ãã
ãã private String content = null;
ãã public StringSourceJavaObject(String name, String content) ?throwsURISyntaxException {
ãã super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension), Kind.SOURCE);
ãã this.content = content;
ãã }
ãã
ãã public CharSequence getCharContent(boolean ignoreEncodingErrors) ?throws IOException {
ãã return content;
ãã }
ãã }
ãã }
ããå¦æä¸è½ä½¿ç¨JDK 6æä¾çJavaç¼è¯å¨APIçè¯ï¼å¯ä»¥ä½¿ç¨JDKä¸çå·¥å ·ç±»com.sun.tools.javac.Mainï¼ä¸è¿è¯¥å·¥å ·ç±»åªè½ç¼è¯åæ¾å¨ç£çä¸çæ件ï¼ç±»ä¼¼äºç´æ¥ä½¿ç¨javacå½ä»¤ã
ããå¦å¤ä¸ä¸ªå¯ç¨çå·¥å ·æ¯Eclipse JDT Coreæä¾çç¼è¯å¨ãè¿æ¯Eclipse Javaå¼åç¯å¢ä½¿ç¨çå¢éå¼Javaç¼è¯å¨ï¼æ¯æè¿è¡åè°è¯æé误ç代ç ã该ç¼è¯å¨ä¹å¯ä»¥åç¬ä½¿ç¨ãPlayæ¡æ¶å¨å é¨ä½¿ç¨äºJDTçç¼è¯å¨æ¥å¨æç¼è¯Javaæºä»£ç ãå¨å¼å模å¼ä¸ï¼Playæ¡æ¶ä¼å®ææ«æ项ç®ä¸çJavaæºä»£ç æ件ï¼ä¸æ¦åç°æä¿®æ¹ï¼ä¼èªå¨ç¼è¯ Javaæºä»£ç ãå æ¤å¨ä¿®æ¹ä»£ç ä¹åï¼å·æ°é¡µé¢å°±å¯ä»¥çå°ååã使ç¨è¿äºå¨æç¼è¯çæ¹å¼çæ¶åï¼éè¦ç¡®ä¿JDKä¸çtools.jarå¨åºç¨ç CLASSPATHä¸ã
ããä¸é¢ä»ç»ä¸ä¸ªä¾åï¼æ¯å ³äºå¦ä½å¨Javaéé¢åååè¿ç®ï¼æ¯å¦æ±åºæ¥(3+4)*7-çå¼ãä¸è¬çåæ³æ¯åæè¾å ¥çè¿ç®è¡¨è¾¾å¼ï¼èªå·±æ¥æ¨¡æ计ç®è¿ç¨ãèèå°æ¬å·çåå¨åè¿ç®ç¬¦çä¼å 级çé®é¢ï¼è¿æ ·ç计ç®è¿ç¨ä¼æ¯è¾å¤æï¼èä¸å®¹æåºéãå¦å¤ä¸ç§åæ³æ¯å¯ä»¥ç¨JSR å¼å ¥çèæ¬è¯è¨æ¯æï¼ç´æ¥æè¾å ¥ç表达å¼å½åJavaScriptææ¯JavaFXèæ¬æ¥æ§è¡ï¼å¾å°ç»æãä¸é¢ç代ç 使ç¨çåæ³æ¯å¨æçæJavaæºä»£ç 并ç¼è¯ï¼æ¥çå è½½Javaç±»æ¥æ§è¡å¹¶è·åç»æãè¿ç§åæ³å®å ¨ä½¿ç¨Javaæ¥å®ç°ã
ãã private static double calculate(String expr) throws CalculationException {
ãã String className = "CalculatorMain";
ãã String methodName = "calculate";
ãã String source = "public class " + className
ãã + " { public static double " + methodName + "() { return " + expr +"; } }";
ãã //çç¥å¨æç¼è¯Javaæºä»£ç çç¸å ³ä»£ç ï¼åè§ä¸ä¸è
ãã boolean result = task.call();
ãã if (result) {
ãã ClassLoader loader = Calculator.class.getClassLoader();
ãã try {
ãã Class<?> clazz = loader.loadClass(className);
ãã Method method = clazz.getMethod(methodName, new Class<?>[] { });
ãã Object value = method.invoke(null, new Object[] { });
ãã return (Double) value;
ãã } catch (Exception e) {
ãã throw new CalculationException("å é¨é误ã");
ãã }
ãã } else {
ãã throw new CalculationException("é误ç表达å¼ã");
ãã }
ãã }
ããä¸é¢ç代ç ç»åºäºä½¿ç¨å¨æçæçJavaåè代ç çåºæ¬æ¨¡å¼ï¼å³éè¿ç±»å è½½å¨æ¥å è½½åè代ç ï¼å建Javaç±»ç对象çå®ä¾ï¼åéè¿Javaåå°APIæ¥è°ç¨å¯¹è±¡ä¸çæ¹æ³ã
ããJavaåè代ç å¢å¼º
ããJava åè代ç å¢å¼ºæçæ¯å¨Javaåè代ç çæä¹åï¼å¯¹å ¶è¿è¡ä¿®æ¹ï¼å¢å¼ºå ¶åè½ãè¿ç§åæ³ç¸å½äºå¯¹åºç¨ç¨åºçäºè¿å¶æ件è¿è¡ä¿®æ¹ãå¨å¾å¤Javaæ¡æ¶ä¸é½å¯ä»¥è§å°è¿ç§å®ç°æ¹å¼ãJavaåè代ç å¢å¼ºé常ä¸Javaæºæ件ä¸ç注解ï¼annotationï¼ä¸å使ç¨ã注解å¨Javaæºä»£ç ä¸å£°æäºéè¦å¢å¼ºçè¡ä¸ºåç¸å ³çå æ°æ®ï¼ç±æ¡æ¶å¨è¿è¡æ¶å»å®æ对åè代ç çå¢å¼ºãJavaåè代ç å¢å¼ºåºç¨çåºæ¯æ¯è¾å¤ï¼ä¸è¬é½éä¸å¨åå°åä½ä»£ç å对å¼å人åå±è½åºå±çå®ç°ç»èä¸ãç¨è¿JavaBeansç人å¯è½å¯¹å ¶ä¸é£äºå¿ 须添å çgetter/setteræ¹æ³æå°å¾ç¹çï¼å¹¶ä¸é¾ä»¥ç»´æ¤ãèéè¿åè代ç å¢å¼ºï¼å¼å人ååªéè¦å£°æBeanä¸çå±æ§å³å¯ï¼getter/setteræ¹æ³å¯ä»¥éè¿ä¿®æ¹åè代ç æ¥èªå¨æ·»å ãç¨è¿JPAç人ï¼å¨è°è¯ç¨åºçæ¶åï¼ä¼åç°å®ä½ç±»ä¸è¢«æ·»å äºä¸äºé¢å¤ç ååæ¹æ³ãè¿äºååæ¹æ³æ¯å¨è¿è¡æ¶å»ç±JPAçå®ç°å¨ææ·»å çãåè代ç å¢å¼ºå¨é¢åæ¹é¢ç¼ç¨ï¼AOPï¼çä¸äºå®ç°ä¸ä¹æ使ç¨ã
easylogging源码学习笔记(6)
`LOG` 是默认日志、CLOG自定义日志、LOG_IF条件日志
特殊日志
LOG_EVERY_N、LOG_AFTER_N、LOG_N_TIMES
for (int i = 1; i <= ; ++i) {
LOG_EVERY_N(2, INFO) << "Logged every second iter";
}// 5 logs written; 2, 4, 6, 7,
for (int i = 1; i <= ; ++i) {
LOG_AFTER_N(2, INFO) << "Log after 2 hits; " << i;
}// 8 logs written; 3, 4, 5, 6, 7, 8, 9,
for (int i = 1; i <= ; ++i) {
LOG_N_TIMES(3, INFO) << "Log only 3 times; " << i;
}// 3 logs writter; 1, 2, 3
条件日志和特殊日志可以搭配使用
* `VLOG_IF(condition, verbose-level)`
* `CVLOG_IF(condition, verbose-level, loggerID)`
* `VLOG_EVERY_N(n, verbose-level)`
* `CVLOG_EVERY_N(n, verbose-level, loggerID)`
* `VLOG_AFTER_N(n, verbose-level)`
* `CVLOG_AFTER_N(n, verbose-level, loggerID)`
* `VLOG_N_TIMES(n, verbose-level)`
* `CVLOG_N_TIMES(n, verbose-level, loggerID)`
日志详细等级判定
if (VLOG_IS_ON(2)) {
// Verbosity level 2 is on for this file
}
性能追踪
* `TIMED_FUNC(obj-name)`
* `TIMED_SCOPE(obj-name, block-name)`
* `TIMED_BLOCK(obj-name, block-name)`
这些宏实际上都是关于el::base::type::PerformanceTrackerPtr,一个指向el::base::PerformanceTracker的指针
#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
PerformanceTracker::PerformanceTracker(const std::string& blockName,
base::TimestampUnit timestampUnit,
const std::string& loggerId,
bool scopedLog, Level level) :
m_blockName(blockName), m_timestampUnit(timestampUnit), m_loggerId(loggerId), m_scopedLog(scopedLog),
m_level(level), m_hasChecked(false), m_lastCheckpointId(std::string()), m_enabled(false) {
#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
// We store it locally so that if user happen to change configuration by the end of scope
// or before calling checkpoint, we still depend on state of configuration at time of construction
el::Logger* loggerPtr = ELPP->registeredLoggers()->get(loggerId, false);
m_enabled = loggerPtr != nullptr && loggerPtr->m_typedConfigurations->performanceTracking(m_level);
if (m_enabled) {
base::utils::DateTime::gettimeofday(&m_startTime);
}
#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
}
在构造函数中获取一个时间,
PerformanceTracker::~PerformanceTracker(void) {
#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
if (m_enabled) {
base::threading::ScopedLock scopedLock(lock());
if (m_scopedLog) {
base::utils::DateTime::gettimeofday(&m_endTime);
base::type::string_t formattedTime = getFormattedTimeTaken();
PerformanceTrackingData data(PerformanceTrackingData::DataType::Complete);
data.init(this);
data.m_formattedTimeTaken = formattedTime;
PerformanceTrackingCallback* callback = nullptr;
for (const std::pair& h
: ELPP->m_performanceTrackingCallbacks) {
callback = h.second.get();
if (callback != nullptr && callback->enabled()) {
callback->handle(&data);
}
}
}
}
#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING)
}
在析构函数中获取一个时间,处理时间data,使用PerformanceTrackingCallback类型指针callback,并在callback->handle(&data)中处理输出。
由于定义了ELPP_FEATURE_PERFORMANCE_TRACKING,因此在初始化(INITIALIZE_EASYLOGGINGPP)中实际上是安装了一个base::DefaultPerformanceTrackingCallback。
在PerformanceTracker类的handle函数中,callback是一个PerformanceTrackingCallback类型指针,由于安装的是DefaultPerformanceTrackingCallback对象,因此是一个基类指针指向了派生类对象。处理输出的逻辑在DefaultPerformanceTrackingCallback类的handle函数中。
DefaultPerformanceTrackingCallback类的handle函数首先会将数据成员m_data的指针赋值给函数参数,并创建一个base::type::stringstream_t类型的unirx源码阅读对象ss用于构建输出内容。根据m_data的dataType,输出不同的信息。在输出时,会使用el::base::Writer类构造并输出内容。
逆向pyinstaller打包的exe软件,获取python源码(6)
在之前的讨论中,我们已经成功逆向了由pyinstaller打包的exe程序的主程序。然而,关于其依赖的python文件,其实获取方法相当直接。关键在于PYZ-.pyz_extracted文件夹,其中包含编译exe时转化为pyc格式的依赖文件。只要对这些pyc文件进行逆向,就能揭示出整个exe的所有python源代码,这种方法屡试不爽。然而,有知乎网友推荐使用Nuitka进行exe打包,以增加代码的防护,防止源码被轻易反编译。具体步骤如下:首先,进入PYZ-.pyz_extracted文件夹,你将发现所需的依赖文件。
接着,对这些pyc文件进行逆向处理,从而获取到全部的python源代码。
在pycharm等开发环境中,打开这些源代码,解决任何依赖关系问题。
最后,直接运行你修改后的代码,程序即可成功启动。
从源码构建并安装Qt6
在处理大作业时,我需要使用Qt,然而官方下载途径的不便和速度让我考虑了其他方式。从Qt 5.开始,官方已不再提供离线安装包,只能通过在线下载或源码构建。对于我这个初次接触项目构建的初学者来说,这个过程充满挑战,但在大佬的帮助下,我成功安装了。
如果你对Qt的需求并不紧急,可以访问download.qt.io/archive/...,下载5.版本及以下的离线安装包。
对于想要从源码构建Qt6的用户,以下是具体步骤。注意,这个过程会安装全套工具,大约GB,但无法定制安装。以Qt6.5.0为例,首先从官方下载页或镜像站如清华大学、中国互联网络信息中心或中国科学技术大学的 mirrors 获取qt-everywhere-src-6.5.0.zip。
确保你的环境中安装了CMake、Ninja(推荐,但可选)和Python3,并将它们的路径添加到系统PATH中。解压下载的代码包后,重命名或直接放在指定目录如D:\Qt\6.5.0,用~代替。找到VS编译器目录,例如C:\Program Files\Microsoft Visual Studio\\Community\VC\Auxiliary\Build。
创建一个txt文件,内容如下(请根据实际路径替换):
bash
set PATH=%ProgramFiles%\Microsoft Visual Studio\\Community\VC\Tools\MSVC\..\bin\HostX\x;%PATH%
set PATH=%VSCOMNTOOLS%;%PATH%
将后缀改为.cmd,然后在cmd中运行配置命令,如%SystemRoot%\system\cmd.exe /E:ON /V:ON /k D:\Qt\6.5.0\qt6vars.cmd。接着,cd到源码目录并运行configure -prefix -debug(不写-prefix默认安装路径为C:\Program Files\Qt)。
开始构建过程,使用cmake --build . --parallel 或 ninja,这可能需要到分钟,具体时间取决于配置。最后,通过cmake --install . 完成安装,qmake.exe等可执行文件会出现在bin目录中。
Keil AC5 和 AC6的一些区别
Keil MDK的默认编译器已升级到Arm Compiler 6(AC6),而AC5编译器虽已不包含在最新版本中,但因其性能稳定,仍在部分工程中被使用。AC6相比于AC5,最大的区别在于编译速度显著提升,并且在代码大小上也有所优化。AC6采用的armclang编译器基于LLVM和Clang技术,提供了更先进的编译策略。在优化选项方面,AC6提供了多种选择,如-O0、-O1、-O2、-O3、-Os、-Oz、-Ofast和-Omax,帮助开发者根据需求选择最适合的优化级别。
AC6相对于AC5的改进还包括支持C++标准,以及TrustZone for Armv8-M技术,为设备创建安全和非安全代码的能力。此外,AC6兼容基于GCC创建的源代码,使得开发者能够利用更广泛的C++库和工具。
编译器的性能提升主要得益于更高效的代码生成和优化算法,以及对现代处理器特性的更好支持。优化选项的增加为开发者提供了更大的灵活性,以满足不同场景下的性能、代码大小和调试体验需求。例如,-Os和-Oz选项专注于优化代码大小,而-O3和-Ofast选项则侧重于性能提升,但可能在代码可读性和调试上有所妥协。
在迁移过程中,开发者需要注意不同编译器之间的兼容性差异,并参考官方文档和指南完成代码和配置的适配。Keil MDK的优化选项为开发者提供了强大的工具,帮助他们根据特定应用需求定制编译过程,从而获得最佳的性能、代码质量和资源利用效率。
Keil MDK和Arm Compiler之间的区别在于集成和优化选项,以及对现代编程语言和处理器特性的支持。选择合适的编译器和优化策略对于提高软件性能、减小代码大小以及提高开发效率至关重要。通过了解不同编译器的特点和优势,开发者能够更有效地利用资源,实现高性能、可维护的软件系统。