当前位置: 首页 > news >正文

NDK JNI 变声器实现

Android NDK 导入 C库的开发流程学习;通过使用fmod的C库,实现变声器功能。

  1. 导入库文件

1)复制fmod的C库到cpp目录下

2)复制fmod的so库到jniLibs目录下

3)复制fmod的jar库到libs目录下

4)将声音文件复制到assets目录下

fmod库文件资源:https://wwgl.lanzout.com/ilXHP0pn7f4f

  1. 打开CMakeLists.txt导入fmod库文件

cmake_minimum_required(VERSION 3.10.2) # 最低支持的CMake版本project("whine")# TODO 第一步 导入头文件(fmod库)
include_directories("inc")# 批量导入所有文件
file(GLOB allCPP *.c *.h *.cpp)add_library(native-lib # 打包出来库的名称 libnative-lib.soSHARED # 动态库${allCPP} # 添加所有库文件
)# TODO 第二步 导入库文件(fmod库)
# ${CMAKE_CXX_FLAGS} 原先的CMake环境 +
# -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI} 加上新的fmod库的路径
# CMAKE_SOURCE_DIR == CMakeLists.txt所在的路径
# /../ 回退到cpp目录
# jniLibs/ 进入jniLibs目录
# ${CMAKE_ANDROID_ARCH_ABI} 使用当前手机CPU系统结构对应的库 如:arm64-v8a
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}")find_library(log-liblog # 自动寻找log库
)# TODO 第三步 链接具体的库,到 libnative-lib.so总库
target_link_libraries(native-lib${log-lib}fmod # 具体的库 链接到 libnative-lib.so里面去fmodL # 具体的库 链接到 libnative-lib.so里面去
)
  1. 打开build.gradle,指定CPU架构和依赖fmod的jar包

defaultConfig {// TODO 第四步externalNativeBuild {cmake {// cppFlags "" // 默认五大平台// 指定CPU架构,Cmake的本地库, 例如:native-lib ---> arm64-v8aabiFilters "arm64-v8a"}}// TODO 第五步// 指定CPU架构,打入APK lib/CPU平台ndk {abiFilters "arm64-v8a"}
}dependencies {// TODO 第六步:依赖fmod的jar包implementation files("libs\\fmod.jar");
}
  1. 准备工作完成,开始编写Activity代码

1)定义变声模式

/*** 定义变声模式* 0 正常; 1 萝莉; 2 大叔; 3 惊悚; 4 搞怪; 5 回声;*/
private static final int MODE_NORMAL = 0;
private static final int MODE_LUOLI = 1;
private static final int MODE_DASHU = 2;
private static final int MODE_JINGSONG = 3;
private static final int MODE_GAOGUAI = 4;
private static final int MODE_KONGLING = 5;

2)加载编译后的lib库

static {System.loadLibrary("native-lib");
}

3)初始化fmod.jar库,并在页面关闭的时候释放

@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);FMOD.init(this);
}@Override
protected void onDestroy() {super.onDestroy();FMOD.close();
}

4)编写变声native层方法和变声结束后提供native调用的方法

public native void voiceChangeNative(int modeNormal, String path);private void playerEnd(String msg) {isPlaying = false;runOnUiThread(() -> Toast.makeText(this, msg, Toast.LENGTH_SHORT).show());
}

5)Activity完整代码

