import java.io.*;

public class ReadMAC
{
public static String physicalAddress = "read MAC error!";

public ReadMAC()
{
}

public static String checkPhysicalAddress()
{

try
{
String line;
Process process = Runtime.getRuntime().exec("cmd /c ipconfig /all");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));

while ( (line=bufferedReader.readLine()) != null)
{

if(line.indexOf("Physical Address. . . . . . . . . :") != -1)
{

if(line.indexOf(":") != -1)
{
physicalAddress = line.substring(line.indexOf(":")+2);
break; //找到MAC,推出循環(huán)
}
}
}
process.waitFor();

}catch(Exception e)
{
e.printStackTrace();
}
return physicalAddress;
}

public static void main(String[] args)
{
System.out.println("本機(jī)的MAC地址是: "+ ReadMAC.checkPhysicalAddress());
}
}
1 引言
用Java編寫(xiě)的程序,可以很方便地運(yùn)行在各種平臺(tái)的環(huán)境。但在實(shí)際的開(kāi)發(fā)過(guò)程中,有時(shí)不得不涉及一些底層的編程。比如為了防止軟件盜用,我們希望軟件只能在指定計(jì)算機(jī)上運(yùn)行,所以需要程序讀取該機(jī)區(qū)分于其它計(jì)算機(jī)的硬件特征,如MAC地址等。作為一種跨平臺(tái)語(yǔ)言,給Java語(yǔ)言提出了挑戰(zhàn)。本文正是針對(duì)該問(wèn)題,提出一種直接用純Java語(yǔ)言,讀去MAC地址的編程方法。
我們知道,在每一個(gè)Java應(yīng)用程序中都存在著一個(gè)與其運(yùn)行環(huán)境相聯(lián)系的Runtime對(duì)象。該對(duì)象可執(zhí)行外部命令、查可用內(nèi)存等。而多數(shù)操作系統(tǒng)都提供有查詢?cè)摍C(jī)MAC地址的命令。如在Microsoft的操作系統(tǒng)中,命令I(lǐng)PCONFIG等。本文的思路是在程序中運(yùn)行一個(gè)外部命令,將該命令的運(yùn)行結(jié)果作為一個(gè)流(Stream),讀取并分析之,進(jìn)而實(shí)現(xiàn)獲取MAC地址的目的。
2 Runtime類(lèi)
在每一個(gè)Java 應(yīng)用程序里面,都有惟一的一個(gè)Runtime 對(duì)象。通過(guò)這個(gè)Runtime 對(duì)象,應(yīng)用程序可以與其運(yùn)行環(huán)境發(fā)生相互作用。
一般不實(shí)例化一個(gè)Runtime對(duì)象。但是可以通過(guò)調(diào)用靜態(tài)方法Runtime.getRuntime( )而獲得對(duì)當(dāng)前Runtime對(duì)象的引用。Runtime 類(lèi)的大多數(shù)方法是實(shí)例方法。
Runtime 對(duì)象的作用主要有:執(zhí)行外部命令;返回空閑內(nèi)存;運(yùn)行垃圾回收器;加載動(dòng)態(tài)庫(kù)等。
Applets和其他不可信賴(lài)的程序由于沒(méi)有引起一個(gè)安全異常(SecurityException)而不能調(diào)用任何的Runtime方法。
下面的例子演示了怎樣使用Runtime 對(duì)象運(yùn)行一個(gè)外部命令。
以下是引用片段:
:
Process process = Runtime.getRuntime().exec("cmd.exe /c dir");
process.waitFor(); |
Runtime.getRuntime()返回當(dāng)前應(yīng)用程序的Runtime對(duì)象,該對(duì)象的exec()方法指示Java虛擬機(jī)創(chuàng)建一個(gè)子進(jìn)程執(zhí)行指定的可執(zhí)行程序,并返回與該子進(jìn)程對(duì)應(yīng)的Process對(duì)象實(shí)例。通過(guò)Process可以控制該子進(jìn)程的執(zhí)行或獲取該子進(jìn)程的信息。第二條語(yǔ)句的目的是等待子進(jìn)程完成后再往下執(zhí)行。
上面的程序在運(yùn)行時(shí)會(huì)執(zhí)行dir命令。如果在Windows95/98下,命令格式可以寫(xiě)成"command.exe /c dir"。開(kāi)關(guān)/C指明后面跟隨的字符串是命令,并在執(zhí)行命令后關(guān)閉DOS 窗口。
方法exec還可以打開(kāi)一個(gè)不可執(zhí)行的程序,但該文件存在關(guān)聯(lián)的應(yīng)用程序。以打開(kāi)一個(gè)word文檔Mydoc.doc文件為例,Java中可以有以下兩種寫(xiě)法:
以下是引用片段:
exec(""cmd /E:ON /c start MyDoc.doc"");
exec(" c:Program FilesMicrosoft Officeofficewinword.exe .mydoc.doc"); |
在第一種方式中,被執(zhí)行的命令是start Mydoc.doc,開(kāi)關(guān)E:ON 指定DOS 命令處理器允許命令擴(kuò)展,而start 命令會(huì)開(kāi)啟一個(gè)單獨(dú)的窗口執(zhí)行所提供的命令。
執(zhí)行一個(gè)有標(biāo)準(zhǔn)輸出的DOS命令,程序執(zhí)行完后往往不會(huì)自動(dòng)關(guān)閉,從而導(dǎo)致Java應(yīng)用程序阻塞在waitfor( )。導(dǎo)致該現(xiàn)象的原因可能是該命令的輸出比較多,而運(yùn)行窗口的輸出緩沖區(qū)不夠大。解決的辦法是,利用Java的Process類(lèi)提供的方法讓Java虛擬機(jī)截獲DOS運(yùn)行的標(biāo)準(zhǔn)輸出,在waitfor()命令之前讀出該緩沖區(qū)的內(nèi)容。以運(yùn)行命令dir為例,典型的程序如下:
以下是引用片段:
:
String line;
Process process = Runtime.getRuntime().exec("cmd /c dir");
BufferedReader bufferedReader = new BufferedReader ( new InputStreamReader(process.getInputStream()));
while ( (line = bufferedReader.readLine()) != -1) System. out.println(line);
process.waitFor( );
:3 Process |
Runtime.exec方法創(chuàng)建一個(gè)本機(jī)進(jìn)程,并返回 Process 子類(lèi)的一個(gè)實(shí)例,該實(shí)例可用來(lái)控制進(jìn)程并獲取相關(guān)信息。
抽象類(lèi)Process封裝了一個(gè)進(jìn)程(process),一個(gè)正在執(zhí)行的程序。它主要被當(dāng)作由Runtime類(lèi)中的exec( )方法所創(chuàng)建的對(duì)象的類(lèi)型的超類(lèi)。在抽象類(lèi)Process中,主要包含了如下一些抽象方法。
InputStream getInputStream( ):返回一個(gè)從進(jìn)程的out輸出流中讀輸入的輸入流。
OutputStream getOutputStream( ):返回一個(gè)從進(jìn)程的in輸入流中寫(xiě)輸出的輸出流。
int waitFor( ) throws InterruptedException:返回由進(jìn)程返回的退出碼。這個(gè)方法直到調(diào)用它的進(jìn)程中止,才會(huì)返回。
4 程序編寫(xiě)
我們先來(lái)分析ipconfig/all的輸出格式:
從圖1中我們看到MAC地址包含的行為:“ Physical Address. . . . . . . . . : 00-10-DC-A9-0B-2C”。為了找到MAC地址,我們一行一行讀取字符,只要找到字符串“ Physical Address. . . . . . . . . :”,就可以找到MAC地址了。下面是實(shí)現(xiàn)的程序片段:
以下是引用片段:
:
Process process = Runtime.getRuntime().exec("cmd /c ipconfig /all");
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader (process.getInputStream()));
while ( (line=bufferedReader.readLine()) != null){
if(line.indexOf("Physical Address. . . . . . . . . :") != -1){
if(line.indexOf(":") != -1){
physicalAddress = line.substring(line.indexOf(":")+2);
: |
在上面的程序中,為了讀取命令輸出的字符,利用子進(jìn)程process生成了一個(gè)數(shù)據(jù)流緩沖區(qū)。
5 結(jié)束語(yǔ)
作為一個(gè)跨平臺(tái)語(yǔ)言,編寫(xiě)的JAVA程序一般都與硬件無(wú)關(guān),因而能運(yùn)行在不同的操作系統(tǒng)環(huán)境。但這給編寫(xiě)底層相關(guān)的程序時(shí)帶來(lái)不便。
Java的應(yīng)用程序都存在著一個(gè)與其運(yùn)行環(huán)境相聯(lián)系的Runtime對(duì)象,利用該對(duì)象可執(zhí)行外部命令,在WindowsXP/NT/2000環(huán)境中的命令I(lǐng)PCONFIG的輸出包含有MAC地址。本文編寫(xiě)的Java程序,執(zhí)行外部命令I(lǐng)PCONFIG,并通過(guò)分析該命令的輸入流而獲得本機(jī)的MAC地址。由于IPCONFIG命令是操作系統(tǒng)命令,所以該方法既方便又可靠。
以上討論的程序適合于Windows XP/NT/2000操作系統(tǒng),因?yàn)樗腔谠摬僮飨到y(tǒng)的命令I(lǐng)PCONFIG格式的。由于不同操作系統(tǒng)讀取MAC地址的命令、以及命令輸出格式的不同,所以該程序不能直接運(yùn)用到其它系統(tǒng)。要移植到其它系統(tǒng)只需針對(duì)命令的輸出格式稍作修改。
posted on 2009-11-06 17:21
junly 閱讀(459)
評(píng)論(0) 編輯 收藏 所屬分類(lèi):
java