
摘要:MATLAB中封装了种类齐全、功能强大的函数和工具箱等,有时在Java工程中编写可能花费很多精力,为此可直接将MATLAB中编写好的功能模块打包成jar包,在Java中进行引用。本文详细介绍如何将已编写好的m文件打包成jar包的软件安装以及打包具体步骤,然后介绍了如何在Java中调用打包好的jar包并给出具体代码。其要点如下:
由于MATLAB在数值计算方面的高性能,大大提高了科研和工作的效率,已逐渐发展成一个具有较高通用性的、带有众多实用工具的运算操作平台。MATLAB中封装了种类齐全、功能强大的函数和工具箱等,MATLAB与Java的混合编程能帮助我们减少许多编写代码的时间,特别是在已经编写好MATLAB程序,需要用Java进行封装形成一个可运行的独立程序的时候,这样做则方便得多。要实现这个功能则需要安装并配置好Java环境以及MATLAB软件,利用MATLAB的编译功能打包jar,然后在Java工程中进行调用。以下是详细介绍。
首先当然需要安装好MATLAB,已经成功安装并解决证书问题的可以跳过这一步骤。MATLAB R2014a下载与安装网上用很多教程,也可以通过我的百度网盘下载,里面有安装及key证书说明。由于某些原因这种分享容易失效,请关注文末的本人公众号“AI技术研究与分享”,并回复关键字“MATLAB R2014a”获取:
MATLAB打包成jar包时需要调用javac生成class文件,因此我们需要安装JDK。由于编译过程中的可能报错,大多是由于MATLAB的版本与JDK的版本不一致所导致的,根据情况需要降低JDK版本,经试验,MATLAB 2015a、2014a 适用jdk1.7 ,MATLAB 2013a 适用jdk1.6,其他的未测试(jdk1.8可能报错)。
jdk的安装步骤网上有许多教程可供参考,限于篇幅,这里就不作介绍了。值得注意的是,环境变量务必配置正确,否则后面的编译过程极易报错。
这里我以一个简单的m程序打包作为例子,介绍其详细步骤供参考。
一、在MATLAB中编写m文件(写成m函数形式)并调试通过,我写好的MATLAB程序如下图所示


要打包的函数是test.m,其中调用了maxMum.m函数,上面的代码如下
test.m文件:
function [Mean,Sum,Std,result]=test(input1,input2)
Mean=mean(input1);
Sum=sum(input1);
Std=std(input1);
result=maxMum(input1,input2);
end
maxMum.m文件:
function result=maxMum(a,b)
Maxb=max(max(b));
result=double(a>Maxb);
end
二、在MATLAB命令行窗口输入deploytool并回车,在跳出的编译器选择界面选择Library Compiler 如下图所示
三、弹出的编辑界面如下图

1.在界面1号框内选择Java Package;
2.点击2号框内的加号选择要打包的文件;
3.在3号框内设置包名;
4.在4号框内修改类名及方法名(为了方便调用,建议修改默认的类名)
5.第5、6号框内分别是运行时所需要的文件和一起安装的文件,一般会系统自动检测并添加进去;
6.点击7号框内的Package按钮进行打包,界面如下