package com.whine;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.view.View;
import android.widget.Toast;import org.fmod.FMOD;/*** TODO Android NDK 导入 C库,开发流程 之 变声器*/
public class MainActivity extends AppCompatActivity {/*** 定义变声模式* 0 正常; 1 萝莉; 2 大叔; 3 惊悚; 4 搞怪; 5 回声;*/private static final int MODE_NORMAL = 0;private static final int MODE_LUOLI = 1;private static final int MODE_DASHU = 2;private static final int MODE_JINGSONG = 3;private static final int MODE_GAOGUAI = 4;private static final int MODE_KONGLING = 5;/*** 声音路径*/private String soundPath;private boolean isPlaying = false;static {System.loadLibrary("native-lib");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// TODO 第七步 初始化FMOD库FMOD.init(this);initData();}private void initData() {soundPath = "file:///android_asset/sound.mp3";}// 点击事件public void onFix(View view) {switch (view.getId()) {case R.id.btn_normal:voiceChange(MODE_NORMAL, soundPath); // 真实开发中,必须子线程  JNI线程(很多坑)break;case R.id.btn_luoli:voiceChange(MODE_LUOLI, soundPath);break;case R.id.btn_dashu:voiceChange(MODE_DASHU, soundPath);break;case R.id.btn_jingsong:voiceChange(MODE_JINGSONG, soundPath);break;case R.id.btn_gaoguai:voiceChange(MODE_GAOGUAI, soundPath);break;case R.id.btn_kongling:voiceChange(MODE_KONGLING, soundPath);break;}}@Overrideprotected void onDestroy() {super.onDestroy();FMOD.close();}private void voiceChange(int modeNormal, String path) {if (isPlaying) {Toast.makeText(this, "正在播放,请稍后!", Toast.LENGTH_SHORT).show();return;}isPlaying = true;new Thread(() -> voiceChangeNative(modeNormal, path)).start();}/*** 给C++(native)层调用的函数* JNI 调用 Java函数的时候,忽略掉 私有、公开 等** @param msg*/private void playerEnd(String msg) {isPlaying = false;runOnUiThread(() -> Toast.makeText(this, msg, Toast.LENGTH_SHORT).show());}/*** 变声native层方法** @param modeNormal* @param path*/public native void voiceChangeNative(int modeNormal, String path);
}
  1. 编写native层头文件(声明文件)

1)导入需要使用到的头文件

#include <jni.h>
#include <fmod.hpp>
#include <string>
#include <android/log.h>

2)定义log宏

#define TAG "NDK"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)

3)定义变声模式宏

#undef com_whine_MainActivity_MODE_NORMAL
#define com_whine_MainActivity_MODE_NORMAL 0L
#undef com_whine_MainActivity_MODE_LUOLI
#define com_whine_MainActivity_MODE_LUOLI 1L
#undef com_whine_MainActivity_MODE_DASHU
#define com_whine_MainActivity_MODE_DASHU 2L
#undef com_whine_MainActivity_MODE_JINGSONG
#define com_whine_MainActivity_MODE_JINGSONG 3L
#undef com_whine_MainActivity_MODE_GAOGUAI
#define com_whine_MainActivity_MODE_GAOGUAI 4L
#undef com_whine_MainActivity_MODE_KONGLING
#define com_whine_MainActivity_MODE_KONGLING 5L

4)头文件完整代码

// TODO 第八步 编写头文件(声明文件)
#include <jni.h>
// 导入FMOD的头文件
#include <fmod.hpp>
#include <string>
// 导入log库
#include <android/log.h>extern "C" {// log宏
#define TAG "NDK"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)// 创建变声模式宏
#undef com_whine_MainActivity_MODE_NORMAL
#define com_whine_MainActivity_MODE_NORMAL 0L
#undef com_whine_MainActivity_MODE_LUOLI
#define com_whine_MainActivity_MODE_LUOLI 1L
#undef com_whine_MainActivity_MODE_DASHU
#define com_whine_MainActivity_MODE_DASHU 2L
#undef com_whine_MainActivity_MODE_JINGSONG
#define com_whine_MainActivity_MODE_JINGSONG 3L
#undef com_whine_MainActivity_MODE_GAOGUAI
#define com_whine_MainActivity_MODE_GAOGUAI 4L
#undef com_whine_MainActivity_MODE_KONGLING
#define com_whine_MainActivity_MODE_KONGLING 5L
JNIEXPORT void JNICALL Java_com_whine_MainActivity_voiceChangeNative(JNIEnv *, jobject, jint, jstring);
}
  1. 编写native层实现文件

1)转换Java层传递的声音路径jstring -> char *

const char *pathChar = env->GetStringUTFChars(path, NULL);

2)定义和初始化音效引擎系统

// 定义音效引擎系统 指针
System *system = 0;
// 声音
Sound *sound = 0;
// 音轨
Channel *channel = 0;
// 数字信号处理  指针
DSP *dsp = 0;
// 创建系统
System_Create(&system);
// 初始化系统 参数1:最大音轨数,参数2:系统初始化标记,参数3:额外数据
system->init(32, FMOD_INIT_NORMAL, 0);
// 创建声音  参数1:路径,  参数2:声音初始化标记, 参数3:额外数据, 参数4:声音指针
system->createSound(pathChar, FMOD_DEFAULT, 0, &sound);
// 播放声音,并赋值通道 参数1:声音,参数2:分组音轨,参数3:控制,参数4:通道
system->playSound(sound, 0, false, &channel);

