隨筆 - 63  文章 - 0  trackbacks - 0
          <2025年5月>
          27282930123
          45678910
          11121314151617
          18192021222324
          25262728293031
          1234567

          常用鏈接

          留言簿(2)

          隨筆分類

          隨筆檔案

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          1. package cn.edu.tongji.cims.wade.system;   
          2.   
          3. import java.io.*;   
          4.   
          5. public class FileOperate {   
          6.   public FileOperate() {   
          7.   }   
          8.   
          9.   /**  
          10.    * 新建目錄  
          11.    * @param folderPath String 如 c:/fqf  
          12.    * @return boolean  
          13.    */  
          14.   public void newFolder(String folderPath) {   
          15.     try {   
          16.       String filePath = folderPath;   
          17.       filePath = filePath.toString();   
          18.       java.io.File myFilePath = new java.io.File(filePath);   
          19.       if (!myFilePath.exists()) {   
          20.         myFilePath.mkdir();   
          21.       }   
          22.     }   
          23.     catch (Exception e) {   
          24.       System.out.println("新建目錄操作出錯(cuò)");   
          25.       e.printStackTrace();   
          26.     }   
          27.   }   
          28.   
          29.   /**  
          30.    * 新建文件  
          31.    * @param filePathAndName String 文件路徑及名稱 如c:/fqf.txt  
          32.    * @param fileContent String 文件內(nèi)容  
          33.    * @return boolean  
          34.    */  
          35.   public void newFile(String filePathAndName, String fileContent) {   
          36.   
          37.     try {   
          38.       String filePath = filePathAndName;   
          39.       filePath = filePath.toString();   
          40.       File myFilePath = new File(filePath);   
          41.       if (!myFilePath.exists()) {   
          42.         myFilePath.createNewFile();   
          43.       }   
          44.       FileWriter resultFile = new FileWriter(myFilePath);   
          45.       PrintWriter myFile = new PrintWriter(resultFile);   
          46.       String strContent = fileContent;   
          47.       myFile.println(strContent);   
          48.       resultFile.close();   
          49.   
          50.     }   
          51.     catch (Exception e) {   
          52.       System.out.println("新建目錄操作出錯(cuò)");   
          53.       e.printStackTrace();   
          54.   
          55.     }   
          56.   
          57.   }   
          58.   
          59.   /**  
          60.    * 刪除文件  
          61.    * @param filePathAndName String 文件路徑及名稱 如c:/fqf.txt  
          62.    * @param fileContent String  
          63.    * @return boolean  
          64.    */  
          65.   public void delFile(String filePathAndName) {   
          66.     try {   
          67.       String filePath = filePathAndName;   
          68.       filePath = filePath.toString();   
          69.       java.io.File myDelFile = new java.io.File(filePath);   
          70.       myDelFile.delete();   
          71.   
          72.     }   
          73.     catch (Exception e) {   
          74.       System.out.println("刪除文件操作出錯(cuò)");   
          75.       e.printStackTrace();   
          76.   
          77.     }   
          78.   
          79.   }   
          80.   
          81.   /**  
          82.    * 刪除文件夾  
          83.    * @param filePathAndName String 文件夾路徑及名稱 如c:/fqf  
          84.    * @param fileContent String  
          85.    * @return boolean  
          86.    */  
          87.   public void delFolder(String folderPath) {   
          88.     try {   
          89.       delAllFile(folderPath); //刪除完里面所有內(nèi)容   
          90.       String filePath = folderPath;   
          91.       filePath = filePath.toString();   
          92.       java.io.File myFilePath = new java.io.File(filePath);   
          93.       myFilePath.delete(); //刪除空文件夾   
          94.   
          95.     }   
          96.     catch (Exception e) {   
          97.       System.out.println("刪除文件夾操作出錯(cuò)");   
          98.       e.printStackTrace();   
          99.   
          100.     }   
          101.   
          102.   }   
          103.   
          104.   /**  
          105.    * 刪除文件夾里面的所有文件  
          106.    * @param path String 文件夾路徑 如 c:/fqf  
          107.    */  
          108.   public void delAllFile(String path) {   
          109.     File file = new File(path);   
          110.     if (!file.exists()) {   
          111.       return;   
          112.     }   
          113.     if (!file.isDirectory()) {   
          114.       return;   
          115.     }   
          116.     String[] tempList = file.list();   
          117.     File temp = null;   
          118.     for (int i = 0; i < tempList.length; i++) {   
          119.       if (path.endsWith(File.separator)) {   
          120.         temp = new File(path + tempList[i]);   
          121.       }   
          122.       else {   
          123.         temp = new File(path + File.separator + tempList[i]);   
          124.       }   
          125.       if (temp.isFile()) {   
          126.         temp.delete();   
          127.       }   
          128.       if (temp.isDirectory()) {   
          129.         delAllFile(path+"/"+ tempList[i]);//先刪除文件夾里面的文件   
          130.         delFolder(path+"/"+ tempList[i]);//再刪除空文件夾   
          131.       }   
          132.     }   
          133.   }   
          134.   
          135.   /**  
          136.    * 復(fù)制單個(gè)文件  
          137.    * @param oldPath String 原文件路徑 如:c:/fqf.txt  
          138.    * @param newPath String 復(fù)制后路徑 如:f:/fqf.txt  
          139.    * @return boolean  
          140.    */  
          141.   public void copyFile(String oldPath, String newPath) {   
          142.     try {   
          143.       int bytesum = 0;   
          144.       int byteread = 0;   
          145.       File oldfile = new File(oldPath);   
          146.       if (oldfile.exists()) { //文件存在時(shí)   
          147.         InputStream inStream = new FileInputStream(oldPath); //讀入原文件   
          148.         FileOutputStream fs = new FileOutputStream(newPath);   
          149.         byte[] buffer = new byte[1444];   
          150.         int length;   
          151.         while ( (byteread = inStream.read(buffer)) != -1) {   
          152.           bytesum += byteread; //字節(jié)數(shù) 文件大小   
          153.           System.out.println(bytesum);   
          154.           fs.write(buffer, 0, byteread);   
          155.         }   
          156.         inStream.close();   
          157.       }   
          158.     }   
          159.     catch (Exception e) {   
          160.       System.out.println("復(fù)制單個(gè)文件操作出錯(cuò)");   
          161.       e.printStackTrace();   
          162.   
          163.     }   
          164.   
          165.   }   
          166.   
          167.   /**  
          168.    * 復(fù)制整個(gè)文件夾內(nèi)容  
          169.    * @param oldPath String 原文件路徑 如:c:/fqf  
          170.    * @param newPath String 復(fù)制后路徑 如:f:/fqf/ff  
          171.    * @return boolean  
          172.    */  
          173.   public void copyFolder(String oldPath, String newPath) {   
          174.   
          175.     try {   
          176.       (new File(newPath)).mkdirs(); //如果文件夾不存在 則建立新文件夾   
          177.       File a=new File(oldPath);   
          178.       String[] file=a.list();   
          179.       File temp=null;   
          180.       for (int i = 0; i < file.length; i++) {   
          181.         if(oldPath.endsWith(File.separator)){   
          182.           temp=new File(oldPath+file[i]);   
          183.         }   
          184.         else{   
          185.           temp=new File(oldPath+File.separator+file[i]);   
          186.         }   
          187.   
          188.         if(temp.isFile()){   
          189.           FileInputStream input = new FileInputStream(temp);   
          190.           FileOutputStream output = new FileOutputStream(newPath + "/" +   
          191.               (temp.getName()).toString());   
          192.           byte[] b = new byte[1024 * 5];   
          193.           int len;   
          194.           while ( (len = input.read(b)) != -1) {   
          195.             output.write(b, 0, len);   
          196.           }   
          197.           output.flush();   
          198.           output.close();   
          199.           input.close();   
          200.         }   
          201.         if(temp.isDirectory()){//如果是子文件夾   
          202.           copyFolder(oldPath+"/"+file[i],newPath+"/"+file[i]);   
          203.         }   
          204.       }   
          205.     }   
          206.     catch (Exception e) {   
          207.       System.out.println("復(fù)制整個(gè)文件夾內(nèi)容操作出錯(cuò)");   
          208.       e.printStackTrace();   
          209.   
          210.     }   
          211.   
          212.   }   
          213.   
          214.   /**  
          215.    * 移動(dòng)文件到指定目錄  
          216.    * @param oldPath String 如:c:/fqf.txt  
          217.    * @param newPath String 如:d:/fqf.txt  
          218.    */  
          219.   public void moveFile(String oldPath, String newPath) {   
          220.     copyFile(oldPath, newPath);   
          221.     delFile(oldPath);   
          222.   
          223.   }   
          224.   
          225.   /**  
          226.    * 移動(dòng)文件到指定目錄  
          227.    * @param oldPath String 如:c:/fqf.txt  
          228.    * @param newPath String 如:d:/fqf.txt  
          229.    */  
          230.   public void moveFolder(String oldPath, String newPath) {   
          231.     copyFolder(oldPath, newPath);   
          232.     delFolder(oldPath);   
          233.   
          234.   }   
          235. }  
          posted @ 2009-05-07 11:16 lanxin1020 閱讀(407) | 評(píng)論 (0)編輯 收藏

                  如果在Java程序中你使用Java Native Interface(JNI) 來調(diào)用某個(gè)特定平臺(tái)下的本地庫文件,你就會(huì)發(fā)現(xiàn)這個(gè)過程很單調(diào)、乏味。Jeff Friesen一直在介紹一個(gè)知名度很低的Java開源項(xiàng)目:Java Native Access---它能夠避免因使用JNI導(dǎo)致的錯(cuò)誤和乏味,同時(shí)它還能讓你通過編程的方式調(diào)用C語言庫。

                  在Java語言沒有提供必要的APIs的情況下,Java程序使用Java Native Interface (JNI)來調(diào)用特定平臺(tái)下的本地庫是必要的。例如:在Windows XP平臺(tái)中,我使用過JNI來調(diào)用通用串行總線和基于TWAIN的掃描儀器的庫;在更古老的Windows NT平臺(tái)中,調(diào)用過智能卡的庫。

                  我按照一個(gè)基本的、乏味的流程來解決這些問題:首先,我創(chuàng)建一個(gè)Java類用來載入JNI-friendly庫(這個(gè)庫能過訪問其他的庫)并且聲明這個(gè)類的本地方法。然后,在使用JDK中的javah工具為JNI-friendly庫中的函數(shù)---函數(shù)和這個(gè)類中的本地方法一一對(duì)應(yīng)---創(chuàng)建一個(gè)代理。最后,我使用C語言寫了一個(gè)庫并用C編譯器編譯了這些代碼。

                  盡管完成這些流程并不是很困難,但是寫C代碼是一個(gè)很緩慢的過程---例如: C語言中的字符串處理是通過指針來實(shí)現(xiàn)的,這會(huì)很復(fù)雜的。而且,使用JNI很容易出現(xiàn)錯(cuò)誤,導(dǎo)致內(nèi)存泄漏、很難找到程序崩潰的原因。

                  在Java開源系列的第二篇文章中,我要介紹一個(gè)更簡單、更安全的解決方法:Todd Fast and Timothy Wall的Java Native Access (JNA) 項(xiàng)目。JNA能夠讓你在Java程序中調(diào)用本地方法時(shí)避免使用C和Java Native Interface。在這篇文章中,讓我以簡要的介紹        JNA和運(yùn)行示例必需的軟件來開始下面的內(nèi)容。然后,向你展示如何使用JNA將3個(gè)Windows本地庫中的有用代碼移植到Java程序中。

          Get started with JNA(JNA入門)

          Java Native Access 項(xiàng)目 在Java.net上,你可以到這個(gè)網(wǎng)站上現(xiàn)在這個(gè)項(xiàng)目的代碼和在線幫助文檔。雖然在下載有5個(gè)相關(guān)的jar文件,在本文中你僅僅需要下載其中的jna.jar和example.jar。

          Jna.jar提供基本的、運(yùn)行這些示例文件必需的jna運(yùn)行環(huán)境。這個(gè)jna.jar文件除了有Unix、Linux、Windows和Mac OS X平臺(tái)相關(guān)的JNT-friendly本地庫外,還包含其他幾個(gè)類包。每一個(gè)本地庫都是用來訪問相對(duì)應(yīng)平臺(tái)下的本地方法的。

                  example.jar包含了不同的示例來表明JNA的用途。其中的一個(gè)例子是使用JNA來實(shí)現(xiàn)一個(gè)在不同平臺(tái)下的透明視窗技術(shù)的API。在文章最后的示例中將要展示如何使用這個(gè)API修復(fù)上個(gè)月的文章關(guān)于VerifyAge2應(yīng)用中辨認(rèn)透明效果的問題。

          獲取本地時(shí)間(Get local time)

          如果你在Java Native Access 首頁 看過“JNA如何入門”,你就會(huì)知道一個(gè)很簡單的關(guān)于調(diào)用Windows 平臺(tái)下的API函數(shù):GetSystemTime() 的JNA示例。這個(gè)不完整的例子只是展示了JNA的基本特點(diǎn)。(在例子的基礎(chǔ)上,我做了一個(gè)更完整的基于Windows的例子來介紹JNA)我在Windows平臺(tái)下完善了這個(gè)例子來介紹JNA。

          第一例子基于Windows GetLocalTime() API函數(shù)返回本地當(dāng)前的時(shí)間和日期。和GetSystemTime()不同的是,返回的時(shí)間/日期是協(xié)調(diào)通用時(shí)間(UTC)格式的,GetLocalTime()返回的時(shí)間/日期信息的格式是根據(jù)當(dāng)前時(shí)區(qū)來表示。

          在一個(gè)Java程序中使用JNA調(diào)用GetLocalTime,你需要知道這個(gè)函數(shù)所在的Windows平臺(tái)下的動(dòng)態(tài)鏈接庫(DLL)的名稱(和可能所在的地理區(qū)域)。我們發(fā)現(xiàn)GetLocalTime()和GetSystemTime在同一個(gè)DLL文件中:kernel32.dll。你還需要知道GetLocalTime()在C語言環(huán)境中的申明。申明如下Listing 1:

          Listing 1. GetLocalTime在C語言中的申明

          typedef struct
          {
             WORD wYear;
             WORD wMonth;
             WORD wDayOfWeek;
             WORD wDay;
             WORD wHour;
             WORD wMinute;
             WORD wSecond;
             WORD wMilliseconds;
          }
          SYSTEMTIME, *LPSYSTEMTIME;

          VOID GetLocalTime(LPSYSTEMTIME lpst);


          這個(gè)基于C語言的申明表明傳到這個(gè)函數(shù)的參數(shù)數(shù)目和類型。在這個(gè)例子中,只有一個(gè)參數(shù)---一個(gè)指向Windows SYSTEMTIME結(jié)構(gòu)體的指針。而且,每個(gè)結(jié)構(gòu)體成員的類型是16bit長度的無符號(hào)整型。根據(jù)這些信息,你能夠創(chuàng)建一個(gè)完全描述GetLocalTime()函數(shù)的接口,如Listing 2中所示:

          Listing 2. Kernel32.java

          // Kernel32.java

          import com.sun.jna.*;
          import com.sun.jna.win32.*;

          public interface Kernel32 extends StdCallLibrary
          {
             public static class SYSTEMTIME extends Structure
             {
                public short wYear;
                public short wMonth;
                public short wDayOfWeek;
                public short wDay;
                public short wHour;
                public short wMinute;
                public short wSecond;
                public short wMilliseconds;
             }

             void GetLocalTime (SYSTEMTIME result);
          }


          Kernel32 接口(The Kernel32 interface)

          因?yàn)镴NA使用通過一個(gè)接口來訪問某個(gè)庫中的函數(shù),Listing 2表示了一個(gè)描述GetLocalTime()的接口。根據(jù)約定,我把接口命名為Kernel32是因?yàn)镚etLocalTime()在Windows的kernel32.dll庫。

          這個(gè)接口必須繼承com.sun..jna.Library接口。因?yàn)閃indows API函數(shù)遵循stdcall調(diào)用協(xié)議(stdcall calling convention),為Windows API申明的接口也必須繼承com.sun.jna.win32. StdCallLibrary接口。因此這個(gè)接口共繼承了Library 和 com.sun.jna.win32.StdCall兩個(gè)接口。

          在前面,你已經(jīng)知道了GetLocalTime() 需要一個(gè)指向SYSTEMTIME結(jié)構(gòu)體的指針作為它唯一的參數(shù)。因?yàn)镴ava不支持指針,JNA是通過申明一個(gè)com.sun.jna.Structure的子類來代替的。根據(jù)java文檔中抽象類的概念,在參數(shù)環(huán)境中,Structure相當(dāng)于C語言的struct*。

          在SYSTEMTIME類中的字段和C結(jié)構(gòu)體中的相對(duì)應(yīng)的屬性字段的順序是一一對(duì)應(yīng)的。保證字段順序的一致性是非常重要的。例如,我發(fā)現(xiàn)交換wYear和wMonth會(huì)導(dǎo)致wYear和wMonth值互換。

          每個(gè)字段在java中是short integer類型的。按照J(rèn)NA首頁上 “默認(rèn)類型映射”章節(jié)給出的提示,這個(gè)short integer分配類型是正確。然而,我們應(yīng)該知道一個(gè)重要的區(qū)別:Windows平臺(tái)下的WORD類型等同于C語言環(huán)境中的16-bit的無符號(hào)的short integer,而java中short integer是16-bit有符號(hào)的short integer。

          一個(gè)類型映射的問題

          通過比較一個(gè)API 函數(shù)返回的整型值,你會(huì)發(fā)現(xiàn)Windows/C 語言的無符號(hào)整型和Java語言的有符號(hào)整型的JNA類型映射是有問題的。在比較的過程中,如果你不細(xì)心,那么錯(cuò)誤的執(zhí)行過程可能導(dǎo)致決定性情況。導(dǎo)致這種后果是因?yàn)橥浫魏螖?shù)值的符號(hào)位的確定是根據(jù):在無符號(hào)整型的情況下會(huì)被解釋為正號(hào),而在有符號(hào)整型的進(jìn)制中被理解為負(fù)號(hào)的。

          通過Kernel32獲取本地時(shí)間(Access the local time with Kernel32)

          JNA首頁上的GetSystemTime()示例已經(jīng)表明必須使用預(yù)先申明的接口為本地庫分配一個(gè)實(shí)例對(duì)象。你可以通過com.sun.jna.Native類中靜態(tài)公用方法loadLibrary(String name, Class interfaceClass)來完成上述的目標(biāo)。Listing 3 所示:

          Listing 3. LocalTime.java

          // LocalTime.java

          import com.sun.jna.*;

          public class LocalTime
          {
             public static void main (String [] args)
             {
                Kernel32 lib = (Kernel32) Native.loadLibrary ("kernel32",
                                                              Kernel32.class);
                Kernel32.SYSTEMTIME time = new Kernel32.SYSTEMTIME ();
                lib.GetLocalTime (time);
                System.out.println ("Year is "+time.wYear);
                System.out.println ("Month is "+time.wMonth);
                System.out.println ("Day of Week is "+time.wDayOfWeek);
                System.out.println ("Day is "+time.wDay);
                System.out.println ("Hour is "+time.wHour);
                System.out.println ("Minute is "+time.wMinute);
                System.out.println ("Second is "+time.wSecond);
                System.out.println ("Milliseconds are "+time.wMilliseconds);
             }
          }


          Listing 3 執(zhí)行Kernel32 lib = (Kernel32) Native.loadLibrary ("kernel32", Kernel32.class);來分配一個(gè)Kernel32實(shí)例對(duì)象并且裝載kernel32.dll。因?yàn)閗ernel32.dll是Windows平臺(tái)下標(biāo)準(zhǔn)的dll文件,所以不要指定訪問這個(gè)庫的路徑。然而,如果找不到這個(gè)dll文件,loadLibrary()會(huì)拋出一個(gè)UnsatisfiedLinkError異常。

          Kernel32.SYSTEMTIME time = new Kernel32.SYSTEMTIME ();創(chuàng)建了一個(gè)SYSTEMTIME結(jié)構(gòu)體的示例。初始化后下面是lib.GetLocalTime (time);,這句話使用本地的時(shí)間/日期來給這個(gè)實(shí)例賦值。幾個(gè)System.out.println()語句是輸出這些值。

          編譯和運(yùn)行這個(gè)應(yīng)用(Compile and run the application)

          這部分很容易。假設(shè)jna.jar、Kernel32.java和LocalTime.java是放在當(dāng)前文件夾中,調(diào)用java –cp jna.jar;. LocalTime.java來編譯這個(gè)應(yīng)用的源代碼。如果在Windows平臺(tái)下,調(diào)用invoke java –cp jna.jar;. LocalTime 來運(yùn)行這個(gè)應(yīng)用。你可以得到類似與Listing 4的輸出結(jié)果:

          Listing 4. 從LocalTime.java生成的輸出

          Year is 2007
          Month is 12
          Day of Week is 3
          Day is 19
          Hour is 12
          Minute is 35
          Second is 13
          Milliseconds are 156


          獲取操縱桿信息(Accessing joystick device info)

          上面的例子已經(jīng)介紹了JNA,但是這個(gè)獲取本地時(shí)間和日期的例子并沒有很好的利用這個(gè)技術(shù),甚至也沒有體現(xiàn)JNI的價(jià)值。Java語言中的System.currentTimeMillis()函數(shù)已經(jīng)以毫秒的格式返回了這些信息。因?yàn)镴ava語言沒有為游戲控制器提供API,所以獲取操縱桿的信息更適合JNA的使用。

          例如,你要構(gòu)建一個(gè)平臺(tái)無關(guān)的Java庫,而且這些庫使用JNA調(diào)用Linux, Mac OS X, Windwos和Unix平臺(tái)中本地的操縱桿API。為了簡潔和方便起見,這個(gè)例子僅僅是調(diào)用Windows平臺(tái)下的操縱桿API。而且我將重點(diǎn)介紹這個(gè)API很小的一部分。

          類似GetLocalTime(),第一步是辨別出操作桿API的DLL,這個(gè)DLL是winmm.dll,和kernel32.dll在同一個(gè)文件夾中,它包含了操作桿的API和其他的多媒體APIs。還需知道要被使用的操作桿函數(shù)基于C語言的聲明。這些函數(shù)聲明已經(jīng)在Listing 5中列出來了。

          Listing 5. C-based declarations for some Joystick API functions

          #define MAXPNAMELEN 32

          typedef struct
          {
             WORD  wMid;                  // manufacturer identifier
             WORD  wPid;                  // product identifier
             TCHAR szPname  MAXPNAMELEN ; // product name
             UINT  wXmin;                 // minimum x position
             UINT  wXmax;                 // maximum x position
             UINT  wYmin;                 // minimum y position
             UINT  wYmax;                 // maximum y position
             UINT  wZmin;                 // minimum z position
             UINT  wZmax;                 // maximum z position
             UINT  wNumButtons;           // number of buttons
             UINT  wPeriodMin;            // smallest supported polling interval when captured
             UINT  wPeriodMax;            // largest supported polling interval when captured
          }
          JOYCAPS, *LPJOYCAPS;

          MMRESULT joyGetDevCaps(UINT IDDevice, LPJOYCAPS lpjc, UINT cbjc);

          UINT joyGetNumDevs(VOID);


          操作桿API的函數(shù)(Functions of the Joystick API)

          在Windows平臺(tái)下是通過以joy作為函數(shù)名開始的函數(shù)以及被各種函數(shù)調(diào)用的結(jié)構(gòu)體來實(shí)現(xiàn)操作桿API的。例如,joyGetNumDevs()返回的是這個(gè)平臺(tái)下支持的操作桿設(shè)備最多的數(shù)目;joyGetDevCaps()返回的是每個(gè)連接上的操縱桿的質(zhì)量。

          joyGetDevCaps()函數(shù)需要3個(gè)參數(shù):
          * 處在0到j(luò)oyGetNumDevs()-1之間的操作桿ID
          * 保存返回的質(zhì)量信息的JOYCAPS結(jié)構(gòu)體的地址
          * JOYCAPS結(jié)構(gòu)體的字節(jié)大小
          雖然它的結(jié)果不同,這個(gè)函數(shù)返回的是一個(gè)32位的無符號(hào)整型結(jié)果,而且0表示一個(gè)已經(jīng)連接的操縱桿。

          JOYCAPS結(jié)構(gòu)體有3種類型。Windows平臺(tái)下的WORD(16位無符號(hào)短整型)類型對(duì)應(yīng)的是Java語言中16位有符號(hào)短整型。除此之外,Windows下的UINT(32位無符號(hào)整型)類型是和Java語言中32位有符號(hào)整型相對(duì)應(yīng)的。而Windows平臺(tái)上的text character就是TCHAR類型。

          微軟通過TCHAR類型使開發(fā)人員能夠從ASCII類型的函數(shù)參數(shù)平滑的轉(zhuǎn)移到Unicode字符類型的函數(shù)參數(shù)上。而且,擁有text類型參數(shù)的函數(shù)的實(shí)現(xiàn)是通過宏轉(zhuǎn)變?yōu)閷?duì)應(yīng)的ASCII或者wide-character的函數(shù)。例如,joyGetDevCaps()是一個(gè)對(duì)應(yīng)joyGetDevCapsA() 和 joyGetDevCapsW()的宏。

          使用TCHAR(Working with TCHAR)

          使用TCHAR和將TCHAR轉(zhuǎn)變的宏會(huì)導(dǎo)致基于C語言的申明向基于JNA接口的轉(zhuǎn)換
          變得有點(diǎn)復(fù)雜—你在使用ASCII或者wide-character版本的操縱桿函數(shù)嗎?兩種版本都在如下的接口中展示了:

          Listing 6. WinMM.java

          // WinMM.java

          import com.sun.jna.*;
          import com.sun.jna.win32.*;

          public interface WinMM extends StdCallLibrary
          {
             final static int JOYCAPSA_SIZE = 72;

             public static class JOYCAPSA extends Structure
             {
                public short wMid;
                public short wPid;
                public byte szPname [] = new byte [32];
                public int wXmin;
                public int wXmax;
                public int wYmin;
                public int wYmax;
                public int wZmin;
                public int wZmax;
                public int wNumButtons;
                public int wPeriodMin;
                public int wPeriodMax;
             }

             int joyGetDevCapsA (int id, JOYCAPSA caps, int size);

             final static int JOYCAPSW_SIZE = 104;

             public static class JOYCAPSW extends Structure
             {
                public short wMid;
                public short wPid;
                public char szPname [] = new char [32];
                public int wXmin;
                public int wXmax;
                public int wYmin;
                public int wYmax;
                public int wZmin;
                public int wZmax;
                public int wNumButtons;
                public int wPeriodMin;
                public int wPeriodMax;
             }

             int joyGetDevCapsW (int id, JOYCAPSW caps, int size);

             int joyGetNumDevs ();
          }


          Listing 6沒有介紹JNA的新特性。實(shí)際上,JNA強(qiáng)調(diào)了對(duì)本地庫的接口命名規(guī)則。同時(shí),還展示了如何將TCHAR映射到Java語言中的byte和char數(shù)組。最后,它揭示了以常量方式聲明的結(jié)構(gòu)體的大小。Listing 7展示了當(dāng)調(diào)用joyGetDevCapsA() 和 joyGetDevCapsW()時(shí)如何使用這些常量。

          Listing 7. JoystickInfo.java

          // JoystickInfo.java

          import com.sun.jna.*;

          public class JoystickInfo
          {
             public static void main (String [] args)
             {
                WinMM lib = (WinMM) Native.loadLibrary ("winmm", WinMM.class);
                int numDev = lib.joyGetNumDevs ();

                System.out.println ("joyGetDevCapsA() Demo");
                System.out.println ("---------------------\n");

                WinMM.JOYCAPSA caps1 = new WinMM.JOYCAPSA ();
                for (int i = 0; i < numDev; i++)
                     if (lib.joyGetDevCapsA (i, caps1, WinMM.JOYCAPSA_SIZE) == 0)
                     {
                         String pname = new String (caps1.szPname);
                         pname = pname.substring (0, pname.indexOf ('\0'));
                         System.out.println ("Device #"+i);
                         System.out.println ("  wMid = "+caps1.wMid);
                         System.out.println ("  wPid = "+caps1.wPid);
                         System.out.println ("  szPname = "+pname);
                         System.out.println ("  wXmin = "+caps1.wXmin);
                         System.out.println ("  wXmax = "+caps1.wXmax);
                         System.out.println ("  wYmin = "+caps1.wYmin);
                         System.out.println ("  wYmax = "+caps1.wYmax);
                         System.out.println ("  wZmin = "+caps1.wZmin);
                         System.out.println ("  wZmax = "+caps1.wZmax);
                         System.out.println ("  wNumButtons = "+caps1.wNumButtons);
                         System.out.println ("  wPeriodMin = "+caps1.wPeriodMin);
                         System.out.println ("  wPeriodMax = "+caps1.wPeriodMax);
                         System.out.println ();
                     }

                System.out.println ("joyGetDevCapsW() Demo");
                System.out.println ("---------------------\n");

                WinMM.JOYCAPSW caps2 = new WinMM.JOYCAPSW ();
                for (int i = 0; i < numDev; i++)
                     if (lib.joyGetDevCapsW (i, caps2, WinMM.JOYCAPSW_SIZE) == 0)
                     {
                         String pname = new String (caps2.szPname);
                         pname = pname.substring (0, pname.indexOf ('\0'));
                         System.out.println ("Device #"+i);
                         System.out.println ("  wMid = "+caps2.wMid);
                         System.out.println ("  wPid = "+caps2.wPid);
                         System.out.println ("  szPname = "+pname);
                         System.out.println ("  wXmin = "+caps2.wXmin);
                         System.out.println ("  wXmax = "+caps2.wXmax);
                         System.out.println ("  wYmin = "+caps2.wYmin);
                         System.out.println ("  wYmax = "+caps2.wYmax);
                         System.out.println ("  wZmin = "+caps2.wZmin);
                         System.out.println ("  wZmax = "+caps2.wZmax);
                         System.out.println ("  wNumButtons = "+caps2.wNumButtons);
                         System.out.println ("  wPeriodMin = "+caps2.wPeriodMin);
                         System.out.println ("  wPeriodMax = "+caps2.wPeriodMax);
                         System.out.println ();
                     }
             }
          }

          盡管和LocalTime這個(gè)示例類似,JoystickInfo執(zhí)行WinMM lib = (WinMM) Native.loadLibrary ("winmm", WinMM.class);這句話來獲取一個(gè)WinMM的實(shí)例,并且載入winmm.dll。它還執(zhí)行WinMM.JOYCAPSA caps1 = new WinMM.JOYCAPSA (); 和 WinMM.JOYCAPSW caps2 = new WinMM.JOYCAPSW ();初始化必需的結(jié)構(gòu)體實(shí)例。

          編譯和運(yùn)行這個(gè)程序(Compile and run the application)

          假如jna.jar,WinMM.java和JoystickInfo.java在同一個(gè)文件夾中,調(diào)用 javac -cp jna.jar;. JoystickInfo.java 來編譯這個(gè)應(yīng)用的源代碼。
          在windows平臺(tái)下,調(diào)用java -cp jna.jar;. JoystickInfo就可以運(yùn)行這個(gè)應(yīng)用程序了。如果沒有操縱桿設(shè)備,你應(yīng)該得到Listing 8中的輸出。

          將C語言中的string類型轉(zhuǎn)換為Java語言的String類型

          pname = pname.substring (0, pname.indexOf ('\0')); 這段代碼將一個(gè)C string 轉(zhuǎn)換成了Java string. 如果不使用這個(gè)轉(zhuǎn)換,C語言的string結(jié)束符’\0’和string后面的無用字符都會(huì)成為Java語言中String實(shí)例對(duì)象的內(nèi)容。

          Listing 8. 輸出操縱桿信息(Output of JoystickInfo)

          joyGetDevCapsA() Demo
          ---------------------

          joyGetDevCapsW() Demo
          ---------------------


          上面的輸出是因?yàn)槊看握{(diào)用joyGetDevCap()返回的是一個(gè)非空值,這表示沒有操縱桿/游戲控制器設(shè)備或者是出現(xiàn)錯(cuò)誤。為了獲取更多有意思的輸出,將一個(gè)設(shè)備連接到你的平臺(tái)上并且再次運(yùn)行JoystickInfo。如下,將一個(gè)微軟SideWinder即插即用游戲觸摸板設(shè)備聯(lián)上之后我獲取了如下的輸出:

          Listing 9. 操縱桿連接上之后的運(yùn)行結(jié)果(Output after running JoystickInfo with a joystick attached)

          joyGetDevCapsA() Demo
          ---------------------

          Device #0
            wMid = 1118
            wPid = 39
            szPname = Microsoft PC-joystick driver
            wXmin = 0
            wXmax = 65535
            wYmin = 0
            wYmax = 65535
            wZmin = 0
            wZmax = 65535
            wNumButtons = 6
            wPeriodMin = 10
            wPeriodMax = 1000

          joyGetDevCapsW() Demo
          ---------------------

          Device #0
            wMid = 1118
            wPid = 39
            szPname = Microsoft PC-joystick driver
            wXmin = 0
            wXmax = 65535
            wYmin = 0
            wYmax = 65535
            wZmin = 0
            wZmax = 65535
            wNumButtons = 6
            wPeriodMin = 10
            wPeriodMax = 1000


          窗口透明度(Transparent windows)

          在這系列文章中上篇文章是關(guān)于Bernhard Pauler's 氣泡提示(balloontip)工程的。我構(gòu)建了一個(gè)叫做VerifyAge的、包含有一個(gè)氣泡提示的GUI應(yīng)用。Figure 1中顯示了這個(gè)GUI應(yīng)用的一個(gè)小問題:這個(gè)氣泡提示的沒有經(jīng)過修飾的對(duì)話框部分遮住了應(yīng)用窗口的一部分邊框,導(dǎo)致了無法點(diǎn)擊這個(gè)邊框的最小化和最大化按鈕,并且使整個(gè)GUI很難看.
          image
          盡管未修飾部分的對(duì)話框不能顯示氣泡提示的透明度,java語言不支持窗口透明度。幸運(yùn)的是,我們可以通過使用com.sun.jna.examples.WindowUtils類調(diào)用JNA的examples.jar文件來解決這個(gè)問題。
          WindowUtils提供在Unix,Linux,Mac OS X和Windows平臺(tái)上使用JNA’s來實(shí)現(xiàn)窗口透明的工具方法。例如, public static void setWindowMask(final Window w, Icon mask) 讓你根據(jù)像素而不是通過預(yù)定的掩罩(mask)參數(shù)來選取某部分的窗口。這個(gè)功能將在Listing 10中展示:

          Listing 10. Using JNA to render a window transparent


          // Create a mask for this dialog. This mask has the same shape as the
          // dialog's rounded balloon tip and ensures that only the balloon tip
          // part of the dialog will be visible. All other dialog pixels will
          // disappear because they correspond to transparent mask pixels.

          // Note: The drawing code is based on the drawing code in
          // RoundedBalloonBorder.

          Rectangle bounds = getBounds ();
          BufferedImage bi = new BufferedImage (bounds.width, bounds.height,
                                                BufferedImage.TYPE_INT_ARGB);
          Graphics g = bi.createGraphics ();
          g.fillRoundRect (0, 0, bounds.width, bounds.height-VERT_OFFSET,
                           ARC_WIDTH*2, ARC_HEIGHT*2);
          g.drawRoundRect (0, 0, bounds.width-1, bounds.height-VERT_OFFSET-1,
                           ARC_WIDTH*2, ARC_HEIGHT*2);
          int [] xPoints = { HORZ_OFFSET, HORZ_OFFSET+VERT_OFFSET, HORZ_OFFSET };
          int [] yPoints = { bounds.height-VERT_OFFSET-1, bounds.height-VERT_OFFSET
                             -1, bounds.height-1 };
          g.fillPolygon (xPoints, yPoints, 3);
          g.drawLine (xPoints [0], yPoints [0], xPoints [2], yPoints [2]);
          g.drawLine (xPoints [1], yPoints [1], xPoints [2], yPoints [2]);
          g.dispose ();
          WindowUtils.setWindowMask (this, new ImageIcon (bi));


          在Listing 10中的代碼段是從本文代碼文檔(code archive)里的加強(qiáng)版的VerifyAge2 應(yīng)用中的TipFrame的構(gòu)造函數(shù)結(jié)尾部分摘錄的。這個(gè)構(gòu)造函數(shù)定義了圍繞提示氣泡的掩罩(mask)的形狀,在這個(gè)形狀范圍里描繪不透明的像素。
          假如你當(dāng)前文件夾中有examples.jar, jna.jar, 和 VerifyAge2.java,調(diào)用 javac -cp examples.jar;balloontip.jar VerifyAge2.java 來編譯源文件.然后調(diào)用java -Dsun.java2d.noddraw=true -cp examples.jar;balloontip.jar;. VerifyAge2運(yùn)行這個(gè)應(yīng)用. Figure 2 展示了透明示例.
          image

          總結(jié)(In conclusion)

          JNA項(xiàng)目有很長的歷史了(追溯到1999年),但是它第一次發(fā)布是在2006年11月。從此以后它慢慢的被需要將本地C代碼整合到Java工程中的開發(fā)者注意到了。因?yàn)镴NA能夠用來解決JuRuby中常見一個(gè)問題:缺乏對(duì)POSIX調(diào)用的支持(lack of support for POSIX calls),它也在JRuby程序員中掀起些波浪。JNA也同樣被作為實(shí)現(xiàn)用低級(jí)C代碼繼承Ruby的一種解決方案(extending Ruby with low-level C code)。
          我喜歡使用JNA來工作,相信你也會(huì)發(fā)現(xiàn)它比使用JNI來訪問本地代碼更簡單、更安全。無需多言,JNA還有更多的特性在本文中沒有體現(xiàn)出來。查閱它的資源部分:獲取這個(gè)開源java項(xiàng)目更多的信息(learn more about this open source Java project)。用它做demo,而且在論壇(discussion forum )上共享你的經(jīng)驗(yàn)。 下一個(gè)月我會(huì)帶著另一個(gè)開源項(xiàng)目回來的,這個(gè)開源項(xiàng)目會(huì)給你每天的java開發(fā)帶來益處。

          附錄:WindowUtils.setWindowMask()的替代品

          在剛剛寫完這篇文章后,我發(fā)現(xiàn)java語言支持在6u10版本中支持窗口的透明和形狀定制。讀完Kirill Grouchnikov的博客后,我用WindowUtils.setWindowMask()的替代品修改了VerifyAge2,如下:
          // Create and install a balloon tip shape to ensure that only this part
          // of the dialog will be visible.

          Rectangle bounds = getBounds ();
          GeneralPath gp;
          gp = new GeneralPath (new RoundRectangle2D.Double (bounds.x, bounds.y,
                                                             bounds.width,
                                                             bounds.height-
                                                             VERT_OFFSET,
                                                             ARC_WIDTH*2-1,
                                                             ARC_HEIGHT*2-1));
          gp.moveTo (HORZ_OFFSET, bounds.height-VERT_OFFSET);
          gp.lineTo (HORZ_OFFSET, bounds.height);
          gp.lineTo (HORZ_OFFSET+VERT_OFFSET+1, bounds.height-VERT_OFFSET);
          AWTUtilities.setWindowShape (this, gp);


          這段代碼使用新類AWTUtilities(在com.sun.awt包中),而且public void setWindowShape(Window w, Shape s)函數(shù)將TipFrame和JDialog窗口設(shè)置氣泡形狀。
          posted @ 2009-05-07 11:08 lanxin1020 閱讀(817) | 評(píng)論 (0)編輯 收藏
          Java代碼
          1. 簡單介紹及應(yīng)用如下:    
          2.   一、JAVA中所需要做的工作    
          3.   在JAVA程序中,首先需要在類中聲明所調(diào)用的庫名稱,如下:    
          4.   
          5. static {    
          6. System.loadLibrary(“goodluck”);    
          7. }   
          8.   
          9.   
          10.   在這里,庫的擴(kuò)展名字可以不用寫出來,究竟是DLL還是SO,由系統(tǒng)自己判斷。    
          11.   
          12.   還需對(duì)將要調(diào)用的方法做本地聲明,關(guān)鍵字為native。且只需要聲明,而不需要具體實(shí)現(xiàn)。如下:    
          13.   
          14. public native static void set(int i);    
          15. public native static int get();   
          16.   
          17.   
          18.   然后編譯該JAVA程序文件,生成CLASS,再用JAVAH命令,JNI就會(huì)生成C/C++的頭文件。    
          19.   
          20.   例如程序testdll.java,內(nèi)容為:    
          21.   
          22. public class testdll    
          23. {    
          24. static    
          25. {    
          26. System.loadLibrary("goodluck");    
          27. }    
          28. public native static int get();    
          29. public native static void set(int i);    
          30. public static void main(String[] args)    
          31. {    
          32. testdll test = new testdll();    
          33. test.set(10);    
          34. System.out.println(test.get());    
          35. }    
          36. }   
          37.   
          38.   
          39.   用javac testdll.java編譯它,會(huì)生成testdll.class。    
          40.   再用javah testdll,則會(huì)在當(dāng)前目錄下生成testdll.h文件,這個(gè)文件需要被C/C++程序調(diào)用來生成所需的庫文件。    
          41.   
          42.   二、C/C++中所需要做的工作    
          43.   對(duì)于已生成的.h頭文件,C/C++所需要做的,就是把它的各個(gè)方法具體的實(shí)現(xiàn)。然后編譯連接成庫文件即可。再把庫文件拷貝到JAVA程序的路徑下面,就可以用JAVA調(diào)用C/C++所實(shí)現(xiàn)的功能了。    
          44.   接上例子。我們先看一下testdll.h文件的內(nèi)容:    
          45.   
          46. /* DO NOT EDIT THIS FILE - it is machine generated */    
          47. #include    
          48. /* Header for class testdll */    
          49. #ifndef _Included_testdll    
          50. #define _Included_testdll    
          51. #ifdef __cplusplus    
          52. extern "C" {    
          53. #endif    
          54. /*   
          55. * Class: testdll   
          56. * Method: get   
          57. * Signature: ()I   
          58. */    
          59. JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass);    
          60. /*   
          61. * Class: testdll   
          62. * Method: set   
          63. * Signature: (I)V   
          64. */    
          65. JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);    
          66. #ifdef __cplusplus    
          67. }    
          68. #endif    
          69. #endif   
          70.   
          71.   
          72.   在具體實(shí)現(xiàn)的時(shí)候,我們只關(guān)心兩個(gè)函數(shù)原型    
          73.   JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass); 和    
          74.   JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint);   
          75.   
          76.   這里JNIEXPORT和JNICALL都是JNI的關(guān)鍵字,表示此函數(shù)是要被JNI調(diào)用的。而jint是以JNI為中介使JAVA的int類型與本 地的int溝通的一種類型,我們可以視而不見,就當(dāng)做int使用。函數(shù)的名稱是JAVA_再加上java程序的package路徑再加函數(shù)名組成的。參數(shù) 中,我們也只需要關(guān)心在JAVA程序中存在的參數(shù),至于JNIEnv*和jclass我們一般沒有必要去碰它。    
          77.   
          78.   好,下面我們用testdll.cpp文件具體實(shí)現(xiàn)這兩個(gè)函數(shù):    
          79.   
          80. #include "testdll.h"    
          81. int i = 0;    
          82. JNIEXPORT jint JNICALL Java_testdll_get (JNIEnv *, jclass)    
          83. {    
          84. return i;    
          85. }    
          86. JNIEXPORT void JNICALL Java_testdll_set (JNIEnv *, jclass, jint j)    
          87. {    
          88. i = j;    
          89. }   
          90.   
          91.   
          92.   編譯連接成庫文件,本例是在WINDOWS下做的,生成的是DLL文件。并且名稱要與JAVA中需要調(diào)用的一致,這里就是goodluck.dll 。把goodluck.dll拷貝到testdll.class的目錄下,java testdll運(yùn)行它,就可以觀察到結(jié)果了。    
          93.   我的項(xiàng)目比較復(fù)雜,需要調(diào)用動(dòng)態(tài)鏈接庫,這樣在JNI傳送參數(shù)到C程序時(shí),需要對(duì)參數(shù)進(jìn)行處理轉(zhuǎn)換。才可以被C程序識(shí)別。   
          94.   大體程序如下:   
          95.   
          96. public class SendSMS {    
          97. static    
          98. {    
          99.   
          100.   
          101.     
          102. System.out.println(System.getProperty("java.library.path"));    
          103. System.loadLibrary("sms");    
          104. }    
          105. public native static int SmsInit();    
          106. public native static int SmsSend(byte[] mobileNo, byte[] smContent);    
          107. }    
          108.   
          109.   在這里要注意的是,path里一定要包含類庫的路徑,否則在程序運(yùn)行時(shí)會(huì)拋出異常:   
          110.   java.lang.UnsatisfiedLinkError: no sms in java.library.path   
          111.   at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1491)   
          112.   at java.lang.Runtime.loadLibrary0(Runtime.java:788)   
          113.   at java.lang.System.loadLibrary(System.java:834)   
          114.   at com.mobilesoft.sms.mobilesoftinfo.SendSMS.(SendSMS.java:14)   
          115.   at com.mobilesoft.sms.mobilesoftinfo.test.main(test.java:18)   
          116.   Exception in thread "main"  
          117.   
          118.   指引的路徑應(yīng)該到.dll文件的上一級(jí),如果指到.dll,則會(huì)報(bào):   
          119.   java.lang.UnsatisfiedLinkError: C:\sms.dll: Can't find dependent libraries   
          120.   at java.lang.ClassLoader$NativeLibrary.load(Native Method)   
          121.   at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1560)   
          122.   at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1485)   
          123.   at java.lang.Runtime.loadLibrary0(Runtime.java:788)   
          124.   at java.lang.System.loadLibrary(System.java:834)   
          125.   at com.mobilesoft.sms.mobilesoftinfo.test.main(test.java:18)   
          126.   Exception in thread "main"  
          127.   
          128.   通過編譯,生成com_mobilesoft_sms_mobilesoftinfo_SendSMS.h頭文件。(建議使用Jbuilder進(jìn)行編 譯,操作比較簡單?。┻@個(gè)頭文件就是Java和C之間的紐帶。要特別注意的是方法中傳遞的參數(shù)jbyteArray,這在接下來的過程中會(huì)重點(diǎn)介紹。   
          129.   
          130. /* DO NOT EDIT THIS FILE - it is machine generated */    
          131. #include    
          132. /* Header for class com_mobilesoft_sms_mobilesoftinfo_SendSMS */    
          133. #ifndef _Included_com_mobilesoft_sms_mobilesoftinfo_SendSMS    
          134. #define _Included_com_mobilesoft_sms_mobilesoftinfo_SendSMS    
          135. #ifdef __cplusplus    
          136. extern "C" {    
          137. #endif    
          138. /*   
          139. * Class: com_mobilesoft_sms_mobilesoftinfo_SendSMS   
          140. * Method: SmsInit   
          141. * Signature: ()I   
          142. */    
          143. JNIEXPORT jint JNICALL Java_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsInit    
          144. (JNIEnv *, jclass);    
          145. /*   
          146. * Class: com_mobilesoft_sms_mobilesoftinfo_SendSMS   
          147. * Method: SmsSend   
          148. * Signature: ([B[B)I   
          149. */    
          150. JNIEXPORT jint JNICALL Java_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsSend    
          151. (JNIEnv *, jclass, jbyteArray, jbyteArray);    
          152. #ifdef __cplusplus    
          153. }    
          154. #endif    
          155. #endif   
          156.   
          157.   
          158.   
          159.   對(duì)于我要調(diào)用的C程序的動(dòng)態(tài)鏈接庫,C程序也要提供一個(gè)頭文件,sms.h。這個(gè)文件將要調(diào)用的方法羅列了出來。   
          160.   
          161. /*   
          162. * SMS API   
          163. * Author: yippit   
          164. * Date: 2004.6.8   
          165. */    
          166. #ifndef MCS_SMS_H    
          167. #define MCS_SMS_H    
          168. #define DLLEXPORT __declspec(dllexport)    
          169. /*sms storage*/    
          170. #define SMS_SIM 0    
          171. #define SMS_MT 1    
          172. /*sms states*/    
          173. #define SMS_UNREAD 0    
          174. #define SMS_READ 1    
          175. /*sms type*/    
          176. #define SMS_NOPARSE -1    
          177. #define SMS_NORMAL 0    
          178. #define SMS_FLASH 1    
          179. #define SMS_MMSNOTI 2    
          180. typedef struct tagSmsEntry {    
          181. int index; /*index, start from 1*/    
          182. int status; /*read, unread*/    
          183. int type; /*-1-can't parser 0-normal, 1-flash, 2-mms*/    
          184. int storage; /*SMS_SIM, SMS_MT*/    
          185. char date[24];    
          186. char number[32];    
          187. char text[144];    
          188. } SmsEntry;    
          189. DLLEXPORT int SmsInit(void);    
          190. DLLEXPORT int SmsSend(char *phonenum, char *content);    
          191. DLLEXPORT int SmsSetSCA(char *sca);    
          192. DLLEXPORT int SmsGetSCA(char *sca);    
          193. DLLEXPORT int SmsSetInd(int ind);    
          194. DLLEXPORT int SmsGetInd(void);    
          195. DLLEXPORT int SmsGetInfo(int storage, int *max, int *used);    
          196. DLLEXPORT int SmsSaveFlash(int flag);    
          197. DLLEXPORT int SmsRead(SmsEntry *entry, int storage, int index);    
          198. DLLEXPORT int SmsDelete(int storage, int index);    
          199. DLLEXPORT int SmsModifyStatus(int storage, int index); /*unread -> read*/    
          200. #endif   
          201.   
          202.   
          203.   在有了這兩個(gè)頭文件之后,就可以進(jìn)行C程序的編寫了。也就是實(shí)現(xiàn)對(duì)JNI調(diào)用的兩個(gè)方法。在網(wǎng)上的資料中,由于調(diào)用的方法實(shí)現(xiàn)的都比較簡單,(大多是打印字符串等)所以避開了JNI中最麻煩的部分,也是最關(guān)鍵的部分,參數(shù)的傳遞。     
          204. 由于Java和C的編碼是不同的,所以傳遞的參數(shù)是要進(jìn)行再處理,否則C程序是會(huì)對(duì)參數(shù)在編譯過程中提出警告,例如;warning C4024: 'SmsSend' : different types for formal and actual parameter 2等。   
          205.   Sms.c的程序如下:   
          206.   
          207. #include "sms.h"    
          208. #include "com_mobilesoft_sms_mobilesoftinfo_SendSMS.h"    
          209. JNIEXPORT jint JNICALL Java_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsInit(JNIEnv * env, jclass jobject)    
          210. {    
          211. return SmsInit();    
          212. }    
          213.   
          214. JNIEXPORT jint JNICALL Java_com_mobilesoft_sms_mobilesoftinfo_SendSMS_SmsSend(JNIEnv * env, jclass jobject, jbyteArray mobileno, jbyteArray smscontent)    
          215. {    
          216. char * pSmscontent ;    
          217. //jsize theArrayLengthJ = (*env)->GetArrayLength(env,mobileno);    
          218. jbyte * arrayBody = (*env)->GetByteArrayElements(env,mobileno,0);    
          219. char * pMobileNo = (char *)arrayBody;    
          220. printf("[%s]\n ", pMobileNo);    
          221. //jsize size = (*env)->GetArrayLength(env,smscontent);    
          222. arrayBody = (*env)->GetByteArrayElements(env,smscontent,0);    
          223. pSmscontent = (char *)arrayBody;    
          224. printf("<%s>\n", pSmscontent);    
          225. return SmsSend(pMobileNo,pSmscontent);    
          226. }   
          227.   
          228.   
          229.   
          230.   對(duì)于C或C++,在程序上是會(huì)有稍微的不同,這可以由讀者對(duì)其進(jìn)行適當(dāng)?shù)男薷摹_@里要注意的是GetArrayLength,GetByteArrayElements等這些JNI中已經(jīng)包含的方法,這些方法是專門對(duì)轉(zhuǎn)換參數(shù)類型而提供的。具體的方法有很多,在下一篇中會(huì)做專門的介紹。   
          231.   在完成了上述的文件后,可以對(duì)sms.c進(jìn)行編譯,生成.dll文件(建議在release中編譯,這樣動(dòng)態(tài)鏈接庫的容積會(huì)比較小!)   
          232.   完成.dll文件的編譯后,就可以在Java中調(diào)用C程序中的方法了。例如文件test.java   
          233.   
          234. public class test {    
          235. public test() {    
          236. }    
          237. public static void main(String[] args) {    
          238. byte[] mobileno = {    
          239. 0x310x330x360x360x310x360x330x300x360x360x370x00};    
          240. String smscontentemp = "早上好";    
          241. byte[] temp = {0};    
          242. try {    
          243. byte[] smscontentdb = smscontentemp.getBytes("gbk");    
          244. byte[] smscontent = new byte[smscontentdb.length + temp.length];    
          245. System.arraycopy(smscontentdb, 0, smscontent, 0, smscontentdb.length);    
          246. System.arraycopy(temp, 0, smscontent, smscontentdb.length, temp.length);    
          247. SendSMS sendSMS = new SendSMS();    
          248. sendSMS.SmsInit();    
          249. if (sendSMS.SmsSend(mobileno, smscontent) >= 0) {    
          250. System.out.println("chenggong !");    
          251. }    
          252. else {    
          253. System.out.println("shibai !");    
          254. }    
          255. }catch (Exception ex) {}    
          256. }    
          257. }   
          258.   
          259.   
          260.   
          261.   在這個(gè)文件中要注意的有一點(diǎn),就是在傳遞字節(jié)數(shù)組到C程序中時(shí),最后的結(jié)尾一定要以0結(jié)束。這是一個(gè)偷懶的做法,不過是個(gè)有效的做法。因?yàn)榇蠖鄶?shù)情況 下,接口是由第三方提供的。所以我們一般是不知道在C的方法里,具體是怎么處理參數(shù)的。而C又是要求數(shù)組是有長度。所以,在Java中,如果你不想寫程序 傳數(shù)組的長度,那么在數(shù)組中以0結(jié)尾就是最方便的方法了。當(dāng)然,如果有更好的方法也希望大家提出。   
          262.   
          263.   到這里,一個(gè)完整的Java通過JNI調(diào)用動(dòng)態(tài)鏈接庫的程序就完成了。實(shí)際上也不是很復(fù)雜。只要多注意一下細(xì)節(jié),是很容易得出來的。  
          posted @ 2009-05-07 11:04 lanxin1020 閱讀(174) | 評(píng)論 (0)編輯 收藏
          Properties 基本知識(shí)
          如果不熟悉 java.util.Properties 類,那么現(xiàn)在告訴您它是用來在一個(gè)文件中存儲(chǔ)鍵-值對(duì)的,其中鍵和值是用等號(hào)分隔的,如清單 1 所示。

          清單 1. 一組屬性示例
          foo=bar
          fu=baz

          將清單 1 裝載到 Properties 對(duì)象中后,您就可以找到兩個(gè)鍵( foo 和 fu )和兩個(gè)值( foo 的 bar 和 fu 的 baz )了。這個(gè)類支持帶 \u 的嵌入 Unicode 字符串,但是這里重要的是每一項(xiàng)內(nèi)容都當(dāng)作 String 。

          清單 2 顯示了如何裝載屬性文件并列出它當(dāng)前的一組鍵和值。只需傳遞這個(gè)文件的 InputStream 給 load() 方法,就會(huì)將每一個(gè)鍵-值對(duì)添加到 Properties 實(shí)例中。然后用 list() 列出所有屬性或者用 getProperty() 獲取單獨(dú)的屬性。
          清單 2. 裝載屬性
          Java代碼
          1. import java.util.*;   
          2. import java.io.*;   
          3.   
          4. public class LoadSample {   
          5.     public static void main(String args[]) throws Exception {   
          6.       Properties prop = new Properties();   
          7.       FileInputStream fis =    
          8.         new FileInputStream("sample.properties");   
          9.       prop.load(fis);   
          10.       prop.list(System.out);   
          11.       System.out.println("\nThe foo property: " +   
          12.           prop.getProperty("foo"));   
          13.     }   
          14. }  

          運(yùn)行 LoadSample 程序生成如清單 3 所示的輸出。注意 list() 方法的輸出中鍵-值對(duì)的順序與它們?cè)谳斎胛募械捻樞虿灰粯印?Properties 類在一個(gè)散列表(hashtable,事實(shí)上是一個(gè) Hashtable 子類)中儲(chǔ)存一組鍵-值對(duì),所以不能保證順序。

          清單 3. LoadSample 的輸出

          -- listing properties --
          fu=baz
          foo=bar

          The foo property: bar

          XML 屬性文件
          這里沒有什么新內(nèi)容。 Properties 類總是這樣工作的。不過,新的地方是從一個(gè) XML 文件中裝載一組屬性。它的 DTD 如清單 4 所示。

          清單 4. 屬性 DTD

          dtd 寫道
          Java代碼
          1. <?xml version="1.0" encoding="UTF-8"?>    
          2. <!-- DTD for properties -->    
          3. <!ELEMENT properties ( comment?, entry* ) >    
          4. <!ATTLIST properties version CDATA #FIXED "1.0">    
          5. <!ELEMENT comment (#PCDATA) >    
          6. <!ELEMENT entry (#PCDATA) >    
          7. <!ATTLIST entry key CDATA #REQUIRED>  



          如果不想細(xì)讀 XML DTD,那么可以告訴您它其實(shí)就是說在外圍 <properties> 標(biāo)簽中包裝的是一個(gè) <comment> 標(biāo)簽,后面是任意數(shù)量的 <entry> 標(biāo)簽。對(duì)每一個(gè) <entry> 標(biāo)簽,有一個(gè)鍵屬性,輸入的內(nèi)容就是它的值。清單 5 顯示了 清單 1中的屬性文件的 XML 版本是什么樣子的。

          清單 5. XML 版本的屬性文件
          Java代碼
          1. <?xml version="1.0" encoding="UTF-8"?>   
          2. <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">   
          3. <properties>   
          4. <comment>Hi</comment>   
          5. <entry key="foo">bar</entry>   
          6. <entry key="fu">baz</entry>   
          7. </properties>  

          如果清單 6 所示,讀取 XML 版本的 Properties 文件與讀取老格式的文件沒什么不同。
          清單 6. 讀取 XML Properties 文件
          Java代碼
          1. import java.util.*;   
          2. import java.io.*;   
          3.   
          4. public class LoadSampleXML {   
          5.     public static void main(String args[]) throws Exception {   
          6.       Properties prop = new Properties();   
          7.       FileInputStream fis =   
          8.         new FileInputStream("sampleprops.xml");   
          9.       prop.loadFromXML(fis);   
          10.       prop.list(System.out);   
          11.       System.out.println("\nThe foo property: " +   
          12.           prop.getProperty("foo"));   
          13.     }   
          14. }  

          關(guān)于資源綁定的說明
          雖然 java.util.Properties 類現(xiàn)在除了支持鍵-值對(duì),還支持屬性文件作為 XML 文件,不幸的是,沒有內(nèi)置的選項(xiàng)可以將 ResourceBundle 作為一個(gè) XML 文件處理。是的, PropertyResourceBundle 不使用 Properties 對(duì)象來裝載綁定,不過裝載方法的使用是硬編碼到類中的,而不使用較新的 loadFromXML() 方法。

          運(yùn)行清單 6 中的程序產(chǎn)生與原來的程序相同的輸出,如 清單 2所示。

          保存 XML 屬性
          新的 Properties 還有一個(gè)功能是將屬性存儲(chǔ)到 XML 格式的文件中。雖然 store() 方法仍然會(huì)創(chuàng)建一個(gè)類似 清單 1 所示的文件,但是現(xiàn)在可以用新的 storeToXML() 方法創(chuàng)建如 清單 5 所示的文件。只要傳遞一個(gè) OutputStream 和一個(gè)用于注釋的 String 就可以了。清單 7 展示了新的 storeToXML() 方法。

          清單 7. 將 Properties 存儲(chǔ)為 XML 文件
          Java代碼
          1. import java.util.*;   
          2. import java.io.*;   
          3.   
          4. public class StoreXML {   
          5.     public static void main(String args[]) throws Exception {   
          6.       Properties prop = new Properties();   
          7.       prop.setProperty("one-two""buckle my shoe");   
          8.       prop.setProperty("three-four""shut the door");   
          9.       prop.setProperty("five-six""pick up sticks");   
          10.       prop.setProperty("seven-eight""lay them straight");   
          11.       prop.setProperty("nine-ten""a big, fat hen");   
          12.       FileOutputStream fos =   
          13.         new FileOutputStream("rhyme.xml");   
          14.       prop.storeToXML(fos, "Rhyme");   
          15.       fos.close();   
          16.     }   
          17. }  

          運(yùn)行清單 7 中的程序產(chǎn)生的輸出如清單 8 所示。

          清單 8. 存儲(chǔ)的 XML 文件
          Java代碼
          1. <?xml version="1.0" encoding="UTF-8"?>   
          2. <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">   
          3. <properties>   
          4. <comment>Rhyme</comment>   
          5. <entry key="seven-eight">lay them straight</entry>   
          6. <entry key="five-six">pick up sticks</entry>   
          7. <entry key="nine-ten">a big, fat hen</entry>   
          8. <entry key="three-four">shut the door</entry>   
          9. <entry key="one-two">buckle my shoe</entry>   
          10. </properties>  

          結(jié)束語
          使用 XML 文件還是使用老式的 a=b 類型的文件完全取決于您自己。老式文件從內(nèi)存的角度看肯定是輕量級(jí)的。不過,由于 XML 的普遍使用,人們會(huì)期望 XML 格式流行起來,因?yàn)樗呀?jīng)被廣泛使用了,只不過沒有用到 Properties 對(duì)象。選擇完全在您。分析軟件包 private XMLUtils 類的源代碼以獲得關(guān)于所使用的 XML 解析的更多信息。
          Java代碼
          1. import java.io.FileInputStream;   
          2. import java.io.IOException;   
          3. import java.io.InputStream;   
          4. import java.util.Properties;   
          5. /**  
          6. * 實(shí)現(xiàn)properties文件的讀取  
          7. * @author bbflyerwww  
          8. * @date 2006-08-02  
          9. */  
          10. public class PTest {   
          11.       public static void main(String[] args) {   
          12.           try {   
          13.               long start = System.currentTimeMillis();   
          14.               InputStream is = new FileInputStream("conf.properties");   
          15.               Properties p = new Properties();   
          16.               p.load(is);   
          17.               is.close();   
          18.               System.out.println("SIZE : " + p.size());   
          19.               System.out.println("homepage : " + p.getProperty("homepage"));   
          20.               System.out.println("author : " + p.getProperty("author"));   
          21.               System.out.println("school : " + p.getProperty("school"));   
          22.               System.out.println("date : " + p.getProperty("date"));   
          23.               long end = System.currentTimeMillis();    
          24.               System.out.println("Cost : " + (end - start));   
          25.           } catch (IOException ioe) {   
          26.               ioe.printStackTrace();   
          27.           }   
          28.       }   
          29. }  

          conf.properties
          Java代碼
          1. # Configuration fileauthor = bbflyerwww   
          2. school = WuHan University   
          3. date = 2006-08-02  


          Result

          SIZE:4
          author : bbflyerwww
          school : WuHan University
          date : 2006-08-02
          Cost : 0
          posted @ 2009-05-06 22:52 lanxin1020 閱讀(468) | 評(píng)論 (0)編輯 收藏

          一、LOG4J組成

              LOG4J主要由三大組件組成:
              . Logger: 決定什么日志信息應(yīng)該被輸出、什么日志信息應(yīng)該被忽略;
              . Appender: 指定日志信息應(yīng)該輸出到什么地方, 這些地方可以是控制臺(tái)、文件、網(wǎng)絡(luò)設(shè)備;
              . Layout: 指定日志信息的輸出格式;

              一個(gè)Logger可以有多個(gè)Appender,也就是說日志信息可以同時(shí)輸出到多個(gè)設(shè)備上,每個(gè)Appender對(duì)應(yīng)
              一種Layout(示例見下圖)。

                        ↗  Appender1  →  Layout
               /    
              Logger
               ﹨  
                        ↘  Appender2  →  Layout


          二、Logger組件

              1. Logger組件提供的方法:

                 Logger組件是LOG4J的核心組件,它代表了Log4J的日志記錄器,它能夠?qū)θ罩拘畔⑦M(jìn)行分類篩選。它由org.apache.log4j.Logger類實(shí)現(xiàn),提供了如下方法:

           

          java 代碼
          1. package org.apache.log4j;   
          2.   
          3. public class Logger {   
          4.   
          5.            // Creation & retrieval methods:   
          6.            public static Logger getRootLogger();   
          7.            public static Logger getLogger(String name);   
          8.   
          9.            // printing methods:   
          10.            public void debug(Object message);   
          11.            public void info(Object message);   
          12.            public void warn(Object message);   
          13.            public void error(Object message);   
          14.            public void fatal(Object message);   
          15.       
          16.            // generic printing method:   
          17.            public void log(Priority p, Object message);   
          18. }   

              2. 在配置文件中配置Logger組件

                 可在Log4J配置文件中配置自己的Logger組件,示例:

                 log4j.logger.myLogger=WARN

                 以上代碼定義了一個(gè)Logger組件,名稱為myLogger,日志級(jí)別為WARN。
           
              3. 日志級(jí)別種類:

                 一共有五種,級(jí)別由高到低依次是:fatal、error、warn、info、debug。獲得Logger實(shí)例后,我們可調(diào)用以下方法之一輸出日志信息:

                 public void debug(Object message);          //輸出debug級(jí)別的日志信息;
                 public void info(Object message);           //輸出info級(jí)別的日志信息;
                 public void warn(Object message);           //輸出warn級(jí)別的日志信息;
                 public void error(Object message);          //輸出error級(jí)別的日志信息;
                 public void fatal(Object message);          //輸出fatal級(jí)別的日志信息;
                 public void log(Priority p, Object message);//輸出參數(shù)Priority指定級(jí)別的日志信息;

                 以上方法只有當(dāng)它的級(jí)別大于或等于Logger組件配置的日志級(jí)別時(shí)才調(diào)用。以前面我們配置的myLogger為例,它的日志級(jí)別為WARN, 那么在程序中,它的warn()、error()、fatal()方法會(huì)被執(zhí)行。對(duì)于log()方法,只有當(dāng)它的參數(shù)Priority指定的日志級(jí)別大于或等于WARN時(shí),它才會(huì)被執(zhí)行。

              4. 為什么需要對(duì)日志進(jìn)行分級(jí)?
             
                 在寫程序的時(shí)候,為了調(diào)試程序,我們會(huì)在很多出錯(cuò)的地方輸出大量的日志信息。當(dāng)程序調(diào)試完,不需要這些信息時(shí),將程序中這些輸出日志信息代碼刪除嗎?這樣費(fèi)時(shí)費(fèi)力,對(duì)于大型程序幾乎不可行。通過對(duì)日志分級(jí),假如不想輸出WARN級(jí)別的日志信息,則Logger組件的級(jí)別調(diào)高即可,省時(shí)省心。

              5. Logger組件的繼承性

                 Log4J提供了一個(gè)root Logger,它是所有Logger組件的“祖先”,它永遠(yuǎn)存在,且不能通過名字檢索或引用,通過Logger.getRootLogger()方法取得它。配置root Logger代碼:

                 log4j.rootLogger=INFO,console

                 可在配置文件中方便地配置存在繼承關(guān)系的Logger組件,凡是在符號(hào)“.”后面的組件都會(huì)成為在符號(hào)“.”前面的Logger組件的子類。例如:

                 log4j.apache.myLogger=WARN
                 log4j.apache.myLogger.mySonLogger=,file

                 以上代碼中, mySonLogger是myLogger的子類Logger組件。Logger組件的繼承關(guān)系:
                 . 如果子類Logger組件沒有定義日志級(jí)別,則將繼承父類的日志級(jí)別;
                 . 如果子類Logger組件定義了日志級(jí)別,就不會(huì)繼承父類的日志級(jí)別;
                 . 黙認(rèn)情況下,子類Logger組件會(huì)繼承父類所有的Appender,把它們加入到自己的Appener;
                 . 如果把子類Logger組件的additivity標(biāo)志設(shè)為false,那么它就不會(huì)繼承父類Appender。additivity標(biāo)志 默認(rèn)值為false;

                 以上配置的三個(gè)Logger繼承關(guān)系示例如圖:
              
                 root Logger: 日志級(jí)別=INFO  appender清單=console
                                      ↑
                 myLogger: 日志級(jí)別=WARN appender清單=null
                                      ↑
                 mySonLogger: 日志級(jí)別=null appender清單=file

                 這三個(gè)Logger組件實(shí)際日志級(jí)別和Appender如下表:

                 Logger組件          日志級(jí)別          Appender清單
                 root Logger         INFO              console
                 myLogger            WARN              console(繼承)
                 mySonLogger         WARN(繼承)        file,console(繼承)
                
          三、Appender組件

              Appender組件決定將日志信息輸出到什么地方。支持以下目的地:
              . 控制臺(tái)(Console);
              . 文件(File);
              . GUI組件(GUI component);
              . 套接口服務(wù)器(Remote socket server);
              . NT的事件記錄器(NT Event Logger);
              . UNIX Syslog守護(hù)進(jìn)程(Remote UNIX Syslog daemon);

              一個(gè)Logger可同時(shí)對(duì)應(yīng)多個(gè)Appender,示例:myLogger配置二個(gè)Appender: 一個(gè)file, 一個(gè)是console:

              log4j.logger.myAppender=WARN,file,console

              log4j.appender.file=org.apache.log4j.RollingFileAppender
              log4j.appender.file.File=log.txt

              log4j.apender.console=org.apache.log4j.ConsoleAppender

          四、Layout組件

              Layout組件決定日志輸出格式,有以下幾種類型:
              . org.apache.log4j.HTMLLayout(以HTML表格形式布局);
              . org.apache.log4j.PatternLayout(可以靈活地指定布局模式);
              . org.apache.log4j.SimpleLayout(包含日志信息的級(jí)別和信息字符串);
              . org.apache.log4j.TTCCLayout(包含日志產(chǎn)生的時(shí)間、線程和類別等信息);
             
              為名稱為console的Appender配置SimpleLayout,代碼如下:

              log4j.appender.console.layout=org.apache.log4j.SimpleLayout

              輸出日志格式如下:

              WARN - This is a log message from the myLogger
             
              為名稱為file的Appender配置PatternLayout,代碼如下:

              log4j.appender.file.layout=org.apache.log4j.PatternLayout
              log4j.appender.file.layout.ConversionPattern=%t %p - %m%n

              輸出日志格式如下:

              THREAD-1 WARN - This is a log message from the myLogger

              PatternLayout讓開發(fā)者依照ConversionPattern定義輸出格式。ConversionPattern中一些指定日志內(nèi)容和格式的預(yù)定義符號(hào)說明如下:

              符號(hào)         描述
              %r           自程序開始后消耗的毫秒數(shù)
              %t           表示日志記錄請(qǐng)求生成的線程
              %p           表示日專語句的優(yōu)先級(jí)
              %r           與日志請(qǐng)求相關(guān)的類別名稱
              %c           日志信息所在的類名
              %m%n         表示日志信息的內(nèi)容

          五、Log4J的基本用法

              1. 定義配置文件
                 Log4J支持二種配置文件格式:XML和Java屬性文件(采用“鍵=值”形式)。以下為Java屬性文件
                 格式配置文件:
               
                 . 配置Logger組件
                  
                   配置root Logger語法為:log4j.rootLogger=[priority],appenderName,appenderName,...
                   配置自定義Logger組件語法為:log4j.logger.loggerName=[priority],appenderName,appenderName,...

                   其中:priority為日志級(jí)別,可選值包括FATAL、ERROR、WARN、INFO、DEBUG、ALL;
                         appenderName指定Appender組件,可指定多個(gè);        

                 . 配置Appender組件

                   配置日志信息輸出目的地Appender, 語法為:
                   log4j.appender.appenderName=fully.ualified.name.of.appender.class
                   log4j.appender.appenderName.option1=value1
                   ...
                   log4j.appender.appenderName.optionN=valueN

                   Log4J提供的Appender有以下幾種:

                   a. org.apache.log4j.ConsoleAppender(控制臺(tái));
                   b. org.apache.log4j.FileAppender(文件);
                   c. org.apache.log4j.DailyRollingFileAppender(每天產(chǎn)生一個(gè)日志文件);
                   d. org.apache.log4j.RollingFileAppender(文件大小到指定尺寸產(chǎn)生一個(gè)新的文件);
                   e. org.apache.log4j.WriteAppender(將日志信息以流格式發(fā)送到任意指定地方);

                 . 配置Layout組件

                   配置Layout組件語法為:
                   log4j.appender.appenderName.layout=fully.ualified.name.of.appender.class
                   log4j.appender.appenderName.layout.option1=value1
                   ...
                   log4j.appender.appenderName.layout.optionN=valueN

                   下面為一配置文件示例,文件名為log4j.properties:

                   ## LOGGERS ##

                   #configure root logger
                   log4j.rootLogger=INFO,console
                   #define a logger named myLogger
                   log4j.logger.myLogger=WARN
                   #define a second logger that is a child to myLogger
                   log4j.logger.myLogger.mySonLogger=,file

                   ## APPENDERS ##

                   #define an appender named console, which is set to be a ConsoleAppender
                   log4j.appender.console=org.apache.log4j.ConsoleAppender

                   # define an appender named file, which is set to be a RollingFileAppender
                   log4j.appender.file=org.apache.log4j.FileAppender
                   log4j.appender.file.File=log.txt

                   ## LAYOUTS ##
                   # assian a SimpleLayout to console appender
                   log4j.appender.console.layout=org.apache.log4j.SimpleLayout

                   # assian a PatternLayout to file appender
                   log4j.appender.file.layout=org.apache.log4j.PatternLayout
                   log4j.appender.file.layout.ConversionPattern=%t%p-%m%n
                  
              2. 程序中使用Log4j

                 . 獲得日志記錄器:

                   獲得rootLogger:Logger rootLogger=Logger.getRootLogger();
                   獲得自定義Logger:Logger myLogger = Logger.getLogger("log4j.logger.myLogger");

                 . 讀取日志記錄器,配置Log4J環(huán)境;

                   a. BasicConfigurator.configure(): 自動(dòng)快速地使用默認(rèn)Log4J環(huán)境;
                   b. Property.configurator.configure(String configFilename): 讀取使用Java屬性格式的配置文件并配置Log4J環(huán)境;
                   c. DOMConfigurator.configure(String filename): 讀取XML形式的配置文件并配置LOG4J環(huán)境;

                 . 輸出日志信息;

                   在程序代碼中需要生成日志的地方,調(diào)用Logger的各種輸出日志方法輸出不同級(jí)別的日志,例如:
                  
                   myLogger.debug("Thie is a log message from the " + myLogger.getName());

                   下面為一使用Log4J的程序,程序名為Test.java:

          java 代碼
          1.  import org.apache.log4j.Logger;   
          2.  import org.apache.log4j.PropertyConfigurator;   
          3.     
          4.  public class Test {   
          5.   
          6.    public static void main(String[] args) {   
          7.      //Get an instance of the myLogger   
          8.      Logger myLogger = Logger.getLogger("myLogger");   
          9.       
          10.      //Get an instance of the childLogger   
          11.      Logger mySonLogger = Logger.getLogger("myLogger.mySonLogger");   
          12.      //Load the proerties using the PropertyConfigurator   
          13.      PropertyConfigurator.configure("log4j.properties");   
          14.   
          15.      //Log Messages using the Parent Logger   
          16.      myLogger.debug("Thie is a log message from the " + myLogger.getName());   
          17.      myLogger.info("Thie is a log message from the " + myLogger.getName());   
          18.      myLogger.warn("Thie is a log message from the " +  myLogger.getName());   
          19.      myLogger.error("Thie is a log message from the " + myLogger.getName());   
          20.      myLogger.fatal("Thie is a log message from the " + myLogger.getName());   
          21.   
          22.      mySonLogger.debug("Thie is a log message from the " + mySonLogger.getName());   
          23.      mySonLogger.info("Thie is a log message from the " + mySonLogger.getName());   
          24.      mySonLogger.warn("Thie is a log message from the " +  mySonLogger.getName());   
          25.      mySonLogger.error("Thie is a log message from the " + mySonLogger.getName());   
          26.      mySonLogger.fatal("Thie is a log message from the " + mySonLogger.getName());   
          27.    }   
          28. }   

                  程序運(yùn)行結(jié)果為:

                  WARN - Thie is a log message from the myLogger
                  ERROR - Thie is a log message from the myLogger
                  FATAL - Thie is a log message from the myLogger
                  WARN - Thie is a log message from the myLogger.mySonLogger
                  ERROR - Thie is a log message from the myLogger.mySonLogger
                  FATAL - Thie is a log message from the myLogger.mySonLogger

                  另在Test.class所在的目錄下看到一個(gè)log.txt文件,內(nèi)容如下:

                  WARN - Thie is a log message from the myLogger.mySonLogger
                  ERROR - Thie is a log message from the myLogger.mySonLogger
                  FATAL - Thie is a log message from the myLogger.mySonLogger

                  如將配置文件log4j.properties中語句

           log4j.logger.myLogger.mySonLogger=,file

           改為

           log4j.logger.myLogger.mySonLogger=,file,console

           再次運(yùn)行程序,結(jié)果如下:

                  WARN - Thie is a log message from the myLogger
                  ERROR - Thie is a log message from the myLogger
                  FATAL - Thie is a log message from the myLogger
                  WARN - Thie is a log message from the myLogger.mySonLogger
                  WARN - Thie is a log message from the myLogger.mySonLogger
                  ERROR - Thie is a log message from the myLogger.mySonLogger
                  ERROR - Thie is a log message from the myLogger.mySonLogger
                  FATAL - Thie is a log message from the myLogger.mySonLogger         
                  FATAL - Thie is a log message from the myLogger.mySonLogger

                  mySonLogger的日志在控制臺(tái)上輸出了二次,這是因?yàn)閙ySonLogger繼承了父類console Appender,
                  本身又定義了一個(gè)console Appender, 因而有二個(gè)console Appender。

          六、在web應(yīng)用中使用Log4J

              創(chuàng)建一個(gè)Servlet,在它初始化方法中讀取Log4J配置文件并配置Log4J環(huán)境,這個(gè)Servlet在Web應(yīng)用啟
              動(dòng)時(shí)候被加載和初始化,然后就可在其它Web組件中獲取Logger對(duì)象并輸出日志。

              1. 創(chuàng)建用于配置Log4J環(huán)境的Servlet

          java 代碼
          1. import javax.servlet.*;   
          2. import javax.servlet.http.*;   
          3. import java.io.*;   
          4. import java.util.*;   
          5.   
          6. import org.apache.log4j.PropertyConfigurator;   
          7.   
          8. public class Log4JServlet extends HttpServlet {   
          9.       public void init() throws ServletException {   
          10.            String path = getServletContext().getRealPath("/");   
          11.            //getInitParameter("propfile")方法從web.xml文件中讀取Log4J配置文件的名字"profile"。   
          12.            String propfile = path + getInitParameter("propfile");   
          13.            PropertyConfigurator.configure(propfile);   
          14.       }   
          15. }   
          16.   

                該Servlet在web.xml中的配置如下:

          xml 代碼
          1. <servlet>  
          2.   <servlet-name>log4jServlet</servlet-name>  
          3.   <servlet-class>Log4JServlet</servlet-class>  
          4.   <init-param>  
          5.     <param-name>propfile</param-name>  
          6.     <param-value>/WEB-INF/log4j.properties</param-value>  
          7.   </init-param>  
          8.   <load-on-startup>1</load-on-startup>  
          9. </servlet>  

          2. 在login.jsp中輸出日志
                 <%@page import="org.apache.log4j.Logger"%>
                 <html>
                   <head>
                     <title>login</title>
                   </head>
                   <body>
                     <%
                       Logger myLogger = Logger.getLogger("myLogger");
                       Logger mySonLogger = Logger.getLogger("myLogger.mySonLogger");
                       myLogger.debug("Thie is a log message from the " + myLogger.getName());
                       myLogger.info("Thie is a log message from the " + myLogger.getName());
                       myLogger.warn("Thie is a log message from the " +  myLogger.getName());
                       myLogger.error("Thie is a log message from the " + myLogger.getName());
                       myLogger.fatal("Thie is a log message from the " + myLogger.getName());

                       mySonLogger.debug("Thie is a log message from the " + mySonLogger.getName());
                       mySonLogger.info("Thie is a log message from the " + mySonLogger.getName());
                       mySonLogger.warn("Thie is a log message from the " +  mySonLogger.getName());
                       mySonLogger.error("Thie is a log message from the " + mySonLogger.getName());
                       mySonLogger.fatal("Thie is a log message from the " + mySonLogger.getName());
                     %>
                     <br>
                       <form name="loginForm" method="post" action="dispatcher">
                       username: <input type="text" name="username">
                       <br>
                       password: <input type="text" name="password">
                       <br>
                       <input type="submit" name="submit" value="submit">
                     </form>
                   </body>
                 </html>
                        
              3. 發(fā)布運(yùn)行使用Log4J的web應(yīng)用
                 1) 將Log4J的JAR文件拷貝至目錄:<WEB應(yīng)用所在目錄>/WEB-INF/lib
                 2) 創(chuàng)建Log4J的配置文件log4j.properties, 存放目錄為:<WEB應(yīng)用所在目錄>/WEB-INF。內(nèi)容同前面配置文件示例。
                 3) 編譯Log4JServlet, 存放至目錄: <WEB應(yīng)用所在目錄>/WEB-INF/classes
                 4) 修改web.xml文件,加入以下內(nèi)容:

          xml 代碼
          1. <servlet>  
          2.   <servlet-name>log4jServlet</servlet-name>  
          3.   <servlet-class>Log4JServlet</servlet-class>  
          4.   <init-param>  
          5.     <param-name>profile</param-name>  
          6.     <param-value>/WEB-INF/log4j.properties</param-value>  
          7.   </init-param>  
          8.   <load-on-startup>1</load-on-startup>  
          9. </servlet>  


                 5) 啟動(dòng)服務(wù)器,訪問login.jsp頁面,在服務(wù)器控制臺(tái)上看到如下日志:
                    WARN - Thie is a log message from the myLogger
                    ERROR - Thie is a log message from the myLogger
                    FATAL - Thie is a log message from the myLogger
                    WARN - Thie is a log message from the myLogger.mySonLogger
                    ERROR - Thie is a log message from the myLogger.mySonLogger
                    FATAL - Thie is a log message from the myLogger.mySonLogger

                    另在<WEB應(yīng)用所在目錄>/WEB-INF目錄下看到一個(gè)log.txt文件,內(nèi)容如下:

                    WARN - Thie is a log message from the myLogger.mySonLogger
                    ERROR - Thie is a log message from the myLogger.mySonLogger
                    FATAL - Thie is a log message from the myLogger.mySonLogger

          posted @ 2009-05-04 17:19 lanxin1020 閱讀(167) | 評(píng)論 (0)編輯 收藏

          在實(shí)際編程時(shí),要使Log4j真正在系統(tǒng)中運(yùn)行事先還要對(duì)配置文件進(jìn)行定義。定義步驟就是對(duì)Logger、Appender及Layout的分別使用。
            Log4j支持兩種配置文件格式,一種是XML格式的文件,一種是java properties(key=value)【Java特性文件(鍵=值)】。下面我們介紹使用Java特性文件做為配置文件的方法
            具體如下:
            
            1、配置根Logger , 其語法為:
            log4j.rootLogger = [ level ] , appenderName1, appenderName2, …
            level : 是日志記錄的優(yōu)先級(jí),分為OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定義的級(jí)別。Log4j建議只使用四個(gè)級(jí)別,優(yōu)先級(jí)從高到低分別是ERROR、WARN、INFO、DEBUG。通過在這里定義的級(jí)別,您可以控制到應(yīng)用程序中相應(yīng)級(jí)別的日志信息的開關(guān)。比如在這里定 義了INFO級(jí)別,則應(yīng)用程序中所有DEBUG級(jí)別的日志信息將不被打印出來。
            appenderName:就是指定日志信息輸出到哪個(gè)地方。您可以同時(shí)指定多個(gè)輸出目的地。
            例如:log4j.rootLogger=info,A1,B2,C3
            
            2、配置日志信息輸出目的地 ,其語法為:
            log4j.appender.appenderName = fully.qualified.name.of.appender.class   //
               "fully.qualified.name.of.appender.class" 可以指定下面五個(gè)目的地中的一個(gè):
                1.org.apache.log4j.ConsoleAppender(控制臺(tái))
                2.org.apache.log4j.FileAppender(文件)
                3.org.apache.log4j.DailyRollingFileAppender(每天產(chǎn)生一個(gè)日志文件)
                4.org.apache.log4j.RollingFileAppender(文件大小到達(dá)指定尺寸的時(shí)候產(chǎn)生一個(gè)新的文件)
                5.org.apache.log4j.WriterAppender(將日志信息以流格式發(fā)送到任意指定的地方)
                  1.ConsoleAppender選項(xiàng)
                        Threshold=WARN:指定日志消息的輸出最低層次。
                        ImmediateFlush=true:默認(rèn)值是true,意謂著所有的消息都會(huì)被立即輸出。
                        Target=System.err:默認(rèn)情況下是:System.out,指定輸出控制臺(tái)
                  2.FileAppender 選項(xiàng)
                        Threshold=WARN:指定日志消息的輸出最低層次。
                        ImmediateFlush=true:默認(rèn)值是true,意謂著所有的消息都會(huì)被立即輸出。
                        File=mylog.txt:指定消息輸出到mylog.txt文件。
                        Append=false:默認(rèn)值是true,即將消息增加到指定文件中,false指將消息覆蓋指定的文件內(nèi)容。
                  3.DailyRollingFileAppender 選項(xiàng)
                        Threshold=WARN:指定日志消息的輸出最低層次。
                        ImmediateFlush=true:默認(rèn)值是true,意謂著所有的消息都會(huì)被立即輸出。
                        File=mylog.txt:指定消息輸出到mylog.txt文件。
                        Append=false:默認(rèn)值是true,即將消息增加到指定文件中,false指將消息覆蓋指定的文件內(nèi)容。
                        DatePattern='.'yyyy-ww:每周滾動(dòng)一次文件,即每周產(chǎn)生一個(gè)新的文件。當(dāng)然也可以指定按月、周、天、時(shí)和分。即對(duì)應(yīng)的格式如下:
                        1)'.'yyyy-MM: 每月
                        2)'.'yyyy-ww: 每周
                        3)'.'yyyy-MM-dd: 每天
                        4)'.'yyyy-MM-dd-a: 每天兩次
                        5)'.'yyyy-MM-dd-HH: 每小時(shí)
                        6)'.'yyyy-MM-dd-HH-mm: 每分鐘
                  4.RollingFileAppender 選項(xiàng)
                        Threshold=WARN:指定日志消息的輸出最低層次。
                        ImmediateFlush=true:默認(rèn)值是true,意謂著所有的消息都會(huì)被立即輸出。
                        File=mylog.txt:指定消息輸出到mylog.txt文件。
                        Append=false:默認(rèn)值是true,即將消息增加到指定文件中,false指將消息覆蓋指定的文件內(nèi)容。
                        MaxFileSize=100KB: 后綴可以是KB, MB 或者是 GB. 在日志文件到達(dá)該大小時(shí),將會(huì)自動(dòng)滾動(dòng),即將原來的內(nèi)容移到mylog.log.1文件。
                        MaxBackupIndex=2:指定可以產(chǎn)生的滾動(dòng)文件的最大數(shù)。 實(shí)際應(yīng)用:
            log4j.appender.A1=org.apache.log4j.ConsoleAppender //這里指定了日志輸出的第一個(gè)位置A1是控制臺(tái)ConsoleAppender
            
            3、配置日志信息的格式 , 其語法為:
            A. log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
                    "fully.qualified.name.of.layout.class" 可以指定下面4個(gè)格式中的一個(gè):
                  1.org.apache.log4j.HTMLLayout(以HTML表格形式布局),
                 2.org.apache.log4j.PatternLayout(可以靈活地指定布局模式),
                 3.org.apache.log4j.SimpleLayout(包含日志信息的級(jí)別和信息字符串),
                 4.org.apache.log4j.TTCCLayout(包含日志產(chǎn)生的時(shí)間、線程、類別等等信息)
                      1.HTMLLayout 選項(xiàng)
                        LocationInfo=true:默認(rèn)值是false,輸出java文件名稱和行號(hào)
                        Title=my app file: 默認(rèn)值是 Log4J Log Messages.
                      2.PatternLayout 選項(xiàng)
                        ConversionPattern=%m%n :指定怎樣格式化指定的消息。
                      3.XMLLayout   選項(xiàng)
                        LocationInfo=true:默認(rèn)值是false,輸出java文件和行號(hào)
            實(shí)際應(yīng)用:
              log4j.appender.A1.layout=org.apache.log4j.PatternLayout
              B . log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n
                  這里需要說明的就是日志信息格式中幾個(gè)符號(hào)所代表的含義:
                   -X號(hào): X信息輸出時(shí)左對(duì)齊;
                      %p: 輸出日志信息優(yōu)先級(jí),即DEBUG,INFO,WARN,ERROR,F(xiàn)ATAL,
                      %d: 輸出日志時(shí)間點(diǎn)的日期或時(shí)間,默認(rèn)格式為ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},輸出類似:2002年10月18日 22:10:28,921
                      %r: 輸出自應(yīng)用啟動(dòng)到輸出該log信息耗費(fèi)的毫秒數(shù)
                      %c: 輸出日志信息所屬的類目,通常就是所在類的全名
                      %t: 輸出產(chǎn)生該日志事件的線程名
                      %l: 輸出日志事件的發(fā)生位置,相當(dāng)于%C.%M(%F:%L)的組合,包括類目名、發(fā)生的線程,以及在代碼中的行數(shù)。舉例:Testlog4.main(TestLog4.java:10)
                      %x: 輸出和當(dāng)前線程相關(guān)聯(lián)的NDC(嵌套診斷環(huán)境),尤其用到像java servlets這樣的多客戶多線程的應(yīng)用中。
                      %%: 輸出一個(gè)"%"字符
                      %F: 輸出日志消息產(chǎn)生時(shí)所在的文件名稱
                      %L: 輸出代碼中的行號(hào)
                      %m: 輸出代碼中指定的消息,產(chǎn)生的日志具體信息
                      %n: 輸出一個(gè)回車換行符,Windows平臺(tái)為"\r\n",Unix平臺(tái)為"\n"輸出日志信息換行
                  可以在%與模式字符之間加上修飾符來控制其最小寬度、最大寬度、和文本的對(duì)齊方式。如:
                        1)%20c:指定輸出category的名稱,最小的寬度是20,如果category的名稱小于20的話,默認(rèn)的情況下右對(duì)齊。
                        2)%-20c:指定輸出category的名稱,最小的寬度是20,如果category的名稱小于20的話,"-"號(hào)指定左對(duì)齊。
                        3)%.30c:指定輸出category的名稱,最大的寬度是30,如果category的名稱大于30的話,就會(huì)將左邊多出的字符截掉,但小于30的話也不會(huì)有空格。
                        4)%20.30c:如果category的名稱小于20就補(bǔ)空格,并且右對(duì)齊,如果其名稱長于30字符,就從左邊交遠(yuǎn)銷出的字符截掉。
            這里上面三個(gè)步驟是對(duì)前面Log4j組件說明的一個(gè)簡化;下面給出一個(gè)具體配置例子,在程序中可以參照?qǐng)?zhí)行:
            log4j.rootLogger=INFO,A1,B2
            log4j.appender.A1=org.apache.log4j.ConsoleAppender
            log4j.appender.A1.layout=org.apache.log4j.PatternLayout
            log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n
            根據(jù)上面的日志格式,某一個(gè)程序的輸出結(jié)果如下:
            0  INFO 2003-06-13 13:23:46968 ClientWithLog4j Client socket: Socket[addr=localhost/127.0.0.1,port=8002,localport=2014]
            16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server says: 'Java server with log4j, Fri Jun 13 13:23:46 CST 2003'
            16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j GOOD
            16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server responds: 'Command 'HELLO' not understood.'
            16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j HELP
            16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server responds: 'Vocabulary: HELP QUIT'
            16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j QUIT

            4. # 當(dāng)輸出信息于回滾文件時(shí)
                log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender   //指定以文件的方式輸出日志
                  log4j.appender.ROLLING_FILE.Threshold=ERROR
                  log4j.appender.ROLLING_FILE.File=rolling.log   //文件位置,也可以用變量${java.home}、rolling.log
                  log4j.appender.ROLLING_FILE.Append=true
                  log4j.appender.ROLLING_FILE.MaxFileSize=10KB   //文件最大尺寸
                  log4j.appender.ROLLING_FILE.MaxBackupIndex=1   //備份數(shù)
                  log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
                  log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n     
          ××××××××××××××××××××××××××××××××××××××××××××××××

          附:Log4j比較全面的配置
          LOG4J的配置之簡單使它遍及于越來越多的應(yīng)用中了:Log4J配置文件實(shí)現(xiàn)了輸出到控制臺(tái)、文件、回滾文件、發(fā)送日志郵件、輸出到數(shù)據(jù)庫日志表、自定義標(biāo)簽等全套功能。擇其一二使用就夠用了,
          log4j.rootLogger=DEBUG,CONSOLE,A1,im
          log4j.addivity.org.apache=true
          # 應(yīng)用于控制臺(tái)
          log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
          log4j.appender.Threshold=DEBUG
          log4j.appender.CONSOLE.Target=System.out
          log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
          log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
          #log4j.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n
          #應(yīng)用于文件
          log4j.appender.FILE=org.apache.log4j.FileAppender
          log4j.appender.FILE.File=file.log
          log4j.appender.FILE.Append=false
          log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
          log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
          # Use this layout for LogFactor 5 analysis
          # 應(yīng)用于文件回滾
          log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
          log4j.appender.ROLLING_FILE.Threshold=ERROR
          log4j.appender.ROLLING_FILE.File=rolling.log   //文件位置,也可以用變量${java.home}、rolling.log
          log4j.appender.ROLLING_FILE.Append=true     //true:添加   false:覆蓋
          log4j.appender.ROLLING_FILE.MaxFileSize=10KB   //文件最大尺寸
          log4j.appender.ROLLING_FILE.MaxBackupIndex=1   //備份數(shù)
          log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
          log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

          #應(yīng)用于socket
          log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender
          log4j.appender.SOCKET.RemoteHost=localhost
          log4j.appender.SOCKET.Port=5001
          log4j.appender.SOCKET.LocationInfo=true
          # Set up for Log Facter 5
          log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout
          log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n

          # Log Factor 5 Appender
          log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
          log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000
          # 發(fā)送日志給郵件
          log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
          log4j.appender.MAIL.Threshold=FATAL
          log4j.appender.MAIL.BufferSize=10
          log4j.appender.MAIL.From=web@www.wuset.com
          log4j.appender.MAIL.SMTPHost=www.wusetu.com
          log4j.appender.MAIL.Subject=Log4J Message
          log4j.appender.MAIL.To=web@www.wusetu.com
          log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
          log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
          # 用于數(shù)據(jù)庫
          log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender
          log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test
          log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver
          log4j.appender.DATABASE.user=root
          log4j.appender.DATABASE.password=
          log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')
          log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout
          log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

          log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
          log4j.appender.A1.File=SampleMessages.log4j
          log4j.appender.A1.DatePattern=yyyyMMdd-HH'.log4j'
          log4j.appender.A1.layout=org.apache.log4j.xml.XMLLayout
          #自定義Appender
          log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender
          log4j.appender.im.host = mail.cybercorlin.net
          log4j.appender.im.username = username
          log4j.appender.im.password = password
          log4j.appender.im.recipient = corlin@cybercorlin.net
          log4j.appender.im.layout=org.apache.log4j.PatternLayout
          log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

          posted @ 2009-05-04 14:40 lanxin1020 閱讀(132) | 評(píng)論 (0)編輯 收藏
          Log4j下載
          在apache網(wǎng)站:jakarta.apache.org/log4j 可以免費(fèi)下載到Log4j最新版本的軟件包。

          Log4j使用
          Log4j的包下載完成后,解壓,將其中打包好的的log4j-1.x.x.jar導(dǎo)入你的工程LIB中。
          Log4j之所以受歡迎的原因之一是它的靈活性。Log4j提供了靈活的配置方法,默認(rèn)是調(diào)用BasicConfigurator.configure()來進(jìn)行配置,但如果只是簡單的調(diào)用BasicConfigurator.configure()來進(jìn)行配置工作,那么所有的配置都是固定的,不方便以后修改配置。另一種是動(dòng)態(tài)配置,Log4j提供了PropertyConfigurator.configure(……)來動(dòng)態(tài)配置,參數(shù)可以是一個(gè)properties文件所在路徑的String對(duì)象,可以是一個(gè)properties文件所在路徑的URL對(duì)象,也可以是一個(gè)properties對(duì)象。如果要用XML文件來配置信息,則可用類型的DOMConfigurator()函數(shù)來從一個(gè)XML文件中加載配置信息。這種方式更方便修改配置。

          動(dòng)態(tài)配置

          Java代碼
          1. package http;       
          2.       
          3. import org.apache.log4j.BasicConfigurator;       
          4. import org.apache.log4j.Logger;       
          5. import org.apache.log4j.PropertyConfigurator;       
          6. import org.apache.log4j.xml.DOMConfigurator;       
          7.       
          8. public class Log4jDemo {       
          9.     static Logger log = Logger.getLogger(Log4jDemo.class.getClass());       
          10.     /**     
          11.      * main     
          12.      * @param args     
          13.      */      
          14.     public static void main(String[] args) {       
          15.         BasicConfigurator.configure();//默認(rèn)配置       
          16.         PropertyConfigurator.configure("c:/log4j.properties");       
          17.         //動(dòng)態(tài)配置,參數(shù)可以是一個(gè)properties文件所在路徑的String對(duì)象       
          18.         //可以是一個(gè)properties文件所在路徑的URL對(duì)象,也可以是一個(gè)properties對(duì)象       
          19.                
          20.         DOMConfigurator.configure("c:/log4j.xml");//XML配置文件       
          21.       
          22.         //PropertyConfigurator.configure()的參數(shù)還可以是XML、Properties對(duì)象       
          23.                
          24.         //下面就可使用log4j       
          25.         log.info("info");       
          26.         log.debug("debug");       
          27.         log.error("error");       
          28.         log.warn("warn");       
          29.     }       
          30.       
          31. }      


          J2EE應(yīng)用log4j
          上面代碼描述了Log4j的簡單應(yīng)用,其實(shí)使用Log4j也就是這樣簡單方便。當(dāng)然除了上面的配置方法,還有其它,比如做一個(gè)J2EE應(yīng)用,在J2EE應(yīng)用使用Log4j,必須先在啟動(dòng)服務(wù)時(shí)加載Log4j的配置文件進(jìn)行初始化,可以在web.xml中進(jìn)行。


          java 代碼
          Java代碼
          1. import java.io.IOException;       
          2. import java.io.PrintWriter;       
          3.       
          4. import javax.servlet.ServletException;       
          5. import javax.servlet.http.HttpServlet;       
          6. import javax.servlet.http.HttpServletRequest;       
          7. import javax.servlet.http.HttpServletResponse;       
          8.       
          9.       
          10.       
          11. public class J2eeLog4jDemo extends HttpServlet {       
          12.       
          13.     public void destroy() {       
          14.         super.destroy();        
          15.     }          
          16.     public void doGet(HttpServletRequest request, HttpServletResponse response)       
          17.             throws ServletException, IOException {       
          18.     }       
          19.     public void doPost(HttpServletRequest request, HttpServletResponse response)       
          20.             throws ServletException, IOException {             
          21.     }       
          22.     public void init() throws ServletException {       
          23.         //通過web.xml來動(dòng)態(tài)取得配置文件       
          24.         String prefix = getServletContext().getRealPath("/");       
          25.         String file = getInitParameter("log4j");       
          26.       
          27.         //如果沒有給出相應(yīng)的配置文件,則不進(jìn)行初始化       
          28.         if(file != null)        
          29.         {       
          30.             PropertyConfigurator.configure(prefix+file);       
          31.         }       
          32.     }       
          33.       
          34. }      

          Web.xml 代碼
          Java代碼
          1. <servlet>      
          2. <servlet-name>j2eelog4jdemoservlet-name>      
          3. <servlet-class>J2eeLog4jDemoservlet-class>      
          4. <init-param>      
          5. <param-name>log4jparam-name>      
          6. <param-value>log4j.propertiesparam-value>      
          7. init-param>      
          8. <load-on-startup>1load-on-startup>  //設(shè)為1時(shí),Web容器啟動(dòng)即進(jìn)行加載    
          9. servlet  


          Spring配置Log4j
          Spring中配置Log4j只要配置applicationContext.xml文件,Log4j的配置文件放在Web工程的根目錄下,默認(rèn)是objectname/root下,可以在web.xml中設(shè)置工程根目錄.

          設(shè)置根目錄


          web.xml 代碼
          Java代碼
          1. <!--不定義webAppRootKey參數(shù),webAppRootKey就是缺省的"webapp.root"-->      
          2.  <context-param>      
          3.   <param-name>webAppRootKeyparam-name>      
          4.   <param-value>webapp.rootparam-value>      
          5.  context-param>  


          配置applicationContext.xml


          applicationContext.xml 代碼
          Java代碼
          1. <!--由Sprng載入的Log4j配置文件位置-->      
          2. <context-param>      
          3.  <param-name>log4jConfigLocationparam-name>      
          4.  <param-value>/WEB-INF/log4j.propertiesparam-value>      
          5.  <!--在這里定位配置文件,需要的是從root開始的絕對(duì)路徑-->      
          6. context-param>      
          7.       
          8.       
          9.       
          10. <!--Spring默認(rèn)刷新Log4j配置文件的間隔,單位為millisecond-->      
          11. <context-param>      
          12.  <param-name>log4jRefreshIntervalparam-name>      
          13.  <param-value>60000param-value>      
          14. context-param>      
          15.       
          16. <!--Spring log4j 監(jiān)聽器-->      
          17. <listener>      
          18.  <listener-class>org.springframework.web.util.Log4jConfigListenerlistener-class>      
          19. listener>     


          同時(shí)使用commons-logging和Log4j


          1)首先在classpath下尋找自己的配置文件commons-logging.properties,如果找到,則使用其中定義的Log實(shí)現(xiàn)類
          2)如果找不到commons-logging.properties文件,則在查找是否已定義系統(tǒng)環(huán)境變量org.apache.commons.logging.Log,找到則使用其定義的Log實(shí)現(xiàn)類
          3)否則,查看classpath中是否有Log4j的包,如果發(fā)現(xiàn),則自動(dòng)使用Log4j作為日志實(shí)現(xiàn)類
          4)否則,使用JDK自身的日志實(shí)現(xiàn)類(JDK1.4以后才有日志實(shí)現(xiàn)類)
          5)否則,使用commons-logging自己提供的一個(gè)簡單的日志實(shí)現(xiàn)類SimpleLog


          將commons-logging和Log4j的jar包都放置到classpath下,同時(shí)也將Log4j的配置文件放到classpath中,兩者就可以很好的合作,實(shí)現(xiàn)如下:
          Java代碼
          1. package com.doctorcom.model;       
          2.       
          3. import org.apache.commons.logging.Log;       
          4.       
          5. public class LogFactorySupport {           
          6.           
          7.     public Log getLog(){       
          8.         Log log = org.apache.commons.logging.LogFactory.getLog(LogFactorySupport.class);       
          9.         log.info("");       
          10.         log.debug("");       
          11.     }       
          12.            
          13. }   


          java 代碼

          Log4j配置內(nèi)容
          看一個(gè)簡單的java屬性配置文件log4j.properties:

          properties 代碼
          Java代碼
          1. #指定根Logger,及日志輸出級(jí)別,大于等于該級(jí)別的日志將被輸出( DEBUG < INFO < WARN < ERROR < FATAL ) 設(shè)為OFF可以關(guān)閉日志       
          2. log4j.rootLogger=DEBUG, A1,A2       
          3. #指定log輸出目的,這里設(shè)為輸出日志到指定目錄的文件my.log中       
          4. log4j.appender.A1=org.apache.log4j.FileAppender       
          5. log4j.appender.A1.File=\\logs\\my.log   #當(dāng)前根目錄下    
          6. #指定日志信息的格式       
          7. log4j.appender.A1.layout=org.apache.log4j.PatternLayout        
          8. log4j.appender.A1.layout.ConversionPattern=%r %d{yyyy-MM-dd HH:mm:ss} %c %p -%m%n       
          9.       
          10. #把A2輸出到控制臺(tái)       
          11. log4j.appender.A2=org.apache.log4j.ConsoleAppender       
          12. log4j.appender.A2.layout=org.apache.log4j.SimpleLayout        
          13.       
          14. #還可以單獨(dú)指定輸出某個(gè)包的日志級(jí)別       
          15. #log4j.logger.com.study.HelloLog4j=INFO   


          1、配置根Logger,其語法為:
          log4j.rootLogger = [ level ] , appenderName, appenderName2
          level:日志的級(jí)別,指定這條日志信息的重要性。分為ALL < DEBUG < INFO < WARN <error fatal=""></error>一般常用的為 DEBUG , INFO ,WARN ,ERROR四種,分別對(duì)應(yīng)Logger類的四種方法
          debug(Object message ) ;
          info(Object message ) ;
          warn(Object message ) ;
          error(Object message ) ;
          如果設(shè)置級(jí)別為INFO,則優(yōu)先級(jí)大于等于INFO級(jí)別(如:INFO、WARN、ERROR)的日志信息將可以被輸出,小于該級(jí)別的如:DEBUG將不會(huì)被輸出
          appenderName :就是指定日志信息輸出目的地,比如(打印到控制臺(tái),輸出到文件等)。同一條日志信息可以配置多個(gè)輸出目的地。

          2、配置log輸出目的地
          Log4j提供以下幾種:
          org.apache.log4j.ConsoleAppender(控制臺(tái))
          org.apache.log4j.FileAppender(文件)
          org.apache.log4j.DailyRollingFileAppender(每天產(chǎn)生一個(gè)日志文件)
          org.apache.log4j.RollingFileAppender(文件大小到達(dá)指定尺寸的時(shí)候產(chǎn)生一個(gè)新的文件)
          org.apache.log4j.WriterAppender(將日志信息以流格式發(fā)送到任意指定的地方)
          3、log信息的格式
          org.apache.log4j.HTMLLayout(HTML表格形式)
          org.apache.log4j.SimpleLayout(簡單格式的日志,只包括日志信息的級(jí)別和指定的信息字符串 ,如:DEBUG - Hello)
          org.apache.log4j.TTCCLayout(日志的格式包括日志產(chǎn)生的時(shí)間、線程、類別等等信息)
          org.apache.log4j.PatternLayout(靈活地自定義日志格式)

          當(dāng)使用org.apache.log4j.PatternLayout來自定義信息格式時(shí),可以使用
          log4j.appender.A1.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p -%m%n 來格式化信息
          %c    輸出所屬類的全名,可寫為 %c{Num} ,Num類名輸出的范圍  如:"com.sun.aaa.classB", %C{2}將使日志輸出輸出范圍為:aaa.classB
          %d    輸出日志時(shí)間其格式為 可指定格式 如 %d{HH:mm:ss}等
          %l    輸出日志事件發(fā)生位置,包括類目名、發(fā)生線程,在代碼中的行數(shù)
          %n    換行符
          %m    輸出代碼指定信息,如info(“message”),輸出message
          %p    輸出日志的優(yōu)先級(jí),即 FATAL ,ERROR 等
          %r    輸出從啟動(dòng)到顯示該條日志信息所耗費(fèi)的時(shí)間(毫秒數(shù))
          %t    輸出產(chǎn)生該日志事件的線程名
          posted @ 2009-05-04 14:37 lanxin1020 閱讀(161) | 評(píng)論 (0)編輯 收藏

          HashMap 與 TreeMap的區(qū)別

          HashMap通過hashcode對(duì)其內(nèi)容進(jìn)行快速查找,而TreeMap中所有的元素都保持著某種固定的順序,如果你需要得到一個(gè)有序的結(jié)果你就應(yīng)該使用TreeMap(HashMap中元素的排列順序是不固定的)。

          集合框架”提供兩種常規(guī)的Map實(shí)現(xiàn):HashMapTreeMap (TreeMap實(shí)現(xiàn)SortedMap接口)。在Map 中插入、刪除和定位元素,HashMap 是最好的選擇。但如果您要按自然順序或自定義順序遍歷鍵,那么TreeMap會(huì)更好。使用HashMap要求添加的鍵類明確定義了hashCode()equals()的實(shí)現(xiàn)。  這個(gè)TreeMap沒有調(diào)優(yōu)選項(xiàng),因?yàn)樵摌淇偺幱谄胶鉅顟B(tài)。

          2、兩個(gè)對(duì)象值相同(x.equals(y) == true),但卻可有不同的hash code,這句話對(duì)不對(duì)?hash code是什么意思

           hashcode是給一系列hash算法用的,比如hashtable。不同的對(duì)象應(yīng)該有不同的hashcode,同一個(gè)對(duì)象應(yīng)該有同樣的hashcode

          更正,不是同一個(gè)對(duì)象,而是相等的對(duì)象,應(yīng)該有相同的hashcode

          hash算法是什么啊,作用? hash算法基本就是為了將一個(gè)對(duì)象和一個(gè)整數(shù)對(duì)應(yīng)起來,不同的對(duì)象對(duì)應(yīng)不同的整數(shù)。
          (x.equals(y) == true)那這個(gè)的話就是去比較它們所對(duì)應(yīng)的整數(shù)?
          不是。有一個(gè)equals()函數(shù),和一個(gè)hashcode()函數(shù)

          3、String a="abc";String b=new String("abc");String c="abc";

          System.out.println(a==b);f
          System.out.println(a==c);t
          System.out.println(b==c);f
          System.out.println(a.equals(b));
          輸出結(jié)果是什么?
          為什么?

          4、a=0;b=0;
          if((a=3)>0|(b=3)>0){}
          if((a=3)>0||(b=3)>0){}分別說出a,b的值

          posted @ 2009-04-18 09:42 lanxin1020 閱讀(215) | 評(píng)論 (0)編輯 收藏
               摘要: TREEMAP的排序機(jī)制   1package com.sf;  2  3import java.text.CollationKey;  4import java.text.Collator;  5import java.util.Comparator;  6import ...  閱讀全文
          posted @ 2009-04-18 09:36 lanxin1020 閱讀(1092) | 評(píng)論 (0)編輯 收藏

          內(nèi)部類:定義在其他類里面的類。
          使用內(nèi)部類的理由:
          1.內(nèi)部類方法能夠訪問外部類的任何數(shù)據(jù)成員包括私有成員。
          2.對(duì)同一個(gè)包的其他類,內(nèi)部類是不可見的。
          3.匿名內(nèi)部類能夠方便的定義回調(diào)而不用寫太多方法。

          非靜態(tài)內(nèi)部類沒有默認(rèn)的構(gòu)造函數(shù),非靜態(tài)內(nèi)部類的構(gòu)造函數(shù)都有一個(gè)外圍類對(duì)象的引用。
          內(nèi)部類的特殊語法規(guī)則:
          1.相對(duì)內(nèi)部類,引用其外部類隱式對(duì)象的形式:OuterClass.this
          2.調(diào)用內(nèi)部類的構(gòu)造函數(shù):outerObject.new InnerClass(construction parameters);
          3.外部類外面引用內(nèi)部類:OuterClass.InnerClass

          內(nèi)部類是一種編譯器現(xiàn)象與虛擬機(jī)無關(guān)。編譯器將內(nèi)部類翻譯為用$分隔外部類名和內(nèi)部類名的常規(guī)類文件,虛擬機(jī)對(duì)此并無所知。
          使用javap -private OuterClass$InnerClass。javap這個(gè)工具確實(shí)挺不錯(cuò)的,對(duì)分析字節(jié)碼和源碼都有很大的幫助。
          可以看出詳細(xì)的內(nèi)部類源碼清單,其中包括了編譯器自動(dòng)添加的部分:
          public class Outer
          {
           public class Inner
           {
           }
          }
          當(dāng)內(nèi)部類是非靜態(tài)內(nèi)部類時(shí)相應(yīng)的內(nèi)部類的詳細(xì)源碼如下:
          Compiled from "Outer.java"
          public class Outer$Inner extends java.lang.Object{
              final Outer this$0;  //編譯器自動(dòng)在內(nèi)部類里面添加了指向外部類對(duì)象的引用
              public Outer$Inner(Outer);  //內(nèi)部類的構(gòu)造函數(shù)默認(rèn)有一個(gè)外部類對(duì)象作為參數(shù)。
          }

          當(dāng)內(nèi)部類是靜態(tài)內(nèi)部類時(shí):
          Compiled from "Outer.java"
          public class Outer$Inner extends java.lang.Object{
              public Outer$Inner(); //沒有了對(duì)外部類對(duì)象的引用
          }


          如下代碼模擬了上面內(nèi)部類的情形唯一不同的是這里的Inner沒有訪問Outer私有數(shù)據(jù)的權(quán)限:
          class Outer{
             Inner in = new Inner(this);
          }

          class Inner{
             public Inner(Outer outer){
                this.outer = outer;
             }
            
             private Outer outer;
          }

           

          //那么權(quán)限是如何控制的呢?當(dāng)內(nèi)部類中的方法訪問到外部類的私有數(shù)據(jù)時(shí)(注意如果內(nèi)部類沒有方法去訪問外部類的私有數(shù)據(jù)不會(huì)生成該靜態(tài)方法static int access$000(Outer);)
          public class Outer
          {
           private int i;
           public void methodOne()
           {
           }

           class Inner
           {
            public void print(){
             System.out.println(Outer.this.i);
            }
           }
          }

          相應(yīng)的外部類詳細(xì)源碼如下:
          public class Outer
          {
             public Outer();

             public void methodOne();
             static int access$000(Outer); //由編譯器合成的用于內(nèi)部類對(duì)外部類進(jìn)行特殊訪問權(quán)限的控制:這也是
                                          //為什么內(nèi)部類能夠訪問外部類中的私有數(shù)據(jù)的原因。
             private int i;
          }

          內(nèi)部類訪問外部類的private數(shù)據(jù)的這種方式很可能導(dǎo)致危險(xiǎn),雖然access$000不是一個(gè)合法的Java方法名,但是熟悉class文件結(jié)構(gòu)的黑客可以使用十六進(jìn)制編輯器輕松創(chuàng)建一個(gè)用虛擬機(jī)指令調(diào)用那個(gè)方法的類文件。由于隱秘的訪問方法需要擁有包可見性,所以攻擊代碼需要與被攻擊類放在同一個(gè)包中。總之,如果內(nèi)部類訪問了外部類的私有數(shù)據(jù)域,就有可能通過附加在外部類所在包中的其他類訪問私有數(shù)據(jù)。

          局部內(nèi)部類:定義在方法之中,因此局部類沒有public和private修飾符。對(duì)外界是完全隱藏的。
          局部類不僅能夠訪問外部類,還能訪問方法中的局部變量(或方法的參數(shù))。不過那些局部變量要聲明為final的。


          匿名內(nèi)部類:用外部類+$+數(shù)字的形式表示。一個(gè)外部類中有多個(gè)匿名內(nèi)部類時(shí),其生成的class文件對(duì)應(yīng)有Outer$(1、2、3)的形式表示。注意到該匿名內(nèi)部類是final的。
          final class Outer$1
          {
             Outer$1(Outer);

             public void method();

             final Outer this$0;
          }

          嵌套類:當(dāng)內(nèi)部類不需要訪問外部類的數(shù)據(jù)成員時(shí)應(yīng)該使用嵌套類。注意只有內(nèi)部類可以聲明為static的其他不行。
          在接口中聲明的內(nèi)部類自動(dòng)轉(zhuǎn)換為public static的,在接口中定義的成員自動(dòng)都是public static的。

          內(nèi)部類構(gòu)造函數(shù)的可見性與其類的可見性相同。

           

          posted @ 2009-04-16 14:06 lanxin1020 閱讀(149) | 評(píng)論 (0)編輯 收藏
          僅列出標(biāo)題
          共7頁: 上一頁 1 2 3 4 5 6 7 下一頁 
          主站蜘蛛池模板: 莫力| 沂水县| 明溪县| 宁安市| 永登县| 庆元县| 辰溪县| 察隅县| 郓城县| 门源| 舞阳县| 利津县| 大田县| 房产| 屏边| 凤冈县| 台北市| 崇州市| 沙洋县| 江都市| 清原| 莆田市| 沁源县| 阳东县| 东阳市| 禹州市| 甘泉县| 衢州市| 台湾省| 苏尼特右旗| 铜梁县| 息烽县| 策勒县| 淮南市| 海口市| 崇州市| 佛山市| 商城县| 龙游县| 涿州市| 新竹县|