四、等待打包完成,此时会出现三个文件夹如下所示
上面都完成后,若无错误,将默认在当前m文件所在目录生成以包名命名的文件夹,在for_testing文件夹内有我们需要的jar文件。
打包完成我们还是有必要了解下生成的这几个文件,for_testing文件夹中除了jar文件还有m文件转换的对应java程序,例如打开for_testing文件夹下的test(先前编译时自设的包名)文件夹,就有我们想要的Test类的java文件,打开可查看代码以及调用方式。
除了上述方式可以查看调用方法,还有更简单的方式。打开在生成文件夹下路径为for_redistribution_files_only\doc\html\index.html文件,可以查看test所有重载函数的使用说明,如下
这里最适合的方法是红色框圈出的,该方法的调用说明如下
解读:
参数nargout: 第一个输入参数是整形,表示的是输出的个数,在本例中有四个输出(Mean,Sum,Std,result),因此设置为4;
参数rhs: 与M函数对应的输入参数,为Object类型,本例中有两个输入参数(input1,input2)。虽说Object类是Java中其他所有类的基类,这里的两个参数是数组、int型等类型都是可以的,但建议使用MWNumericArray类型,后面详细介绍;
函数返回值: 一个包含nargout个返回参数的Object类型数组,每个元素对应M函数中的每个输出结果。
有了以上的基本认识,终于可以开始正式使用jar包了。
一、新建java工程,新建一个java程序用于使用jar包,添加必要的Jar包
因为是MATLAB打包的jar包,需要依赖MATLAB中的相关函数,所以需要的Jar包除了我们前面生成的test.jar 包还要 javabuilder.jar 包,它的路径在MATLAB的安装目录下的toolbox\javabuilder\jar\javabuilder.jar ,可以将两个jar包拷出来放到一个自建的文件夹中,方便下面添加jar包。
1.在新建的工程文件夹右击选择Properties进入属性界面
2.选择左侧Java Build Path(1号框),点击右边的Libraries(2号框),点击Add External JARs(3号框),找到上面说的javabuilder.jar和test.jar包的路径将两个包添加进库中(4号框)
3.点击右下角OK按钮,完成jar包添加。
二、在新建的java程序中导入包,即输入以下代码
import com.mathworks.toolbox.javabuilder.*;
import test.Test;//此处的test为前面编译时设置的包名,Test为选定的类名
三、在主方法中调用函数,输入如下代码
import java.util.ArrayList;
import com.mathworks.toolbox.javabuilder.*;
import test.Test;//此处的test为前面的包名,Test为选定的类名
/** 在java中调用matlab转的jar包示例
* @author W.X
* @version 1.0 10/5/2018
* */
public class Main {
public static void main(String[] args) {
MWNumericArray input1 = null;// 输入参数一
MWNumericArray input2 = null;// 输入参数二
Object[] result = null; // 输出结果
Test test = null;
try {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 15; i++){
list.add(i+1);
}
// 参数一为一个从1到15的数组
input1 = new MWNumericArray(list.toArray(),
MWClassID.DOUBLE);
// 参数二为10
input2 = new MWNumericArray(Double.valueOf(10),
MWClassID.DOUBLE);
test = new Test();// 实例化
result = test.test(4, input1,input2);// 调用test方法
double Mean=((MWNumericArray) result[0]).getDouble(1);// 第一个输出
double Sum=((MWNumericArray) result[1]).getDouble(1); // 第二个输出
double Std=((MWNumericArray) result[2]).getDouble(1); // 第三个输出
double[] R =new double[15]; // 第四个输出,为一个数组
for(int i=0;i<15;i++){
R[i]=((MWNumericArray) result[3]).getDouble(i+1); // 从result中依次取出第四个输出
System.out.println(R[i]);
}
// 打印结果
System.out.println(Mean);
System.out.println(Sum);
System.out.println(Std);
}
catch (MWException e) {
e.printStackTrace();
}
finally {
MWArray.disposeArray(input1);
MWArray.disposeArray(input2);
MWArray.disposeArray(result);
test.dispose();
}
}
}
代码说明:
代码看似较长,其实非常简单。代码11-14行声明了所有参数及对象,17-26行是对两个输入参数赋值。对于MATLAB来说原m函数中的两个输入参数可以是数组也可以是某个数,在java中调用时同样如此,作为示例这里我的第一个参数是个数组,第二个参数是一个实数。数组采用的是ArrayList型,实数是double型,两个参数都转化成MWNumericArray的类型进行调用。
代码第30行,调用test方法得到结果,结果保存在result的Object数组中。第32-34行依次从result的每个元素中取出第一、二、三个结果(Mean、Sum、Std),由于result是Object型而我们往往需要的是double型的结果数据,因此需要进行类型转换转换为MWNumericArray型然后引用其getDouble方法转化成double。
代码第36-40行,取出第四个结果并放在double型数组R中,由于第四个结果是数组型所以取出时需要借助循环结构依次赋值取出。
至此从编译至调用的步骤完成,许多MATLAB中好用的m函数在java中也能轻松使用了,不得不说使用MATLAB打包成jar确实为一个简单粗暴又好用的方法。但同时由于两种语言的内部差异以及其中的复杂转换使得在java中调用时运行速度减慢,如果特别在意运行速度建议还需要另做优化调整或采用纯java编写。
由于博主能力有限,博文中提及的方法与代码即使经过测试,也难免会有疏漏之处。希望您能热心指出其中的错误,以便下次修改时能以一个更完美更严谨的样子,呈现在大家面前。同时如果有更好的实现方法也请您不吝赐教。
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A
我注意到像bundler这样的项目在每个specfile中执行requirespec_helper我还注意到rspec使用选项--require,它允许您在引导rspec时要求一个文件。您还可以将其添加到.rspec文件中,因此只要您运行不带参数的rspec就会添加它。使用上述方法有什么缺点可以解释为什么像bundler这样的项目选择在每个规范文件中都需要spec_helper吗? 最佳答案 我不在Bundler上工作,所以我不能直接谈论他们的做法。并非所有项目都checkin.rspec文件。原因是这个文件,通常按照当前的惯例,只