3)判断变声模式,调节音效

switch (mode_normal) {case com_whine_MainActivity_MODE_NORMAL:resultChar = "原生,播放完毕!";break;case com_whine_MainActivity_MODE_LUOLI:resultChar = "萝莉,播放完毕!";// 音调高 -- 萝莉 2.0// 1.创建DSP类型的Pitch 音调条件system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);// 2.设置Pitch音调调节2.0dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 3.0f);// 3.添加音效进去 第一个音轨channel->addDSP(0, dsp);break;case com_whine_MainActivity_MODE_DASHU:resultChar = "大叔,播放完毕!";// 音调低 -- 大叔 0.7// 1.创建DSP类型的Pitch 音调条件system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);// 2.设置Pitch音调调节0.7dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 0.7f);// 3.添加音效进去 第一个音轨channel->addDSP(0, dsp);break;case com_whine_MainActivity_MODE_GAOGUAI:resultChar = "搞怪小黄人,播放完毕!";// 小黄人声音 频率快// 1.从音轨拿 当前 频率float frequency;channel->getFrequency(&frequency);// 2.加快频率加快  小黄人的声音channel->setFrequency(frequency * 1.5f);break;case com_whine_MainActivity_MODE_JINGSONG:resultChar = "惊悚,播放完毕!";// 惊悚音效:特点:很多声音的拼接// TODO 1.音调低// 音调低 -- 大叔 0.7// 1.创建DSP类型的Pitchsystem->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);// 2.设置Pitch音调调节0.7dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 0.7f);// 3.添加音效进去 第一个音轨channel->addDSP(0, dsp);// TODO 2.回声// 回音 ECHO// 1.创建DSP类型的ECHOsystem->createDSPByType(FMOD_DSP_TYPE_ECHO, &dsp);// 2.设置回音 延时 to 5000.  Default = 500.dsp->setParameterFloat(FMOD_DSP_ECHO_DELAY, 200);// 3.设置回音 衰减度 Default = 50   0 完全衰减了dsp->setParameterFloat(FMOD_DSP_ECHO_FEEDBACK, 10);// 4.添加音效进去 第二个音轨channel->addDSP(1, dsp);// TODO 3.颤抖// Tremolo 颤抖音// 1.创建DSP类型的Tremolosystem->createDSPByType(FMOD_DSP_TYPE_TREMOLO, &dsp);// 2.设置颤抖 正常 5,非常颤抖 20dsp->setParameterFloat(FMOD_DSP_TREMOLO_FREQUENCY, 20);// 3.dsp->setParameterFloat(FMOD_DSP_TREMOLO_SKEW, 0.8f);// 4.第三个音轨channel->addDSP(2, dsp);break;case com_whine_MainActivity_MODE_KONGLING:resultChar = "空灵,播放完毕!";// 回音 ECHO// 1.创建DSP类型的ECHO 音调条件system->createDSPByType(FMOD_DSP_TYPE_ECHO, &dsp);// 2.设置回音 延时 to 5000.  Default = 500.dsp->setParameterFloat(FMOD_DSP_ECHO_DELAY, 200);// 3.设置回音 衰减度 Default = 50   0 完全衰减了dsp->setParameterFloat(FMOD_DSP_ECHO_FEEDBACK, 10);// 4.添加音效进去 第一个音轨channel->addDSP(0, dsp);break;
}

4)检测声音是否播放完毕

bool isPlay = true;
while (isPlay) {// 如果真的播放完成了,音轨是知道的,内部会修改isPlayer=falsechannel->isPlaying(&isPlay);// 休眠100mSusleep(100 * 1000);
}

5)回收C层资源

sound->release();
system->close();
system->release();
env->ReleaseStringUTFChars(path, pathChar);

6)播放完毕,通知java层(调用Java层的播放完成方法)

jclass jClazz = env->GetObjectClass(thiz);
jmethodID methodId = env->GetMethodID(jClazz, "playerEnd", "(Ljava/lang/String;)V");
jstring value = env->NewStringUTF(resultChar);
env->CallVoidMethod(thiz, methodId, value);

7)实现文件完整代码

