前言
有时我们因为软件授权或者其它需要获取主机唯一标识而需要获取用户主机的MAC
地址,而本文则将介绍如何通过Java
来实现跨平台获取MAC
地址的两种方法,同时具体的代码也已上传到GitHub。
如果不希望将 GitHub 的代码克隆到本地查看,但是又无法忍受在网页查看代码时无限的链接嵌套,可以尝试在网址的 GitHub 单词后加上 1s,即可在网页中有通过 VSCode 查看代码的效果,例如本文是 https://github1s.com/zhangjiwei1221/blog/blob/master/mac,如下图所示:
使用 NetworkInterface 类
首先介绍如何通过Java
的NetworkInterface
类的API
来获取本机MAC
地址的方法,首先展示代码:
/**
* 获取 mac 地址工具类 v1 版
*
* @date 2021/5/13
* @author zjw
*/publicclassMacUtil{publicstaticvoidmain(String[] args){getMac().forEach(System.out::println);}/**
* 获取本机 mac 地址集合
*
* @return mac 地址集合
*/publicstaticList<String>getMac(){List<String> list=newArrayList<>();try{Enumeration<NetworkInterface> networkInterfaces=NetworkInterface.getNetworkInterfaces();while(networkInterfaces.hasMoreElements()){NetworkInterface networkInterface= networkInterfaces.nextElement();Optional.ofNullable(networkInterface.getHardwareAddress()).ifPresent(mac-> list.add(format(mac)));}}catch(Exception e){
e.printStackTrace();}return list;}/**
* 将 mac 字节数组格式化为全大写并且使用 - 作为分隔符的字符串
*
* @param mac 获取到的 mac 字节数组
*
* @return 格式化后的 mac 地址
*/privatestaticStringformat(byte[] mac){StringBuilder sb=newStringBuilder();for(byte b: mac){
sb.append(String.format("%02X", b)).append("-");}
sb.deleteCharAt(sb.length()-1);return sb.toString();}}
通过以上代码理论上即可获取本机所有的MAC
地址,此外通过format
方法可以将获取到的MAC
地址统一处理成XX-XX-XX-XX-XX-XX
的格式,这里之所以说是理论上,是因为我曾经在别人的苹果电脑上运行,结果并没有得到所有MAC
地址(没有得到执行ifconfig -a
得到的所有MAC
地址,而且还会出现llw0
这个网络的MAC
地址一直变动),但是我在本地的虚拟机中运行苹果时却也是正常,由于我自己没有苹果电脑,所以暂时也不清楚具体的原因,如果有知道的小伙伴,欢迎留言,提前感谢啦~~~
执行命令行获取
正如在上一部分中提到的,在某些情况下使用NetworkInterface
类并不能获取到本机所有的MAC
地址,甚至还可能出现动态变化的情况(暂时不清楚原因)。因此,在这种情况下只能通过Java
的Runtime
类的exec
方法直接执行命令了,当然在大多数情况下还是建议使用NetworkInterface
类,不仅方便,而且万一以后修复了上面的bug(不知道算不算是bug,还是我个人的问题),不对上述代码做任何变动就可以得到自己执行命令的效果了,说了那么多,先看看如果通过自己执行命令获取本机的所有MAC
地址吧,先直接展示代码:
/**
* 获取 mac 地址工具类 v2 版
*
* @date 2021/5/13
* @author zjw
*/publicclassMacUtil{privatestaticfinalString WIN_PREFIX="win";privatestaticfinalString OS_NAME_PROPERTY="os.name";privatestaticfinalString WIN_COMMAND="ipconfig /all";privatestaticfinalString UNIX_COMMAND="/sbin/ifconfig -a";privatestaticfinalString MAC_REGEX="(([a-f0-9]{2}-){5}|([a-f0-9]{2}:){5})[a-f0-9]{2}";privatestaticfinalPattern pattern=Pattern.compile(MAC_REGEX,Pattern.CASE_INSENSITIVE);publicstaticvoidmain(String[] args){getMac().forEach(System.out::println);}/**
* 根据不同操作系统执行不同命令
* 获取本机 mac 地址集合
*
* @return mac 地址集合
*/privatestaticList<String>getMac(){try{String osName=System.getProperty(OS_NAME_PROPERTY).toLowerCase();if(osName.startsWith(WIN_PREFIX)){returngetMacByCommand(WIN_COMMAND);}returngetMacByCommand(UNIX_COMMAND);}catch(Exception e){
e.printStackTrace();}returnCollections.emptyList();}/**
* 通过正则表达式提取执行命令得到的结果集中的 mac 地址
* 并调整得到的 mac 地址的格式
*
* @param command 查看网络信息的命令
*
* @return mac 地址集合
*/privatestaticList<String>getMacByCommand(String command)throwsIOException{List<String> macList=newArrayList<>();List<String> strList=execCommand(command);for(String str: strList){Matcher matcher= pattern.matcher(str);if(matcher.find()&& matcher.end()== str.length()){
macList.add(matcher.group().replace(":","-").toUpperCase());}}return macList;}/**
* 执行命令并得到结果的每一行组成的字符串数组
*
* @param command 查看网络信息的命令
*
* @return 执行命令返回的所有数据行
*/privatestaticList<String>execCommand(String command)throwsIOException{List<String> strList=newArrayList<>();Process process=Runtime.getRuntime().exec(command);try(BufferedReader br=newBufferedReader(newInputStreamReader(process.getInputStream()))){return br.lines().collect(Collectors.toList());}catch(Exception e){
e.printStackTrace();}
process.destroy();return strList;}}
以上便是通过执行命令并结合正则表达式获取本机所有MAC
地址的方法,代码如有错误不当之处,欢迎留言指正。
总结
本文简单介绍了两种跨平台获取MAC
地址的方法,不过仍然存在一些尚未解决的问题,希望有了解的朋友能够留言告诉我,感激不尽!