java通过jna调用科大讯飞语音云实现语音识别功能
说明:写本文时还没有提供java平台的,现在官方有java平台的sdk了,可以直接使用。本文已经没有太多实际意义了。
语音识别技术
语音识别就是让机器通过识别和理解过程把语音信号转变为相应的文本或命令。语音识别技术主要包括特征提取技术、模式匹配准则及模型训练技术三个方面。说实话其中的技术比较多,要独立开发新的基本上不现实。所以自然把目光放到开源项目或者其他公司的API上面了。开源项目我尝试了SpeakRight和sphinx4,但是效果都是一般。AT&T的API老是申请不上,最后把目光放在科大讯飞上了。试用了一下,效果还行,但是它提供的Windows平台的API是C/C++的,我只懂点皮毛,所以稍微研究了一下通过Java调用它的语音云SDK。
JNA
java调用.dll获取.so一般通过JNI,但是JNI的使用比较复杂,需要用C另写一个共享库进行适配。而JNA是一个自动适配工具,通过它调用.dll只需要一个借口即可。
官网:https://github.com/twall/jna/
下载jna.jar即可。
编写接口
科大讯飞语音云主要提供语音合成和语音识别两个方面的东西,我主要使用语音识别这块的功能。
建立接口QTSR,继承Library。
将msc.dll等文件复制到项目根目录。
加载msc.dll
QTSR INSTANCE = (QTSR) Native.loadLibrary( "msc" , QTSR. class ); |
然后来看一下msc.dll公开了哪些方法。首先是QISRInit,这是一个全局初始化函数。
它的返回值为int,参数是const char*。int还是java的int,但是char*就对应的是java的String了。
所以在QTSR中添加方法:
public int QISRInit(String configs); |
返回值在msp_errors.h中定义,等一下我们还是要弄在java里面去。
继续看QISRInit函数,在官方文档中有调用示例:
const char * configs=“server_url=dev.voicecloud.cn, timeout=10000, vad_enable= true ”; int ret = QISRInit( configs ); if (MSP_SUCCESS != ret ) { printf ( “QISRInit failed, error code is: %d”, ret ); } |
对应的在java中的调用代码如下:
String config = "server_url=dev.voicecloud.cn, timeout=10000, vad_enable=true" ; int code = QTSR.INSTANCE.QISRInit(config); if (code != 0 ) { System.out.println( "QISRInit failed, error code is:" + code); } |
我们在看一个函数:QISRSessionBegin,这个开始一路ISR会话。
还是刚才的思路,char*对应java的String,但是注意一下int *errorCode。这个函数其实传入两个参数,传出两个参数。即本身返回的sessionId,还有errorCode。
这里的int*对应的是jna的IntByReference。所以添加方法:
public String QISRSessionBegin(String grammarList, String params,IntByReference errorCode); |
同样看看官方示例:
/* vad_timeout和vad_speech_tail两个参数只有在打开VAD功能时才生效 */ const char * params= “ssm=1,sub=iat,aue=speex-wb;7,auf=audio/L16;rate=16000,ent=sms16k,rst=plain,vad_timeout=1000,vad_speech_tail=1000”; int ret = MSP_SUCCESS; const char * session_id = QISRSessionBegin( NULL, params, &ret ); if (MSP_SUCCESS != ret ) { printf ( “QISRSessionBegin failed, error code is: %d”, ret ); } |
在java这样写:
String params = "ssm=1,sub=iat,aue=speex-wb;7,auf=audio/L16;rate=16000,ent=sms16k,rst=plain,vad_timeout=1000,vad_speech_tail=1000" ; IntByReference errorCode = new IntByReference(); String sessionId = QTSR.INSTANCE.QISRSessionBegin( null , params,errorCode); |
运行效果:
其他的函数处理方式大致相同,这里贴上一个c和java在jna中的类型对应表:
Native Type | Java Type |
char | byte |
short | short |
wchar_t | char |
int | int |
int | boolean |
long | NativeLong |
long long | long |
float | float |
double | double |
char* | String |
void* | Pointer |
其中Unsigned类型和signed在java中对应是一样的。
.h文件和常量处理
在SDK的include目录有4个.h文件,定义了一些常量,比如上面一节中的0其实是msp_errors.h中MSP_SUCCESS。
我以msp_errors.h为例,建立一个接口Msp_errors,继承StdCallLibrary。
照着msp_errors.h中的定义在Msp_errors中进行定义。
public static final int MSP_SUCCESS = 0 ; public static final int ERROR_FAIL = - 1 ; public static final int ERROR_EXCEPTION= - 2 ; public static final int ERROR_GENERAL= 10100 ; public static final int ERROR_OUT_OF_MEMORY= 10101 ; public static final int ERROR_FILE_NOT_FOUND= 10102 ; public static final int ERROR_NOT_SUPPORT= 10103 ; |
使用很简单的,比如MSP_SUCCESS 就是Msp_errors.MSP_SUCCESS。
完整代码和文件
这个只是语音识别部分的,语音合成的话我记得有人做过jni接口的。
*QTSR.java
package com.cnblogs.htynkn; import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.ptr.IntByReference; /** * @author 夜明的孤行灯 * @date 2012-7-5 */ public interface QTSR extends Library { QTSR INSTANCE = (QTSR) Native.loadLibrary( "msc" , QTSR. class ); /** * 初始化MSC的ISR部分 * * @param configs * 初始化时传入的字符串,以指定合成用到的一些配置参数,各个参数以“参数名=参数值”的形式出现,大小写不敏感,不同的参数之间以“ * ,”或“\n”隔开,不设置任何值时可以传入NULL或空串: * @return 如果函数调用成功返回MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors */ public int QISRInit(String configs); /** * 开始一个ISR会话 * * @param grammarList * uri-list格式的语法,可以是一个语法文件的URL或者一个引擎内置语法列表。可以同时指定多个语法,不同的语法之间以“,” * 隔开。进行语音听写时不需要语法,此参数设定为NULL或空串即可;进行语音识别时则需要语法,语法可以在此参数中指定, * 也可以随后调用QISRGrammarActivate指定识别所用的语法。 * @param params * 本路ISR会话使用的参数,可设置的参数及其取值范围请参考《可设置参数列表_MSP20.xls》,各个参数以“参数名=参数值” * 的形式出现,不同的参数之间以“,”或者“\n”隔开。 * @param errorCode * 如果函数调用成功则其值为MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors。几个主要的返回值: * MSP_ERROR_NOT_INIT 未初始化 MSP_ERROR_INVALID_PARA 无效的参数 * MSP_ERROR_NO_LICENSE 开始一路会话失败 * @return MSC为本路会话建立的ID,用来唯一的标识本路会话,供以后调用其他函数时使用。函数调用失败则会返回NULL。 */ public String QISRSessionBegin(String grammarList, String params, IntByReference errorCode); /** * 传入语法 * * @param sessionID * 由QISRSessionBegin返回过来的会话ID。 * @param grammar * 语法字符串 * @param type * 语法类型,可以是uri-list、abnf、xml等 * @param weight * 本次传入语法的权重,本参数在MSP 2.0中会被忽略。 * @return 如果函数调用成功返回MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors */ public int QISRGrammarActivate(String sessionID, String grammar, String type, int weight); /** * 写入用来识别的语音 * * @param sessionID * 由QISRSessionBegin返回过来的会话ID。 * @param waveData * 音频数据缓冲区起始地址 * @param waveLen * 音频数据长度,其大小不能超过设定的max_audio_size * @param audioStatus * 用来指明用户本次识别的音频是否发送完毕,可能值如下: * MSP_AUDIO_SAMPLE_FIRST = 1 第一块音频 * MSP_AUDIO_SAMPLE_CONTINUE = 2 还有后继音频 * MSP_AUDIO_SAMPLE_LAST = 4 最后一块音频 * @param epStatus * 端点检测(End-point detected)器所处的状态,可能的值如下: * MSP _EP_LOOKING_FOR_SPEECH = 0 还没有检测到音频的前端点。 * MSP _EP_IN_SPEECH = 1 已经检测到了音频前端点,正在进行正常的音频处理。 * MSP _EP_AFTER_SPEECH = 3 检测到音频的后端点,后继的音频会被MSC忽略。 * MSP _EP_TIMEOUT = 4 超时。 * MSP _EP_ERROR= 5 出现错误。 * MSP _EP_MAX_SPEECH = 6 音频过大。 * @param recogStatus * 识别器所处的状态 * @return */ public int QISRAudioWrite(String sessionID, Pointer waveData, int waveLen, int audioStatus, IntByReference epStatus, IntByReference recogStatus); /** * 获取识别结果 * * @param sessionID 由QISRSessionBegin返回过来的会话ID。 * @param rsltStatus 识别结果的状态,其取值范围和含义请参考QISRAudioWrite的参数recogStatus * @param waitTime 与服务器交互的间隔时间,可以控制和服务器的交互频度。单位为ms,建议取值为5000。 * @param errorCode 如果函数调用成功返回MSP_SUCCESS,否则返回错误代码,错误代码参见msp_errors * @return 函数执行成功并且获取到识别结果时返回识别结果,函数执行成功没有获取到识别结果时返回NULL */ public String QISRGetResult(String sessionID, IntByReference rsltStatus, int waitTime, IntByReference errorCode); /** * 结束一路会话 * * @param sessionID 由QISRSessionBegin返回过来的会话ID。 * @param hints 结束本次会话的原因描述,用于记录日志,便于用户查阅或者跟踪某些问题。 * @return */ public int QISRSessionEnd(String sessionID, String hints); /** * 获取与识别交互相关的参数 * * @param sessionID 由QISRSessionBegin返回过来的会话ID。 * @param paramName 要获取的参数名称;支持同时查询多个参数,查询多个参数时,参数名称按“,” 或“\n”分隔开来。 * @param paramValue 获取的参数值,以字符串形式返回;查询多个参数时,参数值之间以“;”分开,不支持的参数将返回空的值。 * @param valueLen 参数值的长度。 * @return */ public int QISRGetParam(String sessionID, String paramName, String paramValue, IntByReference valueLen); /** * 逆初始化MSC的ISR部分 * * @return */ public int QISRFini(); } |
*Msp_errors
package com.cnblogs.htynkn; import com.sun.jna.win32.StdCallLibrary; /** * @author 夜明的孤行灯 * @date 2012-7-5 */ public interface Msp_errors extends StdCallLibrary { public static final int MSP_SUCCESS = 0 ; public static final int ERROR_FAIL = - 1 ; public static final int ERROR_EXCEPTION= - 2 ; public static final int ERROR_GENERAL= 10100 ; /* 0x2774 */ public static final int ERROR_OUT_OF_MEMORY= 10101 ; /* 0x2775 */ public static final int ERROR_FILE_NOT_FOUND= 10102 ; /* 0x2776 */ public static final int ERROR_NOT_SUPPORT= 10103 ; /* 0x2777 */ public static final int ERROR_NOT_IMPLEMENT= 10104 ; /* 0x2778 */ public static final int ERROR_ACCESS= 10105 ; /* 0x2779 */ public static final int ERROR_INVALID_PARA= 10106 ; /* 0x277A */ public static final int ERROR_INVALID_PARA_VALUE= 10107 ; /* 0x277B */ public static final int ERROR_INVALID_HANDLE= 10108 ; /* 0x277C */ public static final int ERROR_INVALID_DATA= 10109 ; /* 0x277D */ public static final int ERROR_NO_LICENSE= 10110 ; /* 0x277E */ public static final int ERROR_NOT_INIT= 10111 ; /* 0x277F */ public static final int ERROR_NULL_HANDLE= 10112 ; /* 0x2780 */ public static final int ERROR_OVERFLOW= 10113 ; /* 0x2781 */ public static final int ERROR_TIME_OUT= 10114 ; /* 0x2782 */ public static final int ERROR_OPEN_FILE= 10115 ; /* 0x2783 */ public static final int ERROR_NOT_FOUND= 10116 ; /* 0x2784 */ public static final int ERROR_NO_ENOUGH_BUFFER= 10117 ; /* 0x2785 */ public static final int ERROR_NO_DATA= 10118 ; /* 0x2786 */ public static final int ERROR_NO_MORE_DATA= 10119 ; /* 0x2787 */ public static final int ERROR_NO_RESPONSE_DATA= 10120 ; /* 0x2788 */ public static final int ERROR_ALREADY_EXIST= 10121 ; /* 0x2789 */ public static final int ERROR_LOAD_MODULE= 10122 ; /* 0x278A */ public static final int ERROR_BUSY = 10123 ; /* 0x278B */ public static final int ERROR_INVALID_CONFIG= 10124 ; /* 0x278C */ public static final int ERROR_VERSION_CHECK= 10125 ; /* 0x278D */ public static final int ERROR_CANCELED= 10126 ; /* 0x278E */ public static final int ERROR_INVALID_MEDIA_TYPE= 10127 ; /* 0x278F */ public static final int ERROR_CONFIG_INITIALIZE= 10128 ; /* 0x2790 */ public static final int ERROR_CREATE_HANDLE= 10129 ; /* 0x2791 */ public static final int ERROR_CODING_LIB_NOT_LOAD= 10130 ; /* 0x2792 */ /* Error codes of network 10200(0x27D8)*/ public static final int ERROR_NET_GENERAL= 10200 ; /* 0x27D8 */ public static final int ERROR_NET_OPENSOCK= 10201 ; /* 0x27D9 */ /* Open socket */ public static final int ERROR_NET_CONNECTSOCK= 10202 ; /* 0x27DA */ /* Connect socket */ public static final int ERROR_NET_ACCEPTSOCK = 10203 ; /* 0x27DB */ /* Accept socket */ public static final int ERROR_NET_SENDSOCK= 10204 ; /* 0x27DC */ /* Send socket data */ public static final int ERROR_NET_RECVSOCK= 10205 ; /* 0x27DD */ /* Recv socket data */ public static final int ERROR_NET_INVALIDSOCK= 10206 ; /* 0x27DE */ /* Invalid socket handle */ public static final int ERROR_NET_BADADDRESS = 10207 ; /* 0x27EF */ /* Bad network address */ public static final int ERROR_NET_BINDSEQUENCE= 10208 ; /* 0x27E0 */ /* Bind after listen/connect */ public static final int ERROR_NET_NOTOPENSOCK= 10209 ; /* 0x27E1 */ /* Socket is not opened */ public static final int ERROR_NET_NOTBIND= 10210 ; /* 0x27E2 */ /* Socket is not bind to an address */ public static final int ERROR_NET_NOTLISTEN = 10211 ; /* 0x27E3 */ /* Socket is not listening */ public static final int ERROR_NET_CONNECTCLOSE= 10212 ; /* 0x27E4 */ /* The other side of connection is closed */ public static final int ERROR_NET_NOTDGRAMSOCK= 10213 ; /* 0x27E5 */ /* The socket is not datagram type */ public static final int ERROR_NET_DNS= 10214 ; /* 0x27E6 */ /* domain name is invalid or dns server does not function well */ /* Error codes of mssp message 10300(0x283C) */ public static final int ERROR_MSG_GENERAL= 10300 ; /* 0x283C */ public static final int ERROR_MSG_PARSE_ERROR= 10301 ; /* 0x283D */ public static final int ERROR_MSG_BUILD_ERROR= 10302 ; /* 0x283E */ public static final int ERROR_MSG_PARAM_ERROR= 10303 ; /* 0x283F */ public static final int ERROR_MSG_CONTENT_EMPTY= 10304 ; /* 0x2840 */ public static final int ERROR_MSG_INVALID_CONTENT_TYPE = 10305 ; /* 0x2841 */ public static final int ERROR_MSG_INVALID_CONTENT_LENGTH = 10306 ; /* 0x2842 */ public static final int ERROR_MSG_INVALID_CONTENT_ENCODE = 10307 ; /* 0x2843 */ public static final int ERROR_MSG_INVALID_KEY= 10308 ; /* 0x2844 */ public static final int ERROR_MSG_KEY_EMPTY= 10309 ; /* 0x2845 */ public static final int ERROR_MSG_SESSION_ID_EMPTY= 10310 ; /* 0x2846 */ public static final int ERROR_MSG_LOGIN_ID_EMPTY= 10311 ; /* 0x2847 */ public static final int ERROR_MSG_SYNC_ID_EMPTY= 10312 ; /* 0x2848 */ public static final int ERROR_MSG_APP_ID_EMPTY= 10313 ; /* 0x2849 */ public static final int ERROR_MSG_EXTERN_ID_EMPTY= 10314 ; /* 0x284A */ public static final int ERROR_MSG_INVALID_CMD= 10315 ; /* 0x284B */ public static final int ERROR_MSG_INVALID_SUBJECT= 10316 ; /* 0x284C */ public static final int ERROR_MSG_INVALID_VERSION= 10317 ; /* 0x284D */ public static final int ERROR_MSG_NO_CMD= 10318 ; /* 0x284E */ public static final int ERROR_MSG_NO_SUBJECT= 10319 ; /* 0x284F */ public static final int ERROR_MSG_NO_VERSION= 10320 ; /* 0x2850 */ public static final int ERROR_MSG_MSSP_EMPTY= 10321 ; /* 0x2851 */ public static final int ERROR_MSG_NEW_RESPONSE= 10322 ; /* 0x2852 */ public static final int ERROR_MSG_NEW_CONTENT= 10323 ; /* 0x2853 */ public static final int ERROR_MSG_INVALID_SESSION_ID = 10324 ; /* 0x2854 */ /* Error codes of DataBase 10400(0x28A0)*/ public static final int ERROR_DB_GENERAL= 10400 ; /* 0x28A0 */ public static final int ERROR_DB_EXCEPTION= 10401 ; /* 0x28A1 */ public static final int ERROR_DB_NO_RESULT= 10402 ; /* 0x28A2 */ public static final int ERROR_DB_INVALID_USER= 10403 ; /* 0x28A3 */ public static final int ERROR_DB_INVALID_PWD= 10404 ; /* 0x28A4 */ public static final int ERROR_DB_CONNECT= 10405 ; /* 0x28A5 */ public static final int ERROR_DB_INVALID_SQL= 10406 ; /* 0x28A6 */ public static final int ERROR_DB_INVALID_APPID= 10407 ; /* 0x28A7 */ /* Error codes of Resource 10500(0x2904)*/ public static final int ERROR_RES_GENERAL= 10500 ; /* 0x2904 */ public static final int ERROR_RES_LOAD = 10501 ; /* 0x2905 */ /* Load resource */ public static final int ERROR_RES_FREE = 10502 ; /* 0x2906 */ /* Free resource */ public static final int ERROR_RES_MISSING = 10503 ; /* 0x2907 */ /* Resource File Missing */ public static final int ERROR_RES_INVALID_NAME = 10504 ; /* 0x2908 */ /* Invalid resource file name */ public static final int ERROR_RES_INVALID_ID = 10505 ; /* 0x2909 */ /* Invalid resource ID */ public static final int ERROR_RES_INVALID_IMG = 10506 ; /* 0x290A */ /* Invalid resource image pointer */ public static final int ERROR_RES_WRITE= 10507 ; /* 0x290B */ /* Write read-only resource */ public static final int ERROR_RES_LEAK = 10508 ; /* 0x290C */ /* Resource leak out */ public static final int ERROR_RES_HEAD = 10509 ; /* 0x290D */ /* Resource head currupt */ public static final int ERROR_RES_DATA = 10510 ; /* 0x290E */ /* Resource data currupt */ public static final int ERROR_RES_SKIP = 10511 ; /* 0x290F */ /* Resource file skipped */ /* Error codes of TTS 10600(0x2968)*/ public static final int ERROR_TTS_GENERAL= 10600 ; /* 0x2968 */ public static final int ERROR_TTS_TEXTEND = 10601 ; /* 0x2969 */ /* Meet text end */ public static final int ERROR_TTS_TEXT_EMPTY= 10602 ; /* 0x296A */ /* no synth text */ /* Error codes of Recognizer 10700(0x29CC) */ public static final int ERROR_REC_GENERAL= 10700 ; /* 0x29CC */ public static final int ERROR_REC_INACTIVE= 10701 ; /* 0x29CD */ public static final int ERROR_REC_GRAMMAR_ERROR= 10702 ; /* 0x29CE */ public static final int ERROR_REC_NO_ACTIVE_GRAMMARS = 10703 ; /* 0x29CF */ public static final int ERROR_REC_DUPLICATE_GRAMMAR= 10704 ; /* 0x29D0 */ public static final int ERROR_REC_INVALID_MEDIA_TYPE = 10705 ; /* 0x29D1 */ public static final int ERROR_REC_INVALID_LANGUAGE= 10706 ; /* 0x29D2 */ public static final int ERROR_REC_URI_NOT_FOUND= 10707 ; /* 0x29D3 */ public static final int ERROR_REC_URI_TIMEOUT= 10708 ; /* 0x29D4 */ public static final int ERROR_REC_URI_FETCH_ERROR= 10709 ; /* 0x29D5 */ /* Error codes of Speech Detector 10800(0x2A30) */ public static final int ERROR_EP_GENERAL= 10800 ; /* 0x2A30 */ public static final int ERROR_EP_NO_SESSION_NAME= 10801 ; /* 0x2A31 */ public static final int ERROR_EP_INACTIVE = 10802 ; /* 0x2A32 */ public static final int ERROR_EP_INITIALIZED = 10803 ; /* 0x2A33 */ /* Error codes of TUV */ public static final int ERROR_TUV_GENERAL= 10900 ; /* 0x2A94 */ public static final int ERROR_TUV_GETHIDPARAM = 10901 ; /* 0x2A95 */ /* Get Busin Param huanid*/ public static final int ERROR_TUV_TOKEN= 10902 ; /* 0x2A96 */ /* Get Token */ public static final int ERROR_TUV_CFGFILE= 10903 ; /* 0x2A97 */ /* Open cfg file */ public static final int ERROR_TUV_RECV_CONTENT = 10904 ; /* 0x2A98 */ /* received content is error */ public static final int ERROR_TUV_VERFAIL = 10905 ; /* 0x2A99 */ /* Verify failure */ /* Error codes of IMTV */ public static final int ERROR_LOGIN_SUCCESS= 11000 ; /* 0x2AF8 */ /* 成功 */ public static final int ERROR_LOGIN_NO_LICENSE = 11001 ; /* 0x2AF9 */ /* 试用次数结束,用户需要付费 */ public static final int ERROR_LOGIN_SESSIONID_INVALID = 11002 ; /* 0x2AFA */ /* SessionId失效,需要重新登录通行证 */ public static final int ERROR_LOGIN_SESSIONID_ERROR= 11003 ; /* 0x2AFB */ /* SessionId为空,或者非法 */ public static final int ERROR_LOGIN_UNLOGIN = 11004 ; /* 0x2AFC */ /* 未登录通行证 */ public static final int ERROR_LOGIN_INVALID_USER = 11005 ; /* 0x2AFD */ /* 用户ID无效 */ public static final int ERROR_LOGIN_INVALID_PWD = 11006 ; /* 0x2AFE */ /* 用户密码无效 */ public static final int ERROR_LOGIN_SYSTEM_ERROR= 11099 ; /* 0x2B5B */ /* 系统错误 */ /* Error codes of HCR */ public static final int ERROR_HCR_GENERAL= 11100 ; public static final int ERROR_HCR_RESOURCE_NOT_EXIST = 11101 ; public static final int ERROR_HCR_CREATE= 11102 ; public static final int ERROR_HCR_DESTROY= 11103 ; public static final int ERROR_HCR_START= 11104 ; public static final int ERROR_HCR_APPEND_STROKES= 11105 ; public static final int ERROR_HCR_GET_RESULT= 11106 ; public static final int ERROR_HCR_SET_PREDICT_DATA= 11107 ; public static final int ERROR_HCR_GET_PREDICT_RESULT = 11108 ; /* Error codes of http 12000(0x2EE0) */ public static final int ERROR_HTTP_BASE= 12000 ; /* 0x2EE0 */ /*Error codes of ISV */ public static final int ERROR_ISV_NO_USER = 13000 ; /* 32C8 */ /* the user doesn't exist */ /* Error codes of Lua scripts */ public static final int ERROR_LUA_BASE= 14000 ; /* 0x36B0 */ public static final int ERROR_LUA_YIELD= 14001 ; /* 0x36B1 */ public static final int ERROR_LUA_ERRRUN= 14002 ; /* 0x36B2 */ public static final int ERROR_LUA_ERRSYNTAX= 14003 ; /* 0x36B3 */ public static final int ERROR_LUA_ERRMEM= 14004 ; /* 0x36B4 */ public static final int ERROR_LUA_ERRERR= 14005 ; /* 0x36B5 */ } |
嫌复制粘贴麻烦的可以点击下面的链接下载:
Msp_errors.java: http://www.t00y.com/file/8170772
QTSR.java: http://www.t00y.com/file/8170775
作者:黄云坤
出处:http://www.huangyunkun.com/
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
支持:
新浪微博
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库