#include <unistd.h>
#include "whine.h"using namespace FMOD; // fmod的命名空间extern "C"
JNIEXPORT void JNICALL
Java_com_whine_MainActivity_voiceChangeNative(JNIEnv *env, jobject thiz, jint mode_normal,jstring path) {// 定义一个结果字符串返回char *resultChar = "播放完毕!";// 转换路径jstring -> char *const char *pathChar = env->GetStringUTFChars(path, NULL);// 定义音效引擎系统 指针System *system = 0;// 声音Sound *sound = 0;// 音轨Channel *channel = 0;// 数字信号处理  指针DSP *dsp = 0;// 创建系统System_Create(&system);// 初始化系统 参数1:最大音轨数,参数2:系统初始化标记,参数3:额外数据system->init(32, FMOD_INIT_NORMAL, 0);// 创建声音  参数1:路径,  参数2:声音初始化标记, 参数3:额外数据, 参数4:声音指针system->createSound(pathChar, FMOD_DEFAULT, 0, &sound);// 播放声音,并赋值通道 参数1:声音,参数2:分组音轨,参数3:控制,参数4:通道system->playSound(sound, 0, false, &channel);LOGI("init done");// 判断模式,增加特效switch (mode_normal) {case com_whine_MainActivity_MODE_NORMAL:resultChar = "原生,播放完毕!";break;case com_whine_MainActivity_MODE_LUOLI:resultChar = "萝莉,播放完毕!";// 音调高 -- 萝莉 2.0// 1.创建DSP类型的Pitch 音调条件system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);// 2.设置Pitch音调调节2.0dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 3.0f);// 3.添加音效进去 第一个音轨channel->addDSP(0, dsp);break;case com_whine_MainActivity_MODE_DASHU:resultChar = "大叔,播放完毕!";// 音调低 -- 大叔 0.7// 1.创建DSP类型的Pitch 音调条件system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);// 2.设置Pitch音调调节0.7dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 0.7f);// 3.添加音效进去 第一个音轨channel->addDSP(0, dsp);break;case com_whine_MainActivity_MODE_GAOGUAI:resultChar = "搞怪小黄人,播放完毕!";// 小黄人声音 频率快// 1.从音轨拿 当前 频率float frequency;channel->getFrequency(&frequency);// 2.加快频率加快  小黄人的声音channel->setFrequency(frequency * 1.5f);break;case com_whine_MainActivity_MODE_JINGSONG:resultChar = "惊悚,播放完毕!";// 惊悚音效:特点:很多声音的拼接// TODO 1.音调低// 音调低 -- 大叔 0.7// 1.创建DSP类型的Pitchsystem->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);// 2.设置Pitch音调调节0.7dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 0.7f);// 3.添加音效进去 第一个音轨channel->addDSP(0, dsp);// TODO 2.回声// 回音 ECHO// 1.创建DSP类型的ECHOsystem->createDSPByType(FMOD_DSP_TYPE_ECHO, &dsp);// 2.设置回音 延时 to 5000.  Default = 500.dsp->setParameterFloat(FMOD_DSP_ECHO_DELAY, 200);// 3.设置回音 衰减度 Default = 50   0 完全衰减了dsp->setParameterFloat(FMOD_DSP_ECHO_FEEDBACK, 10);// 4.添加音效进去 第二个音轨channel->addDSP(1, dsp);// TODO 3.颤抖// Tremolo 颤抖音// 1.创建DSP类型的Tremolosystem->createDSPByType(FMOD_DSP_TYPE_TREMOLO, &dsp);// 2.设置颤抖 正常 5,非常颤抖 20dsp->setParameterFloat(FMOD_DSP_TREMOLO_FREQUENCY, 20);// 3.dsp->setParameterFloat(FMOD_DSP_TREMOLO_SKEW, 0.8f);// 4.第三个音轨channel->addDSP(2, dsp);break;case com_whine_MainActivity_MODE_KONGLING:resultChar = "空灵,播放完毕!";// 回音 ECHO// 1.创建DSP类型的ECHO 音调条件system->createDSPByType(FMOD_DSP_TYPE_ECHO, &dsp);// 2.设置回音 延时 to 5000.  Default = 500.dsp->setParameterFloat(FMOD_DSP_ECHO_DELAY, 200);// 3.设置回音 衰减度 Default = 50   0 完全衰减了dsp->setParameterFloat(FMOD_DSP_ECHO_FEEDBACK, 10);// 4.添加音效进去 第一个音轨channel->addDSP(0, dsp);break;}// 等待播放完毕 再回收bool isPlay = true;while (isPlay) {// 如果真的播放完成了,音轨是知道的,内部会修改isPlayer=falsechannel->isPlaying(&isPlay);// 休眠100mSusleep(100 * 1000);}LOGI("play done");// 回收资源sound->release();system->close();system->release();env->ReleaseStringUTFChars(path, pathChar);// 通知java层jclass jClazz = env->GetObjectClass(thiz);jmethodID methodId = env->GetMethodID(jClazz, "playerEnd", "(Ljava/lang/String;)V");jstring value = env->NewStringUTF(resultChar);env->CallVoidMethod(thiz, methodId, value);
}

相关文章:

NDK JNI 变声器实现

Android NDK 导入 C库的开发流程学习&#xff1b;通过使用fmod的C库&#xff0c;实现变声器功能。导入库文件1&#xff09;复制fmod的C库到cpp目录下2&#xff09;复制fmod的so库到jniLibs目录下3&#xff09;复制fmod的jar库到libs目录下4&#xff09;将声音文件复制到assets目…...

VMLogin防关联指纹浏览器的主帐号和子账号区别介绍

VMLogin主账户管理子账户&#xff0c;主要用于团队协作&#xff0c;分账户登录使用&#xff0c;主账户相当于老板&#xff0c;子账户相当于员工。 主账户创建并管理子账户&#xff1b; 主账户可以修改子账户的密码&#xff1b; 主账户可以设置子账户是否有创建配置文件权限&a…...

Apache DolphinScheduler GitHub Star 突破 10000!

点击蓝字 关注我们今天&#xff0c;Apache DolphinScheduler GitHub Star 突破 10000&#xff0c;项目迎来一个重要里程碑。这表明 Apache DolphinScheduler 已经在全球的开发者和用户中获得了广泛的认可和使用。DolphinScheduler 旨在解决公司日常运营中的大数据处理工作流调度…...

程序员中的女性力量——做不被定义的自己

她是office lady&#xff0c;亦是程序媛&#xff0c;程序员界的靓丽色彩&#xff0c;不可或缺。 “只有那些疯狂到以为自己能够改变世界的人——才能真正改变世界。” 女性该如何定义自己&#xff1f;程序媛怎么发挥自己最大的价值。 争取自己做选择&#xff0c;经济和思想都独…...

pb中Datawindow中每页打印固定行

Datawindow中每页打印固定行 第一步: 增加一个计算列,此计算列必须放在Detail段,Expression中输入:ceiling(getrow()/20),这里20还可以用全局函数取代,这样可以允许用户任意设置每页打印多少行。 第二步: 定义分组,选择菜单Rows->Create Group...按计算列字段…...

华为OD机试 - 内存池(C 语言解题)【独家】

最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧文章目录 使用说明本期题目:内存池题…...

SaaS简介

SaaS 简介 SaaS被认为是云计算的一部分&#xff0c;其他包括基础设施即服务(IaaS)、平台即服务(PaaS)、桌面即服务(DaaS)、托管软件即服务(MSaaS)、移动后端即服务(MBaaS)、数据中心即服务(DCaaS)、集成平台即服务(iPaaS)和信息技术管理即服务(ITMaaS) SaaS应用程序通常由web浏…...

unity 实现使用三张图片来表达车速,通过传值达到车速

//速度 public Image SpeedNums_Unit; public Image SpeedNums_Ten; //public Image SpeedNums_Hundred; //kw public Image MileageNums_Unit; public Image MileageNums_Ten; /// /// 仪表速度UI /// private void SpeedUI(string speedStr) {if (SpeedNums_Unit == null) …...

程序员看过都说好的资源网站,你值得拥有。

程序员必备的相关资源网站一.技术社区1.GitHub2.Gitee&#xff08;码云&#xff09;3.稀土掘金4.OSCHINA开源中国5.CSDN6.博客园7.SegmentFault&#xff08;思否&#xff09;8.Stack Overflow9.Golang中文社区10.ChinaUnix11.51CTO12.Ruby China二.技术教程1.Devdocs2.码农教程…...

【MySQL高级篇】第03章 用户与权限管理

第03章 用户与权限管理 1. 用户管理 1.1 登录MySQL服务器 启动MySQL服务后&#xff0c;可以通过mysql命令来登录MySQL服务器&#xff0c;命令如下&#xff1a; mysql –h hostname|hostIP –P port –u username –p DatabaseName –e "SQL语句"-h参数后面接主机…...

MySQL的分库分表?通俗易懂

1- 为什么要分库分表 如果一个网站业务快速发展&#xff0c;那这个网站流量也会增加&#xff0c;数据的压力也会随之而来&#xff0c;比如电商系统来说双十一大促对订单数据压力很大&#xff0c;Tps十几万并发量&#xff0c;如果传统的架构&#xff08;一主多从&#xff09;&a…...

elasticsearch 查询语法

match_all 查询所有 GET test/_search {"query": {"match_all": {}} }match 单字段匹配查询 GET test/_search {"query":{"match":{"name":"zhangsan"}} }multi_match 多字段匹配查询 GET test/_search {"…...

深入剖析MVC模型与三层架构

MVC&#xff08;Model-View-Controller&#xff09;模型和三层架构都是常见的软件架构模式&#xff0c;用于实现大型应用程序和软件系统。下面是对它们的深入剖析&#xff1a; MVC模型 MVC模型是一种将应用程序分成三个主要组件的软件架构模式&#xff0c;分别是模型&#xf…...

使用 Wall 搭建个人照片墙和视频墙

下载 Github:https://github.com/super-tongyao/wall 国内仓库&#xff08;不推荐&#xff0c;只做加速访问&#xff0c;无编译包和发行版&#xff0c;以github仓库为准&#xff09;&#xff1a;https://gitee.com/Super_TongYao/wall 推荐github仓库&#xff0c;下载最新版…...

03_Linux压缩解压,用户用户组,文件权限

目录 Linux下常用的压缩格式 gzip 压缩工具 gzip 对文件夹进行压缩 bzip2 压缩工具 tar打包工具 对.tar.bz2 进行压缩和解压缩 对.tar.gz 进行压缩和解压缩 rar格式 zip格式 Linux用户 Linux用户组 创建用户和用户组 Linux文件权限 Linux文件权限修改 Linux下常用…...

硬盘分区数据恢复?这些方法助您解忧

案例&#xff1a;分区把电脑文件丢了&#xff0c;数据还能恢复吗&#xff1f; “急急急&#xff01;&#xff01;&#xff01;本人电脑小白&#xff0c;在使用磁盘管理合并E、F分区的时候&#xff0c;不小心把D分区给删除了&#xff0c;D分区里面存放了很多重要的数据与文件&a…...

高校竞赛信息管理系统

摘要随着当今社会的发展&#xff0c;时代的进步&#xff0c;各行各业也在发生着变化&#xff0c;比如高校竞赛信息管理这一方面&#xff0c;利用网络已经逐步进入人们的生活。传统的高校竞赛信息管理&#xff0c;都是学生去学校查看竞赛信息然后再进行报名&#xff0c;这种传统…...

还是要学好数学啊

有一个无穷大的二维网格图&#xff0c;一开始所有格子都未染色。给你一个正整数 n &#xff0c;表示你需要执行以下步骤 n 分钟&#xff1a;第一分钟&#xff0c;将任一格子染成蓝色。之后的每一分钟&#xff0c;将与蓝色格子相邻的 所有 未染色格子染成蓝色。下图分别是 1、2、…...

ActiveMQ反序列化漏洞原理+复现

ActiveMQ反序列化漏洞 ActiveMQ ActiveMQ是开源消息总线&#xff0c;消息中间件 工作原理 通过使用消息队列&#xff0c;实现服务的异步处理&#xff0c;主要目的是减少请求响应时间和解耦合。 消息队列&#xff0c;服务器A将客户发起的请求放入服务器B的消息队列中&#…...

layui框架实战案例(19):layui-table模块表格综合应用(筛选查询、导入导出、群发短信、一键审核、照片展示、隐私加密)

系列文章目录 layui动态表格翻页和搜索的代码分析layui框架实战案例(3)&#xff1a;layui上传错误请求上传接口出现异常解决方案layui框架实战案例(9)&#xff1a;layPage 静态数据分页组件layui框架实战案例(10)&#xff1a;短信验证码60秒倒计时layui框架实战案例(11)&#…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

GitHub 趋势日报 (2025年06月06日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...

云安全与网络安全:核心区别与协同作用解析

在数字化转型的浪潮中&#xff0c;云安全与网络安全作为信息安全的两大支柱&#xff0c;常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异&#xff0c;并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全&#xff1a;聚焦于保…...