Android系統在超級終端下必會的命令大全(adb shell命令大全)

 
1. 顯示系統中全部Android平臺: 

    android list targets 

2. 顯示系統中全部AVD(模擬器): 

    android list avd 

3. 創建AVD(模擬器): 

    android create avd --name 名稱 --target 平臺編號 

4. 啓動模擬器: 

    emulator -avd 名稱 -sdcard ~/名稱.img (-skin 1280x800) 

5. 刪除AVD(模擬器): 

    android delete avd --name 名稱 

6. 創建SDCard: 

    mksdcard 1024M ~/名稱.img 

7. AVD(模擬器)所在位置: 

    Linux(~/.android/avd)      Windows(C:\Documents and Settings\Administrator\.android\avd) 

8. 啓動DDMS: 

    ddms 

9. 顯示當前運行的全部模擬器: 

    adb devices 

10. 對某一模擬器執行命令: 

      abd -s 模擬器編號 命令 

11. 安裝應用程序: 

      adb install -r 應用程序.apk 

12. 獲取模擬器中的文件: 

      adb pull <remote> <local> 

13. 向模擬器中寫文件: 

      adb push <local> <remote> 

14. 進入模擬器的shell模式: 

      adb shell 

15. 啓動SDK,文檔,實例下載管理器: 

      android 

16. 缷載apk包: 

      adb shell 

      cd data/app 

      rm apk包 

      exit 

      adb uninstall apk包的主包名 

      adb install -r apk包 

17. 查看adb命令幫助信息: 

      adb help 

18. 在命令行中查看LOG信息: 

      adb logcat -s 標籤名 

19. adb shell後面跟的命令主要來自: 

      源碼\system\core\toolbox目錄和源碼\frameworks\base\cmds目錄。 

20. 刪除系統應用: 

      adb remount (重新掛載系統分區,使系統分區重新可寫)。 

      adb shell 

      cd system/app 

      rm *.apk 

21. 獲取管理員權限: 

      adb root 

22. 啓動Activity: 

      adb shell am start -n 包名/包名+類名(-n 類名,-a action,-d date,-m MIME-TYPE,-c category,-e 擴展數據,等)。 

23、發佈端口: 

    你可以設置任意的端口號,做爲主機向模擬器或設備的請求端口。如: 
adb forward tcp:5555 tcp:8000 

24、複製文件: 

    你可向一個設備或從一個設備中複製文件, 
     複製一個文件或目錄到設備或模擬器上: 
  adb push <source> <destination></destination></source> 
      如:adb push test.txt /tmp/test.txt 
     從設備或模擬器上覆制一個文件或目錄: 
     adb pull <source> <destination></destination></source> 
     如:adb pull /addroid/lib/libwebcore.so . 

25、搜索模擬器/設備的實例: 

     取得當前運行的模擬器/設備的實例的列表及每個實例的狀態: 
    adb devices 

26、查看bug報告: 
adb bugreport 
27、記錄無線通訊日誌: 

    一般來說,無線通訊的日誌非常多,在運行時沒必要去記錄,但我們還是可以通過命令,設置記錄: 
    adb shell 
    logcat -b radio 

28、獲取設備的ID和序列號: 

     adb get-product 
     adb get-serialno 

29、訪問數據庫SQLite3 

     adb shell 
     sqlite3 

busybox 

BusyBox 是標準 Linux 工具的一個單個可執行實現。BusyBox 包含了一些簡單的工具,例如 cat 和 echo,還包含了一些更大、更復雜的工具,例如 grep、find、mount 以及 telnet。有些人將 BusyBox 稱爲 Linux 工具裏的瑞士軍刀.簡單的說BusyBox就好像是個大工具箱,它集成壓縮了 Linux 的許多工具和命令。 

1、 BusyBox 的誕生 
  BusyBox 最初是由 Bruce Perens 在 1996 年爲 Debian GNU/Linux 安裝盤編寫的。其目標是在一張軟盤上創建一個可引導的 GNU/Linux 系統,這可以用作安裝盤和急救盤。 
  2、busybox的用法 
  可以這樣用busybox 
  #busybox ls 
  他的功能就相當運行ls命令 
  最常用的用法是建立指向busybox的鏈接,不同的鏈接名完成不同的功能. 
  #ln -s busybox ls 
  #ln -s busybox rm 
  #ln -s busybox mkdir 
  然後分別運行這三個鏈接: 
  #./ls 
  #./rm 
  #./mkdir 
  就可以分別完成了ls rm 和mkdir命令的功能.雖然他們都指向同一個可執行程序busybox,但是隻要鏈接名不同,完成的功能就不同,很多linux網站都提供busybox的源代碼下載。 
  3、配置busybox 
  busybox的配置程序和linux內核菜單配置方式簡直一模一樣.熟悉用make menuconfig方式配置linux內核的朋友很容易上手. 
  #cp busybox-1.00.tar.gz /babylinux 
  #cd /babylinux 
  #tar xvfz busybox-1.00.tar.gz 
  #cd busybox-1.00 
  #make menuconfig 
  下面是需要編譯進busybox的功能選項。 
  General Configuration應該選的選項 
  Show verbose applet usage messages 
  Runtime SUID/SGID configuration via /etc/busybox.conf 
  Build Options 
  Build BusyBox as a static binary (no shared libs) 
  這個選項是一定要選擇的,這樣才能把busybox編譯成靜態鏈接的可執行文件,運行時才獨立於其他函數庫.否則必需要其他庫文件才能運行,在單一個linux內核不能使它正常工作. 
  Installation Options 
  Don't use /usr 
  這個選項也一定要選,否則make install 後busybox將安裝在原系統的/usr下,這將覆蓋掉系統原有的命令.選擇這個選項後,make install後會在busybox目錄下生成一個叫_install的目錄,裏面有busybox和指向它的鏈接. 
  其它選項都是一些linux基本命令選項,自己需要哪些命令就編譯進去,一般用默認的就可以了,配置好後退出並保存。 
  4、編譯並安裝busybox 
  #make 
  #make install 
  編譯好後在busybox目錄下生成子目錄_install,裏面的內容: 
  drwxr-xr-x 2 root root 4096 11月 24 15:28 bin 
  rwxrwxrwx 1 root root 11 11月 24 15:28 linuxrc -> bin/busybox 
  drwxr-xr-x 2 root root 4096 11月 24 15:28 sbin 
  其中可執行文件busybox在bin目錄下,其他的都是指向他的符號鏈接. 

Android系統在超級終端下必會的命令大全(二) 

一、安裝和登錄命令 
reboot 
1.作用 
reboot命令的作用是重新啓動計算機,它的使用權限是系統管理者。 
2.格式 
reboot [-n] [-w] [-d] [-f] [-i] 
3.主要參數 
-n: 在重開機前不做將記憶體資料寫回硬盤的動作。 
-w: 並不會真的重開機,只是把記錄寫到/var/log/wtmp文件裏。 
-d: 不把記錄寫到/var/log/wtmp文件裏(-n這個參數包含了-d)。 
-i: 在重開機之前先把所有與網絡相關的裝置停止。 
mount 
1.作用 
mount命令的作用是加載文件系統,它的用權限是超級用戶或/etc/fstab中允許的使用者。 
2.格式 
mount -a [-fv] [-t vfstype] [-n] [-rw] [-F] device dir 
3.主要參數 
-h:顯示輔助信息。 
-v:顯示信息,通常和-f用來除錯。 
-a:將/etc/fstab中定義的所有文件系統掛上。 
-F:這個命令通常和-a一起使用,它會爲每一個mount的動作產生一個行程負責執行。在系統需要掛上大量NFS文件系統時可以加快加載的速度。 
-f:通常用於除錯。它會使mount不執行實際掛上的動作,而是模擬整個掛上的過程,通常會和-v一起使用。 
-t vfstype:顯示被加載文件系統的類型。 
-n:一般而言,mount掛上後會在/etc/mtab中寫入一筆資料,在系統中沒有可寫入文件系統的情況下,可以用這個選項取消這個動作。 
4.應用技巧 
在 Linux和Unix系統上,所有文件都是作爲一個大型樹(以/爲根)的一部分訪問的。要訪問CD-ROM上的文件,需要將CD-ROM設備掛裝在文件樹中的某個掛裝點。如果發行版安裝了自動掛裝包,那麼這個步驟可自動進行。在Linux中,如果要使用硬盤、光驅等儲存設備,就得先將它加載,當儲存設備掛上了之後,就可以把它當成一個目錄來訪問。掛上一個設備使用mount命令。在使用mount這個指令時,至少要先知道下列三種信息:要加載對象的文件系統類型、要加載對象的設備名稱及要將設備加載到哪個目錄下。 
(1)Linux可以識別的文件系統 
◆ Windows 95/98常用的FAT 32文件系統:vfat ; 
◆ Win NT/2000 的文件系統:ntfs ; 
◆ OS/2用的文件系統:hpfs; 
◆ Linux用的文件系統:ext2、ext3; 
◆ CD-ROM光盤用的文件系統:iso9660。 
雖然vfat是指FAT 32系統,但事實上它也兼容FAT 16的文件系統類型。 
(2)確定設備的名稱 
在Linux中,設備名稱通常都存在/dev裏。這些設備名稱的命名都是有規則的,可以用“推理”的方式把設備名稱找出來。例如,/dev/hda1這個 
IDE設備,hd是Hard Disk(硬盤)的,sd是SCSI Device,fd是Floppy Device(或是Floppy 
Disk?)。a代表第一個設備,通常IDE接口可以接上4個IDE設備(比如4塊硬盤)。所以要識別IDE硬盤的方法分別就是hda、hdb、hdc、 
hdd。hda1中的“1”代表hda的第一個硬盤分區 
(partition),hda2代表hda的第二主分區,第一個邏輯分區從hda5開始,依此類推。此外,可以直接檢查/var/log/messages文件,在該文件中可以找到計算機開機後系統已辨認出來的設備代號。 
(3)查找掛接點 
在決定將設備掛接之前,先要查看一下計算機是不是有個/mnt的空目錄,該目錄就是專門用來當作掛載點(MountPoint)的目錄。建議在/mnt裏建幾個/mnt/cdrom、/mnt/floppy、/mnt/mo等目錄,當作目錄的專用掛載點。舉例而言,如要掛載下列5個設備,其執行指令可能如下 (假設都是Linux的ext2系統,如果是Windows XX請將ext2改成vfat): 
軟盤 ===>mount -t ext2 /dev/fd0 /mnt/floppy 
cdrom ===>mount -t iso9660 /dev/hdc /mnt/cdrom 
SCSI cdrom ===>mount -t iso9660 /dev/sdb /mnt/scdrom 
SCSI cdr ===>mount -t iso9660 /dev/sdc /mnt/scdr 
不過目前大多數較新的Linux發行版本(包括紅旗 Linux、中軟Linux、Mandrake Linux等)都可以自動掛裝文件系統,但Red Hat Linux除外。 
umount 
1.作用 
umount命令的作用是卸載一個文件系統,它的使用權限是超級用戶或/etc/fstab中允許的使用者。 
2.格式 
unmount -a [-fFnrsvw] [-t vfstype] [-n] [-rw] [-F] device dir 
3.使用說明 
umount 
命令是mount命令的逆操作,它的參數和使用方法和mount命令是一樣的。Linux掛裝CD-ROM後,會鎖定CD—ROM,這樣就不能用CD- 
ROM面板上的Eject按鈕彈出它。但是,當不再需要光盤時,如果已將/cdrom作爲符號鏈接,請使用umount/cdrom來卸裝它。僅當無用戶 
正在使用光盤時,該命令纔會成功。該命令包括了將帶有當前工作目錄當作該光盤中的目錄的終端窗口。 
exit 
1.作用 
exit命令的作用是退出系統,它的使用權限是所有用戶。 
2.格式 
exit 
3.參數 
exit命令沒有參數,運行後退出系統進入登錄界面。 




-------------------------------------------------------------------------------- 
作者: ☆-☆    時間: 2010-6-8 11:52 

Android系統在超級終端下必會的命令大全(三) 
二、文件處理命令 
mkdir 
1.作用 
mkdir命令的作用是建立名稱爲dirname的子目錄,與MS DOS下的md命令類似,它的使用權限是所有用戶。 
2.格式 
mkdir [options] 目錄名 
3.[options]主要參數 
-m, --mode=模式:設定權限,與chmod類似。 
-p, --parents:需要時創建上層目錄;如果目錄早已存在,則不當作錯誤。 
-v, --verbose:每次創建新目錄都顯示信息。 
--version:顯示版本信息後離開。 
4.應用實例 
在進行目錄創建時可以設置目錄的權限,此時使用的參數是“-m”。假設要創建的目錄名是“tsk”,讓所有用戶都有rwx(即讀、寫、執行的權限),那麼可以使用以下命令: 
$ mkdir -m 777 tsk 
grep 
1.作用 
grep命令可以指定文件中搜索特定的內容,並將含有這些內容的行標準輸出。grep全稱是Global Regular Expression Print,表示全局正則表達式版本,它的使用權限是所有用戶。 
2.格式 
grep [options] 
3.主要參數 
[options]主要參數: 
-c:只輸出匹配行的計數。 
-I:不區分大小寫(只適用於單字符)。 
-h:查詢多文件時不顯示文件名。 
-l:查詢多文件時只輸出包含匹配字符的文件名。 
-n:顯示匹配行及行號。 
-s:不顯示不存在或無匹配文本的錯誤信息。 
-v:顯示不包含匹配文本的所有行。 
pattern正則表達式主要參數: 
\:忽略正則表達式中特殊字符的原有含義。 
^:匹配正則表達式的開始行。 
$: 匹配正則表達式的結束行。 
\:到匹配正則表達式的行結束。 
[ ]:單個字符,如[A]即A符合要求 。 
[ - ]:範圍,如[A-Z],即A、B、C一直到Z都符合要求 。 
。:所有的單個字符。 
* :有字符,長度可以爲0。 
正則表達式是Linux/Unix系統中非常重要的概念。正則表達式(也稱爲“regex”或“regexp”)是一個可以描述一類字符串的模式(Pattern)。如果一個字符串可以用某個正則表達式來描述,我們就說這個字符和該正則表達式匹配(Match)。這和DOS中用戶可以使用通配符 
“*”代表任意字符類似。在Linux系統上,正則表達式通常被用來查找文本的模式,以及對文本執行“搜索-替換”操作和其它功能。 
4.應用實例 
查詢DNS服務是日常工作之一,這意味着要維護覆蓋不同網絡的大量IP地址。有時IP地址會超過2000個。如果要查看nnn.nnn網絡地址,但是卻忘了第二部分中的其餘部分,只知到有兩個句點,例如nnn nn..。要抽取其中所有nnn.nnn IP地址,使用[0-9 ]\{3 
\}\.[0-0\{3\}\。含義是任意數字出現3次,後跟句點,接着是任意數字出現3次,後跟句點。 
$grep ’[0-9 ]\{3 \}\.[0-0\{3\}\’ ipfile 
補充說明,grep家族還包括fgrep和egrep。fgrep是fix grep,允許查找字符串而不是一個模式;egrep是擴展grep,支持基本及擴展的正則表達式,但不支持\q模式範圍的應用及與之相對應的一些更加規範的模式。 
dd 
1.作用 
dd命令用來複制文件,並根據參數將數據轉換和格式化。 
2.格式 
dd [options] 
3.[opitions]主要參數 
bs=字節:強迫 ibs=及obs=。 
cbs=字節:每次轉換指定的。 
conv=關鍵字:根據以逗號分隔的關鍵字表示的方式來轉換文件。 
count=塊數目:只複製指定的輸入數據。 
ibs=字節:每次讀取指定的。 
if=文件:讀取內容,而非標準輸入的數據。 
obs=字節:每次寫入指定的。 
of=文件:將數據寫入,而不在標準輸出顯示。 
seek=塊數目:先略過以obs爲單位的指定的輸出數據。 
skip=塊數目:先略過以ibs爲單位的指定的輸入數據。 
4.應用實例 
dd命令常常用來製作Linux啓動盤。先找一個可引導內核,令它的根設備指向正確的根分區,然後使用dd命令將其寫入軟盤: 
$ rdev vmlinuz /dev/hda 
$dd if=vmlinuz of=/dev/fd0 
上面代碼說明,使用rdev命令將可引導內核vmlinuz中的根設備指向/dev/hda,請把“hda”換成自己的根分區,接下來用dd命令將該內核寫入軟盤。 



find 
1.作用 
find命令的作用是在目錄中搜索文件,它的使用權限是所有用戶。 
2.格式 
find [path][options][expression] 
path指定目錄路徑,系統從這裏開始沿着目錄樹向下查找文件。它是一個路徑列表,相互用空格分離,如果不寫path,那麼默認爲當前目錄。 
3.主要參數 
[options]參數: 
-depth:使用深度級別的查找過程方式,在某層指定目錄中優先查找文件內容。 
-maxdepth levels:表示至多查找到開始目錄的第level層子目錄。level是一個非負數,如果level是0的話表示僅在當前目錄中查找。 
-mindepth levels:表示至少查找到開始目錄的第level層子目錄。 
-mount:不在其它文件系統(如Msdos、Vfat等)的目錄和文件中查找。 
-version:打印版本。 
[expression]是匹配表達式,是find命令接受的表達式,find命令的所有操作都是針對表達式的。它的參數非常多,這裏只介紹一些常用的參數。 
—name:支持統配符*和?。 
-atime n:搜索在過去n天讀取過的文件。 
-ctime n:搜索在過去n天修改過的文件。 
-group grpoupname:搜索所有組爲grpoupname的文件。 
-user 用戶名:搜索所有文件屬主爲用戶名(ID或名稱)的文件。 
-size n:搜索文件大小是n個block的文件。 
-print:輸出搜索結果,並且打印。 
4.應用技巧 
find命令查找文件的幾種方法: 
(1)根據文件名查找 
例如,我們想要查找一個文件名是lilo.conf的文件,可以使用如下命令: 
find / -name lilo.conf 
find命令後的“/”表示搜索整個硬盤。 
(2)快速查找文件 
根據文件名查找文件會遇到一個實際問題,就是要花費相當長的一段時間,特別是大型Linux文件系統和大容量硬盤文件放在很深的子目錄中時。如果我們知道了這個文件存放在某個目錄中,那麼只要在這個目錄中往下尋找就能節省很多時間。比如smb.conf文件,從它的文件後綴“.conf”可以判斷這是一個配置文件,那麼它應該在/etc目錄內,此時可以使用下面命令: 
find /etc -name smb.conf 
這樣,使用“快速查找文件”方式可以縮短時間。 
(3)根據部分文件名查找方法 
有時我們知道只某個文件包含有abvd這4個字,那麼要查找系統中所有包含有這4個字符的文件可以輸入下面命令:
find / -name ’*abvd*’ 
輸入這個命令以後,Linux系統會將在/目錄中查找所有的包含有abvd這4個字符的文件(其中*是通配符),比如abvdrmyz等符合條件的文件都能顯示出來。 
(4) 使用混合查找方式查找文件 
find命令可以使用混合查找的方法,例如,我們想在/etc目錄中查找大於500000字節,並且在24小時內修改的某個文件,則可以使用-and (與)把兩個查找參數鏈接起來組合成一個混合的查找方式。 
find /etc -size +500000c -and -mtime +1 
mv 
1.作用 
mv命令用來爲文件或目錄改名,或者將文件由一個目錄移入另一個目錄中,它的使用權限是所有用戶。該命令如同DOS命令中的ren和move的組合。 
2.格式 
mv[options] 源文件或目錄 目標文件或目錄 
3.[options]主要參數 
-i:交互方式操作。如果mv操作將導致對已存在的目標文件的覆蓋,此時系統詢問是否重寫,要求用戶回答“y”或“n”,這樣可以避免誤覆蓋文件。 
-f:禁止交互操作。mv操作要覆蓋某個已有的目標文件時不給任何指示,指定此參數後i參數將不再起作用。 
4.應用實例 
(1)將/usr/cbu中的所有文件移到當前目錄(用“.”表示)中: 
$ mv /usr/cbu/ * . 
(2)將文件cjh.txt重命名爲wjz.txt: 
$ mv cjh.txt wjz.txt  
ls 
1.作用 
ls命令用於顯示目錄內容,類似DOS下的dir命令,它的使用權限是所有用戶。 
2.格式 
ls [options][filename] 
3.options主要參數 
-a, --all:不隱藏任何以“.” 字符開始的項目。 
-A, --almost-all:列出除了“ . ”及 “.. ”以外的任何項目。 
--author:印出每個文件著作者。 
-b, --escape:以八進制溢出序列表示不可打印的字符。 
--block-size=大小:塊以指定的字節爲單位。 
-B, --ignore-backups:不列出任何以 ~ 字符結束的項目。 
-f:不進行排序,-aU參數生效,-lst參數失效。 
-F, --classify:加上文件類型的指示符號 (*/=@| 其中一個)。 
-g:like -l, but do not list owner。 
-G, --no-group:inhibit display of group information。 
-i, --inode:列出每個文件的inode號。 
-I, --ignore=樣式:不印出任何符合Shell萬用字符的項目。 
-k:即--block-size=1K。 
-l:使用較長格式列出信息。 
-L, --dereference:當顯示符號鏈接的文件信息時,顯示符號鏈接所指示的對象,而並非符號鏈接本身的信息。 
-m:所有項目以逗號分隔,並填滿整行行寬。 
-n, --numeric-uid-gid:類似-l,但列出UID及GID號。 
-N, --literal:列出未經處理的項目名稱,例如不特別處理控制字符。 
-p, --file-type:加上文件類型的指示符號 (/=@| 其中一個)。 
-Q, --quote-name:將項目名稱括上雙引號。 
-r, --reverse:依相反次序排列。 
-R, --recursive:同時列出所有子目錄層。 
-s, --size:以塊大小爲序。 
4.應用舉例 
ls 
命令是Linux系統使用頻率最多的命令,它的參數也是Linux命令中最多的。使用ls命令時會有幾種不同的顏色,其中藍色表示是目錄,綠色表示是可執 
行文件,紅色表示是壓縮文件,淺藍色表示是鏈接文件,加粗的黑色表示符號鏈接,灰色表示是其它格式文件。ls最常使用的是ls- l。 
文 
件類型開頭是由10個字符構成的字符串。其中第一個字符表示文件類型,它可以是下述類型之一:-(普通文件)、d(目錄)、l(符號鏈接)、b(塊設備文件)、c(字符設備文件)。後面的9個字符表示文件的訪問權限,分爲3組,每組3位。第一組表示文件屬主的權限,第二組表示同組用戶的權限,第三組表示其他用戶的權限。每一組的三個字符分別表示對文件的讀(r)、寫(w)和執行權限(x)。對於目錄,表示進入權限。s表示當文件被執行時,把該文件的UID 或GID賦予執行進程的UID(用戶ID)或GID(組ID)。t表示設置標誌位(留在內存,不被換出)。如果該文件是目錄,那麼在該目錄中的文件只能被超級用戶、目錄擁有者或文件屬主刪除。如果它是可執行文件,那麼在該文件執行後,指向其正文段的指針仍留在內存。這樣再次執行它時,系統就能更快地裝入該文件。接着顯示的是文件大小、生成時間、文件或命令名稱。 
Android系統在超級終端下必會的命令大全(四) 
diff 
1.作用 
diff命令用於兩個文件之間的比較,並指出兩者的不同,它的使用權限是所有用戶。 
2.格式 
diff [options] 源文件 目標文件 
3.[options]主要參數 
-a:將所有文件當作文本文件來處理。 
-b:忽略空格造成的不同。 
-B:忽略空行造成的不同。 
-c:使用綱要輸出格式。 
-H:利用試探法加速對大文件的搜索。 
-I:忽略大小寫的變化。 
-n --rcs:輸出RCS格式。 
cmp 
1.作用 
cmp(“compare”的縮寫)命令用來簡要指出兩個文件是否存在差異,它的使用權限是所有用戶。 
2.格式 
cmp[options] 文件名 
3.[options]主要參數 
-l: 將字節以十進制的方式輸出,並方便將兩個文件中不同的以八進制的方式輸出。 
cat 
1.作用 
cat(“concatenate”的縮寫)命令用於連接並顯示指定的一個和多個文件的有關信息,它的使用權限是所有用戶。 
2.格式 
cat [options] 文件1 文件2…… 
3.[options]主要參數 
-n:由第一行開始對所有輸出的行數編號。 
-b:和-n相似,只不過對於空白行不編號。 
-s:當遇到有連續兩行以上的空白行時,就代換爲一行的空白行。 
4.應用舉例 
(1)cat命令一個最簡單的用處是顯示文本文件的內容。例如,我們想在命令行看一下README文件的內容,可以使用命令: 
$ cat README  
(2)有時需要將幾個文件處理成一個文件,並將這種處理的結果保存到一個單獨的輸出文件。cat命令在其輸入上接受一個或多個文件,並將它們作爲一個單獨的文件打印到它的輸出。例如,把README和INSTALL的文件內容加上行號(空白行不加)之後,將內容附加到一個新文本文件File1 中: 
$ cat README INSTALL File1 
(3)cat 還有一個重要的功能就是可以對行進行編號。這種功能對於程序文檔的編制,以及法律和科學文檔的編制很方便,打印在左邊的行號使得參考文檔的某一部分變得容易,這些在編程、科學研究、業務報告甚至是立法工作中都是非常重要的。對行進行編號功能有-b(只能對非空白行進行編號)和-n(可以對所有行進行編號)兩個參數: 
$ cat -b /etc/named.conf 
ln 
1.作用 
ln命令用來在文件之間創建鏈接,它的使用權限是所有用戶。 
2.格式 
ln [options] 源文件 [鏈接名] 
3.參數 
-f:鏈結時先將源文件刪除。 
-d:允許系統管理者硬鏈結自己的目錄。 
-s:進行軟鏈結(Symbolic Link)。 
-b:將在鏈結時會被覆蓋或刪除的文件進行備份。 
鏈接有兩種,一種被稱爲硬鏈接(Hard Link),另一種被稱爲符號鏈接(Symbolic Link)。默認情況下,ln命令產生硬鏈接。硬連接指通過索引節點來進行的連接。在Linux的文件系統中,保存在磁盤分區中的文件不管是什麼類型都給它分配一個編號,稱爲索引節點號(InodeIndex)。在Linux中,多個文件名指向同一索引節點是存在的。一般這種連接就是硬連接。硬連接的作用是允許一個文件擁有多個有效路徑名,這樣用戶就可以建立硬連接到重要文件,以防止“誤刪”的功能。其原因如上所述,因爲對應該目錄的索引節點有一個以上的連接。只刪除一個連接並不影響索引節點本身和其它的連接,只有當最後一個連接被刪除後,文件的數據塊及目錄的連接纔會被釋放。也就是說,文件纔會被真正刪除。與硬連接相對應,Lnux系統中還存在另一種連接,稱爲符號連接(Symbilc Link),也叫軟連接。軟鏈接文件有點類似於Windows的快捷方式。它實際上是特殊文件的一種。在符號連接中,文件實際上是一個文本文件,其中包含的有另一文件的位置信息。 
-------------------------------------------------------------------------------- 
作者: ☆-☆    時間: 2010-6-8 11:55 

本帖最後由 ☆-☆ 於 2010-6-8 11:59 編輯 

Android系統在超級終端下必會的命令大全(五) 
系統管理命令 
df 
1.作用 
df命令用來檢查文件系統的磁盤空間佔用情況,使用權限是所有用戶。 
2.格式 
df [options] 
3.主要參數 
-s:對每個Names參數只給出佔用的數據塊總數。 
-a:遞歸地顯示指定目錄中各文件及子目錄中各文件佔用的數據塊數。若既不指定-s,也不指定-a,則只顯示Names中的每一個目錄及其中的各子目錄所佔的磁盤塊數。 
-k:以1024字節爲單位列出磁盤空間使用情況。 
-x:跳過在不同文件系統上的目錄不予統計。 
-l:計算所有的文件大小,對硬鏈接文件則計算多次。 
-i:顯示inode信息而非塊使用量。 
-h:以容易理解的格式印出文件系統大小,例如136KB、254MB、21GB。 
-P:使用POSIX輸出格式。 
-T:顯示文件系統類型。 
4.說明 
df 命令被廣泛地用來生成文件系統的使用統計數據,它能顯示系統中所有的文件系統的信息,包括總容量、可用的空閒空間、目前的安裝點等。超級權限用戶使用df 命令時會發現這樣的情況:某個分區的容量超過了100%。這是因爲Linux系統爲超級用戶保留了10%的空間,由其單獨支配。也就是說,對於超級用戶而言,他所見到的硬盤容量將是110%。這樣的安排對於系統管理而言是有好處的,當硬盤被使用的容量接近100%時系統管理員還可以正常工作。 
5.應用實例 
Linux支持的文件系統非常多,包括JFS、ReiserFS、ext、ext2、ext3、ISO9660、XFS、Minx、vfat、MSDOS等。使用df -T命令查看磁盤空間時還可以得到文件系統的信息: 
#df -T 
文件系統 類型 容量 已用 可用 已用% 掛載點 
/dev/hda7 reiserfs 5.2G 1.6G 3.7G 30% / 
/dev/hda1 vfat 2.4G 1.6G 827M 66% /windows/C 
/dev/hda5 vfat 3.0G 1.7G 1.3G 57% /windows/D 
/dev/hda9 vfat 3.0G 2.4G 566M 82% /windows/E 
/dev/hda10 NTFS 3.2G 573M 2.6G 18% /windows/F 
/dev/hda11 vfat 1.6G 1.5G 23M 99% /windows/G 
從上面除了可以看到磁盤空間的容量、使用情況外,分區的文件系統類型、掛載點等信息也一覽無遺。 
top 
1.作用 
top命令用來顯示執行中的程序進程,使用權限是所有用戶。 
2.格式 
top [-] [d delay] [q] [c] [S] [n] 
3.主要參數 
d:指定更新的間隔,以秒計算。 
q:沒有任何延遲的更新。如果使用者有超級用戶,則top命令將會以最高的優先序執行。 
c:顯示進程完整的路徑與名稱。 
S:累積模式,會將己完成或消失的子行程的CPU時間累積起來。 
s:安全模式。 
i:不顯示任何閒置(Idle)或無用(Zombie)的行程。 
n:顯示更新的次數,完成後將會退出top。 
4.說明 
top命令是Linux系統管理的一個主要命令,通過它可以獲得許多信息。 
下面列出了詳細解釋。 
PID(Process ID):進程標示號。 
USER:進程所有者的用戶名。 
PR:進程的優先級別。 
NI:進程的優先級別數值。 
VIRT:進程佔用的虛擬內存值。 
RES:進程佔用的物理內存值。 
SHR:進程使用的共享內存值。 
S:進程的狀態,其中S表示休眠,R表示正在運行,Z表示僵死狀態,N表示該進程優先值是負數。 
%CPU:該進程佔用的CPU使用率。 
%MEM:該進程佔用的物理內存和總內存的百分比。 
TIME+:該進程啓動後佔用的總的CPU時間。 
Command:進程啓動的啓動命令名稱,如果這一行顯示不下,進程會有一個完整的命令行。 
top命令使用過程中,還可以使用一些交互的命令來完成其它參數的功能。這些命令是通過快捷鍵啓動的。 
:立刻刷新。 
P:根據CPU使用大小進行排序。 
T:根據時間、累計時間排序。 
q:退出top命令。 
m:切換顯示內存信息。 
t:切換顯示進程和CPU狀態信息。 
c:切換顯示命令名稱和完整命令行。 
M:根據使用內存大小進行排序。 
W:將當前設置寫入~/.toprc文件中。這是寫top配置文件的推薦方法。 
可以看到,top命令是一個功能十分強大的監控系統的工具,對於系統管理員而言尤其重要。但是,它的缺點是會消耗很多系統資源。 


free 
1.作用 
free命令用來顯示內存的使用情況,使用權限是所有用戶。 
2.格式 
free [-b|-k|-m] [-o] [-s delay] [-t] [-V] 
3.主要參數 
-b -k -m:分別以字節(KB、MB)爲單位顯示內存使用情況。 
-s delay:顯示每隔多少秒數來顯示一次內存使用情況。 
-t:顯示內存總和列。 
-o:不顯示緩衝區調節列。 
4.應用實例 
free命令是用來查看內存使用情況的主要命令。和top命令相比,它的優點是使用簡單,並且只佔用很少的系統資源。通過-S參數可以使用free命令不間斷地監視有多少內存在使用,這樣可以把它當作一個方便實時監控器。 
#free -b -s5 
使用這個命令後終端會連續不斷地報告內存使用情況(以字節爲單位),每5秒更新一次。 

chown 
1.作用 
更改一個或多個文件或目錄的屬主和屬組。使用權限是超級用戶。 
2.格式 
chown [選項] 用戶或組 文件 
3.主要參數 
--dereference:受影響的是符號鏈接所指示的對象,而非符號鏈接本身。 
-h, --no-dereference:會影響符號鏈接本身,而非符號鏈接所指示的目的地(當系統支持更改符號鏈接的所有者,此選項纔有效)。 
--from=目前所有者:目前組只當每個文件的所有者和組符合選項所指定的,纔會更改所有者和組。其中一個可以省略,這已省略的屬性就不需要符合原有的屬性。 
-f, --silent, --quiet:去除大部分的錯誤信息。 
-R, --recursive:遞歸處理所有的文件及子目錄。 
-v, --verbose:處理任何文件都會顯示信息。 
4.說明 
chown 將指定文件的擁有者改爲指定的用戶或組,用戶可以是用戶名或用戶ID;組可以是組名或組ID;文件是以空格分開的要改變權限的文件列表,支持通配符。系統管理員經常使用chown命令,在將文件拷貝到另一個用戶的目錄下以後,讓用戶擁有使用該文件的權限。 
5.應用實例 
1.把文件shiyan.c的所有者改爲wan 
$ chown wan shiyan.c 
2.把目錄/hi及其下的所有文件和子目錄的屬主改成wan,屬組改成users。 
$ chown - R wan.users /hi 
chattr 
1.作用 
修改ext2和ext3文件系統屬性(attribute),使用權限超級用戶。 
2.格式 
chattr [-RV] [-+=AacDdijsSu] [-v version] 文件或目錄 
3.主要參數 
-R:遞歸處理所有的文件及子目錄。 
-V:詳細顯示修改內容,並打印輸出。 
-:失效屬性。 
+:激活屬性。 
= :指定屬性。 
A:Atime,告訴系統不要修改對這個文件的最後訪問時間。 
S:Sync,一旦應用程序對這個文件執行了寫操作,使系統立刻把修改的結果寫到磁盤。 
a:Append Only,系統只允許在這個文件之後追加數據,不允許任何進程覆蓋或截斷這個文件。如果目錄具有這個屬性,系統將只允許在這個目錄下建立和修改文件,而不允許刪除任何文件。 
i:Immutable,系統不允許對這個文件進行任何的修改。如果目錄具有這個屬性,那麼任何的進程只能修改目錄之下的文件,不允許建立和刪除文件。 
D:檢查壓縮文件中的錯誤。 
d:No dump,在進行文件系統備份時,dump程序將忽略這個文件。 
C:Compress,系統以透明的方式壓縮這個文件。從這個文件讀取時,返回的是解壓之後的數據;而向這個文件中寫入數據時,數據首先被壓縮之後才寫入磁盤。 
s:Secure Delete,讓系統在刪除這個文件時,使用0填充文件所在的區域。 
u:Undelete,當一個應用程序請求刪除這個文件,系統會保留其數據塊以便以後能夠恢復刪除這個文件。 
4.說明 
chattr 
命令的作用很大,其中一些功能是由Linux內核版本來支持的,如果Linux內核版本低於2.2,那麼許多功能不能實現。同樣-D檢查壓縮文件中的錯誤 
的功能,需要2.5.19以上內核才能支持。另外,通過chattr命令修改屬性能夠提高系統的安全性,但是它並不適合所有的目錄。chattr命令不能 
保護/、/dev、/tmp、/var目錄。 
5.應用實例 
1.恢復/root目錄,即子目錄的所有文件 
# chattr -R +u/root 
2.用chattr命令防止系統中某個關鍵文件被修改 
在Linux下,有些配置文件(passwd ,fatab)是不允許任何人修改的,爲了防止被誤刪除或修改,可以設定該文件的“不可修改位(immutable)”,命令如下: 
# chattr +i /etc/fstab 
ps 
1.作用 
ps顯示瞬間進程 (process) 的動態,使用權限是所有使用者。 
2.格式 
ps [options] [--help] 
3.主要參數 
ps的參數非常多, 此出僅列出幾個常用的參數。 
-A:列出所有的進程。 
-l:顯示長列表。 
-m:顯示內存信息。 
-w:顯示加寬可以顯示較多的信息。 
-e:顯示所有進程。 
a:顯示終端上的所有進程,包括其它用戶的進程。 
-au:顯示較詳細的信息。 
-aux:顯示所有包含其它使用者的進程。 
4.說明 
要 
對進程進行監測和控制,首先要了解當前進程的情況,也就是需要查看當前進程。ps命令就是最基本、也是非常強大的進程查看命令。使用該命令可以確定有哪些 
進程正在運行、運行的狀態、進程是否結束、進程有沒有殭屍、哪些進程佔用了過多的資源等。圖2給出了ps-aux命令詳解。大部分信息都可以通過執行該命 
令得到。最常用的三個參數是u、a、x。下面就結合這三個參數詳細說明ps命令的作用:ps aux 
圖2 ps-aux命令詳解 
圖2第2行代碼中,USER表示進程擁有者;PID表示進程標示符;%CPU表示佔用的CPU使用率;%MEM佔用的物理內存使用率;VSZ表示佔用的虛擬內存大小;RSS爲進程佔用的物理內存值;TTY爲終端的次要裝置號碼。 
STAT 
表示進程的狀態,其中D爲不可中斷的靜止(I/O動作);R正在執行中;S靜止狀態;T暫停執行;Z不存在,但暫時無法消除;W沒有足夠的內存分頁可分 
配;高優先序的進程;N低優先序的進程;L有內存分頁分配並鎖在內存體內 (實時系統或 
I/O)。START爲進程開始時間。TIME爲執行的時間。COMMAND是所執行的指令。 
4.應用實例 
在進行系統維護時,經常會出現內存使用量驚人,而又不知道是哪一個進程佔用了大量進程的情況。除了可以使用top命令查看內存使用情況之外,還可以使用下面的命令: 
ps aux | sort +5n 
-------------------------------------------------------------------------------- 
作者: ☆-☆    時間: 2010-6-8 11:58 

Android系統在超級終端下必會的命令大全(十) 
六、其他命令 
tar 
1.作用 
tar命令是Unix/Linux系統中備份文件的可靠方法,幾乎可以工作於任何環境中,它的使用權限是所有用戶。 
2.格式 
tar [主選項+輔選項] 文件或目錄 
3.主要參數 
使用該命令時,主選項是必須要有的,它告訴tar要做什麼事情,輔選項是輔助使用的,可以選用。 
主選項: 
-c 創建新的檔案文件。如果用戶想備份一個目錄或是一些文件,就要選擇這個選項。 
-r 把要存檔的文件追加到檔案文件的未尾。例如用戶已經做好備份文件,又發現還有一個目錄或是一些文件忘記備份了,這時可以使用該選項,將忘記的目錄或文件追加到備份文件中。 
-t 列出檔案文件的內容,查看已經備份了哪些文件。 
-u 更新文件。就是說,用新增的文件取代原備份文件,如果在備份文件中找不到要更新的文件,則把它追加到備份文件的最後。 
-x 從檔案文件中釋放文件。 
輔助選項: 
-b 該選項是爲磁帶機設定的,其後跟一數字,用來說明區塊的大小,系統預設值爲20(20×512 bytes)。 
-f 使用檔案文件或設備,這個選項通常是必選的。 
-k 保存已經存在的文件。例如把某個文件還原,在還原的過程中遇到相同的文件,不會進行覆蓋。 
-m 在還原文件時,把所有文件的修改時間設定爲現在。 
-M 創建多卷的檔案文件,以便在幾個磁盤中存放。 
-v 詳細報告tar處理的文件信息。如無此選項,tar不報告文件信息。 
-w 每一步都要求確認。 
-z 用gzip來壓縮/解壓縮文件,加上該選項後可以將檔案文件進行壓縮,但還原時也一定要使用該選項進行解壓縮。 
4.應用說明 
tar 是Tape Archive(磁帶歸檔)的縮寫,最初設計用於將文件打包到磁帶上。如果下載過Linux的源代碼,或許已經碰到過tar文件 
請注意,不要忘了Linux是區分大小寫的。例如,tar命令應該總是以小寫的形式執行。命令行開關可以是大寫、小寫或大小寫的混合。例如,-t和-T執行不同的功能。文件或目錄名稱可以混合使用大小寫,而且就像命令和命令行開關一樣是區分大小寫的。 
5.應用實例 
tar是一個命令行的工具,沒有圖形界面。使用Konsole打開一個終端窗口,接下來是一個簡單的備份命令(在/temp目錄中創建一個back.tar的文件,/usr目錄中所有內容都包含在其中。): 
$tar cvf - /usr > /temp/back.tar 
另 
外,tar命令支持前面第三講中講過的crontab命令,可以用crontab工具設置成基於時間的有規律地運行。例如,每晚6點把/usr目錄備份到 
hda—第一個IDE接口的主驅動器 (總是位於第一個硬盤)中,只要將下面語句添加到root的crontab中即可: 
$00 06 * * * tar cvf /dev/hda1/usrfiles.tar - /usr 
一般情況下,以下這些目錄是需要備份的: 
◆/etc 包含所有核心配置文件,其中包括網絡配置、系統名稱、防火牆規則、用戶、組,以及其它全局系統項。 
◆ /var 包含系統守護進程(服務)所使用的信息,包括DNS配置、DHCP租期、郵件緩衝文件、HTTP服務器文件、dB2實例配置等。 
◆/home 包含所有默認用戶的主目錄,包括個人設置、已下載的文件和用戶不希望失去的其它信息。 
◆/root 根(root)用戶的主目錄。 
◆/opt 是安裝許多非系統文件的地方。IBM軟件就安裝在這裏。OpenOffice、JDK和其它軟件在默認情況下也安裝在這裏。 
有些目錄是可以不備份的: 
◆ /proc 應該永遠不要備份這個目錄。它不是一個真實的文件系統,而是運行內核和環境的虛擬化視圖,包括諸如/proc/kcore這樣的文件,這個文件是整個運行內存的虛擬視圖。備份這些文件只是在浪費資源。 
◆/dev 包含硬件設備的文件表示。如果計劃還原到一個空白的系統,就可以備份/dev。然而,如果計劃還原到一個已安裝的Linux 系統,那麼備份/dev是沒有必要的。 
unzip 
1.作用 
unzip 
命令位於/usr/bin目錄中,它們和MS DOS下的pkzip、pkunzip及MS 
Windows中的Winzip軟件功能一樣,將文件壓縮成.zip文件,以節省硬盤空間,當需要的時候再將壓縮文件用unzip命令解開。該命令使用權 
限是所有用戶。 
2.格式 
unzip [-cflptuvz][-agCjLMnoqsVX][-P ][.zip文件][文件][-d ][-x ] 
3.主要參數 
-c:將解壓縮的結果顯示到屏幕上,並對字符做適當的轉換。 
-f:更新現有的文件。 
-l:顯示壓縮文件內所包含的文件。 
-p:與-c參數類似,會將解壓縮的結果顯示到屏幕上,但不會執行任何的轉換。 
-t:檢查壓縮文件是否正確。 
-u:與-f參數類似,但是除了更新現有的文件外,也會將壓縮文件中的其它文件解壓縮到目錄中。 
-v:執行是時顯示詳細的信息。 
-z:僅顯示壓縮文件的備註文字。 
-a:對文本文件進行必要的字符轉換。 
-b:不要對文本文件進行字符轉換。 
-C:壓縮文件中的文件名稱區分大小寫。 
-j:不處理壓縮文件中原有的目錄路徑。 
-L:將壓縮文件中的全部文件名改爲小寫。 
-M:將輸出結果送到more程序處理。 
-n:解壓縮時不要覆蓋原有的文件。 
-o:不必先詢問用戶,unzip執行後覆蓋原有文件。 
-P:使用zip的密碼選項。 
-q:執行時不顯示任何信息。 
-s:將文件名中的空白字符轉換爲底線字符。 
-V:保留VMS的文件版本信息。 
-X:解壓縮時同時回存文件原來的UID/GID。 
[.zip文件]:指定.zip壓縮文件。 
[文件]:指定要處理.zip壓縮文件中的哪些文件。 
-d:指定文件解壓縮後所要存儲的目錄。 
-x:指定不要處理.zip壓縮文件中的哪些文件。 
-Z unzip:-Z等於執行zipinfo指令。在Linux中,還提供了一個叫zipinfo的工具,能夠察看zip壓縮文件的詳細信息。 
gunzip 
1.作用 
gunzip命令作用是解壓文件,使用權限是所有用戶。 
2.格式 
gunzip [-acfhlLnNqrtvV][-s ][文件...] 
或者 
gunzip [-acfhlLnNqrtvV][-s ][目錄] 
3.主要參數 
-a或--ascii:使用ASCII文字模式。 
-c或--stdout或--to-stdout:把解壓後的文件輸出到標準輸出設備。 
-f或-force:強行解開壓縮文件,不理會文件名稱或硬連接是否存在,以及該文件是否爲符號連接。 
-h或--help:在線幫助。 
-l或--list:列出壓縮文件的相關信息。 
-L或--license:顯示版本與版權信息。 
-n或--no-name:解壓縮時,若壓縮文件內含有原來的文件名稱及時間戳記,則將其忽略不予處理。 
-N或--name:解壓縮時,若壓縮文件內含有原來的文件名稱及時間戳記,則將其回存到解開的文件上。 
-q或--quiet:不顯示警告信息。 
-r或--recursive:遞歸處理,將指定目錄下的所有文件及子目錄一併處理。 
-S或--suffix:更改壓縮字尾字符串。 
-t或--test:測試壓縮文件是否正確無誤。 
-v或--verbose:顯示指令執行過程。 
-V或--version:顯示版本信息。 
4.說明 
gunzip是個使用廣泛的解壓縮程序,它用於解開被gzip壓縮過的文件,這些壓縮文件預設最後的擴展名爲“.gz”。事實上,gunzip就是gzip的硬連接,因此不論是壓縮或解壓縮,都可通過gzip指令單獨完成。gunzip最新版本是1.3.3 。


那就首先說點Runtime類吧,他是一個與JVM運行時環境有關的類,這個類是Singleton的。我說幾個自己覺得重要的地方。 

1、Runtime.getRuntime()可以取得當前JVM的運行時環境,這也是在Java中唯一一個得到運行時環境的方法。 

2、Runtime上其他大部分的方法都是實例方法,也就是說每次進行運行時調用時都要用到getRuntime方法。 

3、 Runtime中的exit方法是退出當前JVM的方法,估計也是唯一的一個吧,因爲我看到System類中的exit實際上也是通過調用 Runtime.exit()來退出JVM的,這裏說明一下Java對Runtime返回值的一般規則(後邊也提到了),0代表正常退出,非0代表異常中止,這只是Java的規則,在各個操作系統中總會發生一些小的混淆。 

4、Runtime.addShutdownHook()方法可以註冊一個hook在JVM執行shutdown的過程中,方法的參數只要是一個初始化過但是沒有執行的Thread實例就可以。(注意,Java中的Thread都是執行過了就不值錢的哦) 

5、說到addShutdownHook這個方法就要說一下JVM運行環境是在什麼情況下shutdown或者abort的。文檔上是這樣寫的,當最後一個非精靈進程退出或者收到了一個用戶中斷信號、用戶登出、系統shutdown、Runtime的exit方法被調用時JVM會啓動shutdown的過程,在這個過程開始後,他會並行啓動所有登記的shutdown hook(注意是並行啓動,這就需要線程安全和防止死鎖)。當shutdown過程啓動後,只有通過調用halt方法才能中止shutdown的過程並退出JVM。 

那什麼時候JVM會abort退出那?首先說明一下,abort退出時JVM就是停止運行但並不一定進行shutdown。這隻有JVM在遇到SIGKILL信號或者windows中止進程的信號、本地方法發生類似於訪問非法地址一類的內部錯誤時會出現。這種情況下並不能保證shutdown hook是否被執行。 


現在開始看這篇文章,呵呵。 


首先講的是Runtime.exec()方法的所有重載。這裏要注意的有一點,就是public Process exec(String [] cmdArray, String [] envp);這個方法中cmdArray是一個執行的命令和參數的字符串數組,數組的第一個元素是要執行的命令往後依次都是命令的參數,envp我個人感覺應該和C中的execve中的環境變量是一樣的,envp中使用的是name=value的方式。 


<!--[if !supportLists]-->1、 <!--[endif]-->一個很糟糕的調用程序,代碼如下,這個程序用exec調用了一個外部命令之後馬上使用exitValue就對其返回值進行檢查,讓我們看看會出現什麼問題。 


import java.util.*; 
import java.io.*; 

public class BadExecJavac 

public static void main(String args[]) 

try 

Runtime rt = Runtime.getRuntime(); 
Process proc = rt.exec("javac"); 
int exitVal = proc.exitValue(); 
System.out.println("Process exitValue: " + exitVal); 
} catch (Throwable t) 

t.printStackTrace(); 




A run of BadExecJavac produces: 


E:classescomjavaworldjpitfallsarticle2>java BadExecJavac 
java.lang.IllegalThreadStateException: process has not exited 
at java.lang.Win32Process.exitValue(Native Method) 
at BadExecJavac.main(BadExecJavac.java:13) 


這裏看原文就可以瞭解,這裏主要的問題就是錯誤的調用了exitValue來取得外部命令的返回值(呵呵,這個錯誤我也曾經犯過),因爲exitValue 這個方法是不阻塞的,程序在調用這個方法時外部命令並沒有返回所以造成了異常的出現,這裏是由另外的方法來等待外部命令執行完畢的,就是waitFor方法,這個方法會一直阻塞直到外部命令執行結束,然後返回外部命令執行的結果,作者在這裏一頓批評設計者的思路有問題,呵呵,反正我是無所謂阿,能用就可以拉。但是作者在這裏有一個說明,就是exitValue也是有好多用途的。因爲當你在一個Process上調用waitFor方法時,當前線程是阻塞的,如果外部命令無法執行結束,那麼你的線程就會一直阻塞下去,這種意外會影響我們程序的執行。所以在我們不能判斷外部命令什麼時候執行完畢而我們的程序還需要繼續執行的情況下,我們就應該循環的使用exitValue來取得外部命令的返回狀態,並在外部命令返回時作出相應的處理。 


2、對exitValue處改進了的程序 

import java.util.*; 
import java.io.*; 

public class BadExecJavac2 

public static void main(String args[]) 

try 

Runtime rt = Runtime.getRuntime(); 
Process proc = rt.exec("javac"); 
int exitVal = proc.waitFor(); 
System.out.println("Process exitValue: " + exitVal); 
} catch (Throwable t) 

t.printStackTrace(); 




不幸的是,這個程序也無法執行完成,它沒有輸出但卻一直懸在那裏,這是爲什麼那? 


JDK文檔中對此有如此的解釋:因爲本地的系統對標準輸入和輸出所提供的緩衝池有效,所以錯誤的對標準輸出快速的寫入和從標準輸入快速的讀入都有可能造成子進程的鎖,甚至死鎖。 


文檔引述完了,作者又開始批評了,他說JDK僅僅說明爲什麼問題會發生,卻並沒有說明這個問題怎麼解決,這的確是個問題哈。緊接着作者說出自己的做法,就是在執行完外部命令後我們要控制好Process的所有輸入和輸出(視情況而定),在這個例子裏邊因爲調用的是Javac,而他在沒有參數的情況下會將提示信息輸出到標準出錯,所以在下面的程序中我們要對此進行處理。 


import java.util.*; 
import java.io.*; 

public class MediocreExecJavac 

public static void main(String args[]) 

try 

Runtime rt = Runtime.getRuntime(); 
Process proc = rt.exec("javac"); 
InputStream stderr = proc.getErrorStream(); 
InputStreamReader isr = new InputStreamReader(stderr); 
BufferedReader br = new BufferedReader(isr); 
String line = null; 
System.out.println("<ERROR>"); 
while ( (line = br.readLine()) != null) 
System.out.println(line); 
System.out.println("</ERROR>"); 
int exitVal = proc.waitFor(); 
System.out.println("Process exitValue: " + exitVal); 
} catch (Throwable t) 

t.printStackTrace(); 





程序的運行結果爲 

E:classescomjavaworldjpitfallsarticle2>java MediocreExecJavac 
<ERROR> 
Usage: javac <options> <source files> 

where <options> includes: 
-g Generate all debugging info 
-g:none Generate no debugging info 
-g:{lines,vars,source} Generate only some debugging info 
-O Optimize; may hinder debugging or enlarge class files 
-nowarn Generate no warnings 
-verbose Output messages about what the compiler is doing 
-deprecation Output source locations where deprecated APIs are used 
-classpath <path> Specify where to find user class files 
-sourcepath <path> Specify where to find input source files 
-bootclasspath <path> Override location of bootstrap class files 
-extdirs <dirs> Override location of installed extensions 
-d <directory> Specify where to place generated class files 
-encoding <encoding> Specify character encoding used by source files 
-target <release> Generate class files for specific VM version 
</ERROR> 
Process exitValue: 2 


哎,不管怎麼說還是出來了結果,作者作了一下總結,就是說,爲了處理好外部命令大量輸出的情況,你要確保你的程序處理好外部命令所需要的輸入或者輸出。 


下一個題目,當我們調用一個我們認爲是可執行程序的時候容易發生的錯誤(今天晚上我剛剛犯這個錯誤,沒事做這個練習時候發生的) 

import java.util.*; 
import java.io.*; 

public class BadExecWinDir 

public static void main(String args[]) 

try 

Runtime rt = Runtime.getRuntime(); 
Process proc = rt.exec("dir"); 
InputStream stdin = proc.getInputStream(); 
InputStreamReader isr = new InputStreamReader(stdin); 
BufferedReader br = new BufferedReader(isr); 
String line = null; 
System.out.println("<OUTPUT>"); 
while ( (line = br.readLine()) != null) 
System.out.println(line); 
System.out.println("</OUTPUT>"); 
int exitVal = proc.waitFor(); 
System.out.println("Process exitValue: " + exitVal); 
} catch (Throwable t) 

t.printStackTrace(); 




A run of BadExecWinDir produces: 


E:classescomjavaworldjpitfallsarticle2>java BadExecWinDir 
java.io.IOException: CreateProcess: dir error=2 
at java.lang.Win32Process.create(Native Method) 
at java.lang.Win32Process.<init>(Unknown Source) 
at java.lang.Runtime.execInternal(Native Method) 
at java.lang.Runtime.exec(Unknown Source) 
at java.lang.Runtime.exec(Unknown Source) 
at java.lang.Runtime.exec(Unknown Source) 
at java.lang.Runtime.exec(Unknown Source) 
at BadExecWinDir.main(BadExecWinDir.java:12) 


說實在的,這個錯誤還真是讓我摸不着頭腦,我覺得在windows中返回2應該是沒有找到這個文件的緣故,可能windows 2000中只有cmd命令,dir命令不是當前環境變量能夠解釋的吧。我也不知道了,慢慢往下看吧。 

嘿,果然和作者想的一樣,就是因爲dir命令是由windows中的解釋器解釋的,直接執行dir時無法找到dir.exe這個命令,所以會出現文件未找到這個2的錯誤。如果我們要執行這樣的命令,就要先根據操作系統的不同執行不同的解釋程序command.com 或者cmd.exe。 

作者對上邊的程序進行了修改 

import java.util.*; 
import java.io.*; 

class StreamGobbler extends Thread 

InputStream is; 
String type; 

StreamGobbler(InputStream is, String type) 

this.is = is; 
this.type = type; 


public void run() 

try 

InputStreamReader isr = new InputStreamReader(is); 
BufferedReader br = new BufferedReader(isr); 
String line=null; 
while ( (line = br.readLine()) != null) 
System.out.println(type + ">" + line); 
} catch (IOException ioe) 

ioe.printStackTrace(); 




public class GoodWindowsExec 

public static void main(String args[]) 

if (args.length < 1) 

System.out.println("USAGE: java GoodWindowsExec <cmd>"); 
System.exit(1); 


try 

String osName = System.getProperty("os.name" ); 
String[] cmd = new String[3]; 

if( osName.equals( "Windows NT" ) ) 

cmd[0] = "cmd.exe" ; 
cmd[1] = "/C" ; 
cmd[2] = args[0]; 

else if( osName.equals( "Windows 95" ) ) 

cmd[0] = "command.com" ; 
cmd[1] = "/C" ; 
cmd[2] = args[0]; 


Runtime rt = Runtime.getRuntime(); 
System.out.println("Execing " + cmd[0] + " " + cmd[1] 
+ " " + cmd[2]); 
Process proc = rt.exec(cmd); 
// any error message? 
StreamGobbler errorGobbler = new 
StreamGobbler(proc.getErrorStream(), "ERROR"); 

// any output? 
StreamGobbler outputGobbler = new 
StreamGobbler(proc.getInputStream(), "OUTPUT"); 

// kick them off 
errorGobbler.start(); 
outputGobbler.start(); 

// any error??? 
int exitVal = proc.waitFor(); 
System.out.println("ExitValue: " + exitVal); 
} catch (Throwable t) 

t.printStackTrace(); 




Running GoodWindowsExec with the dir command generates: 


E:classescomjavaworldjpitfallsarticle2>java GoodWindowsExec "dir *.java" 
Execing cmd.exe /C dir *.java 
OUTPUT> Volume in drive E has no label. 
OUTPUT> Volume Serial Number is 5C5F-0CC9 
OUTPUT> 
OUTPUT> Directory of E:classescomjavaworldjpitfallsarticle2 
OUTPUT> 
OUTPUT>10/23/00 09:01p 805 BadExecBrowser.java 
OUTPUT>10/22/00 09:35a 770 BadExecBrowser1.java 
OUTPUT>10/24/00 08:45p 488 BadExecJavac.java 
OUTPUT>10/24/00 08:46p 519 BadExecJavac2.java 
OUTPUT>10/24/00 09:13p 930 BadExecWinDir.java 
OUTPUT>10/22/00 09:21a 2,282 BadURLPost.java 
OUTPUT>10/22/00 09:20a 2,273 BadURLPost1.java 
... (some output omitted for brevity) 
OUTPUT>10/12/00 09:29p 151 SuperFrame.java 
OUTPUT>10/24/00 09:23p 1,814 TestExec.java 
OUTPUT>10/09/00 05:47p 23,543 TestStringReplace.java 
OUTPUT>10/12/00 08:55p 228 TopLevel.java 
OUTPUT> 22 File(s) 46,661 bytes 
OUTPUT> 19,678,420,992 bytes free 
ExitValue: 0 

這裏作者教了一個windows中很有用的方法,呵呵,至少我是不知道的,就是cmd.exe /C +一個windows中註冊了後綴的文檔名,windows會自動地調用相關的程序來打開這個文檔,我試了一下,的確很好用,但是好像文件路徑中有空格的話就有點問題,我加上引號也無法解決。 

這裏作者強調了一下,不要假設你執行的程序是可執行的程序,要清楚自己的程序是單獨可執行的還是被解釋的,本章的結束作者會介紹一個命令行工具來幫助我們分析。 

這裏還有一點,就是得到process的輸出的方式是getInputStream,這是因爲我們要從Java 程序的角度來看,外部程序的輸出對於Java來說就是輸入,反之亦然。 


最後的一個漏洞的地方就是錯誤的認爲exec方法會接受所有你在命令行或者Shell中輸入並接受的字符串。這些錯誤主要出現在命令作爲參數的情況下,程序員錯誤的將所有命令行中可以輸入的參數命令加入到exec中(這段翻譯的不好,湊合看吧)。下面的例子中就是一個程序員想重定向一個命令的輸出。 


import java.util.*; 
import java.io.*; 

// StreamGobbler omitted for brevity 

public class BadWinRedirect 

public static void main(String args[]) 

try 

Runtime rt = Runtime.getRuntime(); 
Process proc = rt.exec("java jecho 'Hello World' > test.txt"); 
// any error message? 
StreamGobbler errorGobbler = new 
StreamGobbler(proc.getErrorStream(), "ERROR"); 

// any output? 
StreamGobbler outputGobbler = new 
StreamGobbler(proc.getInputStream(), "OUTPUT"); 

// kick them off 
errorGobbler.start(); 
outputGobbler.start(); 

// any error??? 
int exitVal = proc.waitFor(); 
System.out.println("ExitValue: " + exitVal); 
} catch (Throwable t) 

t.printStackTrace(); 




Running BadWinRedirect produces: 


E:classescomjavaworldjpitfallsarticle2>java BadWinRedirect 
OUTPUT>'Hello World' > test.txt 
ExitValue: 0 

程序員的本意是將Hello World這個輸入重訂向到一個文本文件中,但是這個文件並沒有生成,jecho僅僅是將命令行中的參數輸出到標準輸出中,用戶覺得可以像dos中重定向一樣將輸出重定向到一個文件中,但這並不能實現,用戶錯誤的將exec認爲是一個shell解釋器,但它並不是,如果你想將一個程序的輸出重定向到其他的程序中,你必須用程序來實現他。可用java.io中的包。 


import java.util.*; 
import java.io.*; 

class StreamGobbler extends Thread 

InputStream is; 
String type; 
OutputStream os; 

StreamGobbler(InputStream is, String type) 

this(is, type, null); 


StreamGobbler(InputStream is, String type, OutputStream redirect) 

this.is = is; 
this.type = type; 
this.os = redirect; 


public void run() 

try 

PrintWriter pw = null; 
if (os != null) 
pw = new PrintWriter(os); 

InputStreamReader isr = new InputStreamReader(is); 
BufferedReader br = new BufferedReader(isr); 
String line=null; 
while ( (line = br.readLine()) != null) 

if (pw != null) 
pw.println(line); 
System.out.println(type + ">" + line); 

if (pw != null) 
pw.flush(); 
} catch (IOException ioe) 

ioe.printStackTrace(); 




public class GoodWinRedirect 

public static void main(String args[]) 

if (args.length < 1) 

System.out.println("USAGE java GoodWinRedirect <outputfile>"); 
System.exit(1); 


try 

FileOutputStream fos = new FileOutputStream(args[0]); 
Runtime rt = Runtime.getRuntime(); 
Process proc = rt.exec("java jecho 'Hello World'"); 
// any error message? 
StreamGobbler errorGobbler = new 
StreamGobbler(proc.getErrorStream(), "ERROR"); 

// any output? 
StreamGobbler outputGobbler = new 
StreamGobbler(proc.getInputStream(), "OUTPUT", fos); 

// kick them off 
errorGobbler.start(); 
outputGobbler.start(); 

// any error??? 
int exitVal = proc.waitFor(); 
System.out.println("ExitValue: " + exitVal); 
fos.flush(); 
fos.close(); 
} catch (Throwable t) 

t.printStackTrace(); 




Running GoodWinRedirect produces: 


E:classescomjavaworldjpitfallsarticle2>java GoodWinRedirect test.txt 
OUTPUT>'Hello World' 
ExitValue: 0 

這裏就不多說了,看看就明白,緊接着作者給出了一個監測命令的小程序 

import java.util.*; 
import java.io.*; 

// class StreamGobbler omitted for brevity 

public class TestExec 

public static void main(String args[]) 

if (args.length < 1) 

System.out.println("USAGE: java TestExec "cmd""); 
System.exit(1); 


try 

String cmd = args[0]; 
Runtime rt = Runtime.getRuntime(); 
Process proc = rt.exec(cmd); 

// any error message? 
StreamGobbler errorGobbler = new 
StreamGobbler(proc.getErrorStream(), "ERR"); 

// any output? 
StreamGobbler outputGobbler = new 
StreamGobbler(proc.getInputStream(), "OUT"); 

// kick them off 
errorGobbler.start(); 
outputGobbler.start(); 

// any error??? 
int exitVal = proc.waitFor(); 
System.out.println("ExitValue: " + exitVal); 
} catch (Throwable t) 

t.printStackTrace(); 




對這個程序進行運行: 
E:classescomjavaworldjpitfallsarticle2>java TestExec "e:javadocsindex.html" 
java.io.IOException: CreateProcess: e:javadocsindex.html error=193 
at java.lang.Win32Process.create(Native Method) 
at java.lang.Win32Process.<init>(Unknown Source) 
at java.lang.Runtime.execInternal(Native Method) 
at java.lang.Runtime.exec(Unknown Source) 
at java.lang.Runtime.exec(Unknown Source) 
at java.lang.Runtime.exec(Unknown Source) 
at java.lang.Runtime.exec(Unknown Source) 
at TestExec.main(TestExec.java:45) 

193在windows中是說這不是一個win32程序,這說明路徑中找不到這個網頁的關聯程序,下面作者決定用一個絕對路徑來試一下。 

E:classescomjavaworldjpitfallsarticle2>java TestExec 
"e:program filesnetscapeprogramnetscape.exe e:javadocsindex.html" 
ExitValue: 0 


好用了,這個我也試了一下,用的是IE。 


最後,作者總結了幾條規則,防止我們在進行Runtime.exec()調用時出現錯誤。 


<!--[if !supportLists]-->1、 <!--[endif]-->在一個外部進程執行完之前你不能得到他的退出狀態 

<!--[if !supportLists]-->2、 <!--[endif]-->在你的外部程序開始執行的時候你必須馬上控制輸入、輸出、出錯這些流。 

<!--[if !supportLists]-->3、 <!--[endif]-->你必須用Runtime.exec()去執行程序 

<!--[if !supportLists]-->4、 <!--[endif]-->你不能象命令行一樣使用Runtime.exec()。
這是一對繼承於InputStream和OutputStream的類,用於本地文件讀寫(二進制格式讀寫並且是順序讀寫,讀和寫要分別創建出不同的文件流對象); 

本地文件讀寫編程的基本過程爲: 

①  生成文件流對象(對文件讀操作時應該爲FileInputStream類,而文件寫應該爲FileOutputStream類); 

②  調用FileInputStream或FileOutputStream類中的功能函數如read()、write(int b)等)讀寫文件內容; 

③  關閉文件(close())。 

實例:流文件讀寫 

流文件的單元是字節,所以它不但可以讀寫文本文件,也可以讀寫圖片、聲音、影像文件,這種特點非常有用,因爲我們可以把這種文件變成流,然後在網絡上傳輸。 

問題是有了通用的流文件以後,爲什麼還要專門的字符流呢?這是因爲文本可以用不同的方式存儲,可以是普通的文本(UTF-8編碼方式),ASCII文本和Unicode文本,字符流對象可以進行必要的轉換,從而讀出正確的文本。 

有人認爲流文件不能讀寫文本文件,這其實是個誤會,因爲文本文件本質上也是由字節組成的,當然是流文件的一種。作爲讀寫文件的全體,這是沒問題的,但是,如果要處理每次讀入的內容,就最好使用字符流。 

所以在文本文件處理時,使用字符流是個最常用的方法。 

樣例: 

import java.io.*; 

public class FileStreamDemo { 

public static void main(String[] args) throws IOException { 

//創建兩個文件,face.gif是已經存在文件,newFace.gif是新創建的文件 

File inFile = new File("face.gif"); 

File outFile = new File("newFace.gif"); 

//創建流文件讀入與寫出類 

FileInputStream inStream = new FileInputStream(inFile); 

FileOutputStream outStream = new FileOutputStream(outFile); 

//通過available方法取得流的最大字符數 

byte[] inOutb = new byte[inStream.available()]; 

inStream.read(inOutb);  //讀入流,保存在byte數組 

outStream.write(inOutb);  //寫出流,保存在文件newFace.gif中 

inStream.close(); 

outStream.close(); 





實例:讀寫任意大文件應用 

因爲byte數組最大存儲值不超過64M,所以當一個文件大於60M 的時候,需要分開幾個流操作。我們把上面的程序作一個修改,就可以寫入任意大小的文件。這個程序應用了FileInputStream類的方法如下: 

read(byte[] b,int off,int len) 

把特定位置的流內容讀入數組,已經讀入byte[]數組的內容,會在流文件中刪除。 

程序運行的結果會產生一個新文件。 

樣例: 

import java.io.*; 

public class FileStreamDemo2 { 

public static void main(String[] args) throws IOException { 

//創建兩個文件 

File inFile = new File("tcty36.rm"); 

File outFile = new File("newtcty36.rm"); 

//最大的流爲60Mb,當文件的容量大於60Mb的時候便分開流 

final int MAX_BYTE = 60000000; 

long streamTotal = 0;  //接受流的容量 

int streamNum = 0;  //流需要分開的數量 

int leave = 0;  //文件剩下的字符數 

byte[] inOutb;  //byte數組接受文件的數據 

//創建流文件讀入與寫出類 

FileInputStream inStream = new FileInputStream(inFile); 

FileOutputStream outStream = new FileOutputStream(outFile); 

//通過available方法取得流的最大字符數 

streamTotal = inStream.available(); 

//取得流文件需要分開的數量 

streamNum = (int)Math.floor(streamTotal/MAX_BYTE); 

//分開文件之後,剩餘的數量 

leave = (int)streamTotal % MAX_BYTE; 

//文件的容量大於60Mb時進入循環 

if (streamNum > 0) { 

for(int i = 0; i < streamNum; ++i){ 

inOutb = new byte[MAX_BYTE]; 

//讀入流,保存在byte數組 

inStream.read(inOutb, 0, MAX_BYTE); 

outStream.write(inOutb);  //寫出流 

outStream.flush();  //更新寫出的結果 





//寫出剩下的流數據 

inOutb = new byte[leave]; 

inStream.read(inOutb, 0, leave); 

outStream.write(inOutb); 

outStream.flush(); 

inStream.close(); 

outStream.close(); 





六、管道PipedInputStream/PipedOutputStream類: 

當需要在兩個線程中讀寫數據的時候,由於線程的併發執行,讀寫的同步問題可能會發生困難,這時候可以使用管道,管道事實上是一個隊列。 

管道是由系統維護的一個緩衝區,當然程序員也可以自己直接指定該緩衝區的大小(只需要設置管道流類中的PIPE_SIZE屬性的值)。當生產者生產出數據後,只需要將數據寫入管道中,消費者只需要從管道中讀取所需要的數據。利用管道的這種機制,可以將一個線程的輸出結果直接連接到另一個線程的輸入端口,實現兩者之間的數據直接傳送。 

線程1 
線程2 
臨時文件 
管道 

1.管道的連接: 

方法之一是通過構造函數直接將某一個程序的輸出作爲另一個程序的輸入,在定義對象時指明目標管道對象 

PipedInputStream pInput=new PipedInputStream(); 

PipedOutputStream pOutput= new PipedOutputStream(pInput); 

方法之二是利用雙方類中的任一個成員函數 connect()相連接 

PipedInputStream pInput=new PipedInputStream(); 

PipedOutputStream pOutput= new PipedOutputStream(); 

pinput.connect(pOutput); 

2.管道的輸入與輸出: 

輸出管道對象調用write()成員函數輸出數據(即向管道的輸入端發送數據);而輸入管道對象調用read()成員函數可以讀起數據(即從輸出管道中獲得數據)。這主要是藉助系統所提供的緩衝機制來實現的。 

實例:Java的管道的輸入與輸出 

import java.io.*; 

public class PipedIO //程序運行後將sendFile文件的內容拷貝到receiverFile文件中 



public static void main(String args[]) 



try 



//構造讀寫的管道流對象 

PipedInputStream pis=new PipedInputStream(); 

PipedOutputStream pos=new PipedOutputStream(); 

//實現關聯 

pos.connect(pis); 

//構造兩個線程,並且啓動。 

new Sender(pos,"c:\\text2.txt").start(); 

new Receiver(pis,"c:\\text3.txt").start(); 



catch(IOException e) 



System.out.println("Pipe Error"+ e); 







//線程發送 

class Sender extends Thread 



PipedOutputStream pos; 

File file; 

//構造方法 

Sender(PipedOutputStream pos, String fileName) 



this.pos=pos; 

file=new File(fileName); 



//線程運行方法 

public void run() 



try 



//讀文件內容 

FileInputStream fs=new FileInputStream(file); 

int data; 

while((data=fs.read())!=-1) 



//寫入管道始端 

pos.write(data); 



pos.close(); 



catch(IOException e) 



System.out.println("Sender Error" +e); 







//線程讀 

class Receiver extends Thread 



PipedInputStream pis; 

File file; 

//構造方法 

Receiver(PipedInputStream pis, String fileName) 



this.pis=pis; 

file=new File(fileName); 



//線程運行 

public void run() 



try 



//寫文件流對象 

FileOutputStream fs=new FileOutputStream(file); 

int data; 

//從管道末端讀 

while((data=pis.read())!=-1) 



//寫入本地文件 

fs.write(data); 



pis.close(); 



catch(IOException e) 



System.out.println("Receiver Error" +e); 







七、隨機文件讀寫:RandomAccessFile類 

它直接繼承於Object類而非InputStream/OutputStream類,從而可以實現讀寫文件中任何位置中的數據(只需要改變文件的讀寫位置的指針)。 

編程步驟: 

① 生成流對象並且指明讀寫類型; 

② 移動讀寫位置; 

③ 讀寫文件內容; 

④ 關閉文件。 

另外由於RandomAccessFile類實現了DataOutput與DataInput接口,因而利用它可以讀寫Java中的不同類型的基本類型數據(比如採用readLong()方法讀取長整數,而利用readInt()方法可以讀出整數值等)。 

程序實例: 

利用隨機數據流RandomAccessFile類來實現記錄用戶在鍵盤的輸入,每執行一次,將用戶的鍵盤輸入存儲在指定的UserInput.txt文件中。 

import java.io.*; 

public class RandomFileRW 



public static void main(String args[]) 



StringBuffer buf=new StringBuffer(); 

char ch; 

try 



while( (ch=(char)System.in.read()) !='\n') 



buf.append(ch); 



//讀寫方式可以爲"r" or "rw" 

RandomAccessFile myFileStream=new RandomAccessFile("c:\\UserInput.txt","rw"); 

myFileStream.seek(myFileStream.length()) ; 

myFileStream.writeBytes(buf.toString()); 

//將用戶從鍵盤輸入的內容添加到文件的尾部 

myFileStream.close(); 



catch(IOException e) 









八、DataInput/DataOutput接口: 

實現與機器無關的各種數據格式讀寫(如readChar() 、readInt()、readLong()、readFloat(),而readLine()將返回一個String)。其中 RandomAccessFile類實現了該接口,具有比FileInputStream或FileOutputStream類更靈活的數據讀寫方式。
I.Linux C 創建目錄函數mkdir的mode設置問題 

函數原型: 

#include <sys/stat.h> 

int mkdir(const char *path, mode_t mode); 

參數: 

path是目錄名 

mode是目錄權限 

返回值: 

返回0 表示成功, 返回 -1表示錯誤,並且會設置errno值。 

mode模式位: 

mode 表示新目錄的權限,可以取以下值: 

S_IRUSR 
S_IREAD 

S_IWUSR 
S_IWRITE 
S_IXUSR 
S_IEXEC 
S_IRWXU 
This is equivalent to (S_IRUSR | S_IWUSR | S_IXUSR). 
S_IRGRP 
Read permission bit for the group owner of the file. Usually 040. 
S_IWGRP 
Write permission bit for the group owner of the file. Usually 020. 
S_IXGRP 
Execute or search permission bit for the group owner of the file. Usually 010. 
S_IRWXG 
This is equivalent to (S_IRGRP | S_IWGRP | S_IXGRP). 
S_IROTH 
Read permission bit for other users. Usually 04. 
S_IWOTH 
Write permission bit for other users. Usually 02. 
S_IXOTH 
Execute or search permission bit for other users. Usually 01. 
S_IRWXO 
This is equivalent to (S_IROTH | S_IWOTH | S_IXOTH). 
S_ISUID 
This is the set-user-ID on execute bit, usually 04000. See How Change Persona. 
S_ISGID 
This is the set-group-ID on execute bit, usually 02000. See How Change Persona. 
S_ISVTX 
This is the sticky bit, usually 01000. 

例子: 

#include <sys/types.h> #include <sys/stat.h> 
int status; 

status = mkdir("/home/newdir", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); 

這樣就創建了一個newdir目錄,權限通過ls -al 查看爲 

drwxr-xr-x 

跟用linux命令mkdir創建的目錄權限位一致。 



II. linux下C語言創建多級目錄 

int   CreateDir(const   char   *sPathName)  
  {  
  char   DirName[256];  
  strcpy(DirName,   sPathName);  
  int   i,len   =   strlen(DirName);  
  if(DirName[len-1]!='/')  
  strcat(DirName,   "/");  
   
  len   =   strlen(DirName);  
   
  for(i=1;   i<len;   i++)  
  {  
  if(DirName[i]=='/')  
  {  
  DirName[i]   =   0;  
  if(   access(DirName,   NULL)!=0   )  
  {  
      if(mkdir(DirName,   0755)==-1)  
      {   
                      perror("mkdir   error");   
                      return   -1;   
      }  
  }  
  DirName[i]   =   '/';  
  }  
  }  
   
  return   0;  
  } 

III.linux c 編程:創建一個線程,監視某個目錄,一旦目錄裏出現新的文件,就將文件轉移到指定的目錄裏去。 
/* 
頭文件 
*/ 
#define SRCPATH "srcpath/" 
#define DSTPATH "dstpath/" 

int movefile() 

DIR *dir; 
struct dirent *dt; 
FILE *fp1,*fp2; 
char filename1[256],filename2[256]; 
char buf[1024]; 
int readsize,writesize; 

if((dir = opendir(SRCPATH)) == NULL) 

printf("opendir %s error\n",SRCPATH); 
return -1; 

memset(filename1,0,sizeof(filename1)); 
strcpy(filename1,SRCPATH); 
memset(filename2,0,sizeof(filename2)); 
strcpy(filename2,DSTPATH); 
while(1) 

while((dt = readdir(dir)) != NULL) 

if(strcmp(dt->d_name,".")==0||strcmp(dt->d_name,"..")==0) 

continue; 

//如果這個目錄裏 還有目錄,可以在這加判斷 
//這裏假設初始爲空目錄 
strcat(filename1,dt->d_name); 
strcat(filename2,dt->d_name); 
//如果進程資源較少可以直接用linux系統命令 

fp1 = fopen(filename1,"rb"); 
if(fp1==NULL) 

printf("open %s failed /n",filename1); 
return -1; 


fp2 = fopen(filename2,"wb"); 
if(fp2==NULL) 

printf("open %s failed /n",filename2); 
fclose(fp1); 
return -1; 


while((readsize = fread(buf,sizeof(buf),1,fp1))>0) 

//total += readsize; 
memset(buf,0,sizeof(buf)); 
writesize = fwrite(buf,sizeof(buf),1,fp2); 
if(writesize!==readsize) 

printf("write error"); 
return -2; 
fclose(fp1); 
fclose(fp2); 


fclose(fp1); 
fclose(fp2); 
rmdir(filename2); 




int main(int argc,char **argv) 

pthread_t id1; 
int ret; 
ret = pthread_create(&id1, NULL, (void*)movefile, NULL); 
return ret; 

  
1.Linux文件系統 

  Linux支持多種文件系統,如ext、ext2、minix、iso9660、msdos、fat、vfat、nfs等。在這些具體文件系統的上層,Linux提供了虛擬文件系統(VFS)來統一它們的行爲,虛擬文件系統爲不同的文件系統與內核的通信提供了一致的接口。 

linux下的c語言開發 

  在Linux平臺下對文件編程可以使用兩類函數:(1)Linux操作系統文件API;(2)C語言I/O庫函數。 前者依賴於Linux系統調用,後者實際上與操作系統是獨立的,因爲在任何操作系統下,使用C語言I/O庫函數操作文件的方法都是相同的。本章將對這兩種方法進行實例講解。 

  2.Linux文件API 

  Linux的文件操作API涉及到創建、打開、讀寫和關閉文件。 

  創建 

int creat(const char *filename, mode_t mode); 

  參數mode指定新建文件的存取權限,它同umask一起決定文件的最終權限(mode&umask),其中umask代表了文件在創建時需要去掉的一些存取權限。umask可通過系統調用umask()來改變: 

int umask(int newmask); 

  該調用將umask設置爲newmask,然後返回舊的umask,它隻影響讀、寫和執行權限。 

  打開 

int open(const char *pathname, int flags); 
int open(const char *pathname, int flags, mode_t mode); 

  open函數有兩個形式,其中pathname是我們要打開的文件名(包含路徑名稱,缺省是認爲在當前路徑下面),flags可以去下面的一個值或者是幾個值的組合: 

標誌 含義 
O_RDONLY 以只讀的方式打開文件 
O_WRONLY 以只寫的方式打開文件 
O_RDWR 以讀寫的方式打開文件 
O_APPEND 以追加的方式打開文件 
O_CREAT 創建一個文件 
O_EXEC 如果使用了O_CREAT而且文件已經存在,就會發生一個錯誤 
O_NOBLOCK 以非阻塞的方式打開一個文件 
O_TRUNC 如果文件已經存在,則刪除文件的內容 
  

  O_RDONLY、O_WRONLY、O_RDWR三個標誌只能使用任意的一個。 

  如果使用了O_CREATE標誌,則使用的函數是int open(const char *pathname,int flags,mode_t mode); 這個時候我們還要指定mode標誌,用來表示文件的訪問權限。mode可以是以下情況的組合: 

標誌 含義 
S_IRUSR 用戶可以讀 
S_IWUSR 用戶可以寫 
S_IXUSR 用戶可以執行 
S_IRWXU 用戶可以讀、寫、執行 
S_IRGRP 組可以讀 
S_IWGRP 組可以寫 
S_IXGRP 組可以執行 
S_IRWXG 組可以讀寫執行 
S_IROTH 其他人可以讀 
S_IWOTH 其他人可以寫 
S_IXOTH 其他人可以執行 
S_IRWXO 其他人可以讀、寫、執行 
S_ISUID 設置用戶執行ID 
S_ISGID 設置組的執行ID 

  除了可以通過上述宏進行“或”邏輯產生標誌以外,我們也可以自己用數字來表示,Linux總共用5個數字來表示文件的各種權限:第一位表示設置用戶ID;第二位表示設置組ID;第三位表示用戶自己的權限位;第四位表示組的權限;最後一位表示其他人的權限。每個數字可以取1(執行權限)、2(寫權限)、4(讀權限)、0(無)或者是這些值的和。例如,要創建一個用戶可讀、可寫、可執行,但是組沒有權限,其他人可以讀、可以執行的文件,並設置用戶ID位。那麼,我們應該使用的模式是1(設置用戶ID)、0(不設置組 ID)、7(1+2+4,讀、寫、執行)、0(沒有權限)、5(1+4,讀、執行)即10705: 

open("test", O_CREAT, 10705); 

  上述語句等價於: 

open("test", O_CREAT, S_IRWXU | S_IROTH | S_IXOTH | S_ISUID ); 

  如果文件打開成功,open函數會返回一個文件描述符,以後對該文件的所有操作就可以通過對這個文件描述符進行操作來實現。 

  讀寫 

  在文件打開以後,我們纔可對文件進行讀寫了,Linux中提供文件讀寫的系統調用是read、write函數: 

int read(int fd, const void *buf, size_t length); 
int write(int fd, const void *buf, size_t length); 

  其中參數buf爲指向緩衝區的指針,length爲緩衝區的大小(以字節爲單位)。函數read()實現從文件描述符fd所指定的文件中讀取 length個字節到buf所指向的緩衝區中,返回值爲實際讀取的字節數。函數write實現將把length個字節從buf指向的緩衝區中寫到文件描述符fd所指向的文件中,返回值爲實際寫入的字節數。 

  以O_CREAT爲標誌的open實際上實現了文件創建的功能,因此,下面的函數等同creat()函數: 

int open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); 

  定位 

  對於隨機文件,我們可以隨機的指定位置讀寫,使用如下函數進行定位: 

int lseek(int fd, offset_t offset, int whence); 

  lseek()將文件讀寫指針相對whence移動offset個字節。操作成功時,返回文件指針相對於文件頭的位置。參數whence可使用下述值: 

  SEEK_SET:相對文件開頭 
  SEEK_CUR:相對文件讀寫指針的當前位置 
  SEEK_END:相對文件末尾 

  offset可取負值,例如下述調用可將文件指針相對當前位置向前移動5個字節: 

lseek(fd, -5, SEEK_CUR); 

  由於lseek函數的返回值爲文件指針相對於文件頭的位置,因此下列調用的返回值就是文件的長度: 

lseek(fd, 0, SEEK_END); 

  關閉 

  當我們操作完成以後,我們要關閉文件了,只要調用close就可以了,其中fd是我們要關閉的文件描述符: 

int close(int fd); 

  例程:編寫一個程序,在當前目錄下創建用戶可讀寫文件“hello.txt”,在其中寫入“Hello, software weekly”,關閉該文件。再次打開該文件,讀取其中的內容並輸出在屏幕上。 

#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <stdio.h> 
#define LENGTH 100 
main() 

 int fd, len; 
 char str[LENGTH]; 
 fd = open("hello.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); /* 創建並打開文件 */ 
 if (fd) 
 { 
  write(fd, "Hello, Software Weekly", strlen("Hello, software weekly")); /* 寫入 Hello, software weekly字符串 */ 
  close(fd); 
 } 

 fd = open("hello.txt", O_RDWR); 
 len = read(fd, str, LENGTH); /* 讀取文件內容 */ 
 str[len] = '\0'; 
 printf("%s\n", str); 
 close(fd); 


  編譯並運行,執行結果如下圖: 

linux 

  3.C語言庫函數 

  C庫函數的文件操作實際上是獨立於具體的操作系統平臺的,不管是在DOS、Windows、Linux還是在VxWorks中都是這些函數: 

  創建和打開 

FILE *fopen(const char *path, const char *mode); 

  fopen()實現打開指定文件filename,其中的mode爲打開模式,C語言中支持的打開模式如下表: 

標誌 含義 
r, rb 以只讀方式打開 
w, wb 以只寫方式打開。如果文件不存在,則創建該文件,否則文件被截斷 
a, ab 以追加方式打開。如果文件不存在,則創建該文件 
r+, r+b, rb+ 以讀寫方式打開 
w+, w+b, wh+ 以讀寫方式打開。如果文件不存在時,創建新文件,否則文件被截斷 
a+, a+b, ab+ 以讀和追加方式打開。如果文件不存在,創建新文件 

  其中b用於區分二進制文件和文本文件,這一點在DOS、Windows系統中是有區分的,但Linux不區分二進制文件和文本文件。 

  讀寫 

  C庫函數支持以字符、字符串等爲單位,支持按照某中格式進行文件的讀寫,這一組函數爲: 

int fgetc(FILE *stream); 
int fputc(int c, FILE *stream); 
char *fgets(char *s, int n, FILE *stream); 
int fputs(const char *s, FILE *stream); 
int fprintf(FILE *stream, const char *format, ...); 
int fscanf (FILE *stream, const char *format, ...); 
size_t fread(void *ptr, size_t size, size_t n, FILE *stream); 
size_t fwrite (const void *ptr, size_t size, size_t n, FILE *stream); 

  fread()實現從流stream中讀取加n個字段,每個字段爲size字節,並將讀取的字段放入ptr所指的字符數組中,返回實際已讀取的字段數。在讀取的字段數小於num時,可能是在函數調用時出現錯誤,也可能是讀到文件的結尾。所以要通過調用feof()和ferror()來判斷。 

  write()實現從緩衝區ptr所指的數組中把n個字段寫到流stream中,每個字段長爲size個字節,返回實際寫入的字段數。 

  另外,C庫函數還提供了讀寫過程中的定位能力,這些函數包括 

int fgetpos(FILE *stream, fpos_t *pos); 
int fsetpos(FILE *stream, const fpos_t *pos); 
int fseek(FILE *stream, long offset, int whence); 
等。 

  關閉 

  利用C庫函數關閉文件依然是很簡單的操作: 

int fclose (FILE *stream); 

  例程:將第2節中的例程用C庫函數來實現。 

#include <stdio.h> 
#define LENGTH 100 
main() 

 FILE *fd; 
 char str[LENGTH]; 

 fd = fopen("hello.txt", "w+"); /* 創建並打開文件 */ 
 if (fd) 
 { 
  fputs("Hello, Software Weekly", fd); /* 寫入Hello, software weekly字符串 */ 
  fclose(fd); 
 } 

 fd = fopen("hello.txt", "r"); 
 fgets(str, LENGTH, fd); /* 讀取文件內容 */ 
 printf("%s\n", str); 
 fclose(fd); 


  4.小結 

  Linux提供的虛擬文件系統爲多種文件系統提供了統一的接口,Linux的文件編程有兩種途徑:基於Linux系統調用;基於C庫函數。這兩種編程所涉及到文件操作有新建、打開、讀寫和關閉,對隨機文件還可以定位。本章對這兩種編程方法都給出了具體的實例。
首先感謝作者的工作,謝謝了,轉到這裏都是我需要過的 

=>#include <fcntl.h> =>/usr/include/bits/fcntl.h ,裏面有 

/* open/fcntl - O_SYNC is only implemented on blocks devices and on files 
   located on an ext2 file system */ 
#define O_ACCMODE       0003 
#define O_RDONLY          00 
#define O_WRONLY         01 
#define O_RDWR             02 
#define O_CREAT            0100 /* not fcntl */ 
#define O_EXCL              0200 /* not fcntl */ 
#define O_NOCTTY          0400 /* not fcntl */ 
#define O_TRUNC            01000 /* not fcntl */ 
#define O_APPEND          02000 
#define O_NONBLOCK     04000 
#define O_NDELAY           O_NONBLOCK 
#define O_SYNC              010000 
#define O_FSYNC             O_SYNC 
#define O_ASYNC            020000 

摘要:本文簡單介紹文件操作的三個函數(open,read,write)的基本用法。 
詳細說明了open函數的用法。 

    作者:zieckey (zieckey@yahoo.com.cn) 
    All Rights Reserved! 

所需頭文件: 
#include<sys/types.h> 
#include<sys/stat.h> 
#include<fcntl.h> 

函數定義: 
int open( const char * pathname, int flags); 
int open( const char * pathname,int flags, mode_t mode); 

函數說明: 
參數 pathname 指向欲打開的文件路徑字符串。下列是參數 flags 所能使用的旗標: 
O_RDONLY 以只讀方式打開文件 
O_WRONLY 以只寫方式打開文件 
O_RDWR以可讀寫方式打開文件。 
上述三種旗標是互斥的,也就是不可同時使用,但可與下列的旗標利用 OR(|)運算符組合。 

O_CREAT 若欲打開的文件不存在則自動建立該文件。 
O_EXCL 如果 O_CREAT 也被設置,     此指令會去檢查文件是否存在。文件若不存在則建立該文件,         
   否則將導致打開文件錯誤。 此外,若 O_CREAT 與 O_EXCL 同時設置,  並且欲打開的文件爲符號連接,則會打開文件失敗。 
O_NOCTTY 如果欲打開的文件爲終端機設備時,則不會將該終端機當成進程控制終端機。 
O_TRUNC 若文件存在並且以可寫的方式打開時,此旗標會令文件長度清爲 0,而原來存於該文件的資料也會消失。 
O_APPEND 當讀寫文件時會從文件尾開始移動,        也就是所寫入的數據會以附加的方式加入到文件後面。 
O_NONBLOCK 以不可阻斷的方式打開文件,也就是無論有無數據讀取或等待,都會立即返回進程之中。 
O_NDELAY 同 O_NONBLOCK。 
O_SYNC 以同步的方式打開文件。 
O_NOFOLLOW 如果參數 pathname 所指的文件爲一符號連接,則會令打開文件失敗。 
O_DIRECTORY 如果參數 pathname 所指的文件並非爲一目錄,  則 
    會令打開文件失敗。此爲 Linux2.2 以後特有的旗標,以避免一些系 
    統安全問題。參數 mode 則有下列數種組合,只有在建立新文件時 
    纔會生效,此外真正建文件時的權限會受到 umask 值所影響,因此 
    該文件權限應該爲(mode-umaks). 
S_IRWXU00700 權限, 代表該文件所有者具有可讀、    可寫及可執行的權限。 
S_IRUSR 或 S_IREAD,00400 權限,代表該文件所有者具有可讀取的權限。 
S_IWUSR 或 S_IWRITE,00200 權限,代表該文件所有者具有可寫入的權限。 
S_IXUSR 或 S_IEXEC,00100 權限,代表該文件所有者具有可執行的權限。 
S_IRWXG 00070 權限,代表該文件用戶組具有可讀、    可寫及可執行的權限。 
S_IRGRP 00040 權限,代表該文件用戶組具有可讀的權限。 
S_IWGRP 00020 權限,代表該文件用戶組具有可寫入的權限。 
S_IXGRP 00010 權限,代表該文件用戶組具有可執行的權限。 
S_IRWXO 00007 權限,代表其他用戶具有可讀、可寫及可執行的權限。 
S_IROTH 00004 權限,代表其他用戶具有可讀的權限 
S_IWOTH 00002 權限,代表其他用戶具有可寫入的權限。 
S_IXOTH 00001 權限,代表其他用戶具有可執行的權限。 


返回值: 
     若所有欲覈查的權限都通過了檢查則返回 0 值,表示成功,只要有 一個權限被禁止則返回-1。 

錯誤代碼: 
EEXIST 參數 pathname 所指的文件已存在,卻使用了 O_CREAT和 O_EXCL 旗標 
EACCESS 參數 pathname 所指的文件不符合所要求測試的權限。 
EROFS 欲測試寫入權限的文件存在於只讀文件系統內。 
EFAULT 參數 pathname 指針超出可存取內存空間。 
EINVAL 參數 mode 不正確。 
ENAMETOOLONG 參數 pathname 太長。 
ENOTDIR 參數 pathname 不是目錄。 
ENOMEM 核心內存不足。 
ELOOP 參數 pathname 有過多符號連接問題。 
EIO I/O 存取錯誤。 

範例: 

#include <unistd.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 
#include <stdio.h> 

int main(void) 

    int fd,size; 
    char s[]="This program is used to show how to use open(),write(),read() function.\nHave fun!\n"; 
    char buffer[80]; 
    
    fd = open( "temp.log", O_WRONLY|O_CREAT );//以可讀寫的方式打開一個文件,如果不存在則創建該文件 

    if ( -1 == fd ) 
    { 
        printf("Open or create file named \"temp.log\" failed.\n"); 
        return -1; 
    } 
    write( fd, s, sizeof(s) );//向該文件中寫入一個字符串 

    close( fd ); 
    
    fd = open( "temp.log", O_RDONLY ); 
    if ( -1 == fd ) 
    { 
        printf("Open file named \"temp.log\" failed.\n"); 
        return -1; 
    } 
    size = read( fd, buffer, sizeof(buffer) );//讀取文件內容保存到buffer指定的字符串數組中,返回讀取的字符個數 

    close( fd ); 
    printf( "%s", buffer ); 
    
    return 0; 
}
一、       從resource中的raw文件夾中獲取文件並讀取數據(資源文件只能讀不能寫) 

String res = ""; 

try{ 

InputStream in = getResources().openRawResource(R.raw.bbi); 

//在\Test\res\raw\bbi.txt, 

   int length = in.available();       

   byte [] buffer = new byte[length];        

   in.read(buffer);         

   //res = EncodingUtils.getString(buffer, "UTF-8"); 

   //res = EncodingUtils.getString(buffer, "UNICODE"); 

   res = EncodingUtils.getString(buffer, "BIG5"); 

   //依bbi.txt的編碼類型選擇合適的編碼,如果不調整會亂碼 

   in.close();            

   }catch(Exception e){ 

      e.printStackTrace();         

   } 

myTextView.setText(res);//把得到的內容顯示在TextView上 


二、       從asset中獲取文件並讀取數據(資源文件只能讀不能寫) 

String fileName = "yan.txt"; //文件名字 

String res=""; 

try{ 

   InputStream in = getResources().getAssets().open(fileName); 

   // \Test\assets\yan.txt這裏有這樣的文件存在 

   int length = in.available();         

byte [] buffer = new byte[length];        

in.read(buffer);            

res = EncodingUtils.getString(buffer, "UTF-8");     

}catch(Exception e){ 

      e.printStackTrace();         

   } 


三、       從sdcard中去讀文件,首先要把文件通過\android-sdk-windows\tools\adb.exe把本地計算機上的文件copy到sdcard上去,adb.exe push e:/Y.txt /sdcard/, 不可以用adb.exe push e:\Y.txt \sdcard\ 同樣: 把仿真器上的文件copy到本地計算機上用: adb pull ./data/data/com.tt/files/Test.txt e:/ 



String fileName = "/sdcard/Y.txt"; 

//也可以用String fileName = "mnt/sdcard/Y.txt"; 

String res="";     

try{ 

FileInputStream fin = new FileInputStream(fileName); 

//FileInputStream fin = openFileInput(fileName);  

//用這個就不行了,必須用FileInputStream 

    int length = fin.available(); 

    byte [] buffer = new byte[length]; 

    fin.read(buffer);     

    res = EncodingUtils.getString(buffer, "UTF-8"); 

    fin.close();     

    }catch(Exception e){ 

           e.printStackTrace(); 



myTextView.setText(res); 


四、       寫文件, 一般寫在\data\data\com.test\files\裏面,打開DDMS查看file explorer是可以看到仿真器文件存放目錄的結構的 

   String fileName = "TEST.txt"; 

   String message = "FFFFFFF11111FFFFF" ; 

writeFileData(fileName, message); 

  

   public voidwriteFileData(String fileName,String message){ 

       try{ 

        FileOutputStream fout =openFileOutput(fileName, MODE_PRIVATE); 

        byte [] bytes = message.getBytes(); 

        fout.write(bytes); 

         fout.close(); 

        } 

       catch(Exception e){ 

        e.printStackTrace(); 

       } 

   }    


五、       寫, 讀data/data/目錄(相當AP工作目錄)上的文件,用openFileOutput 

   //寫文件在./data/data/com.tt/files/下面 

   public voidwriteFileData(String fileName,String message){ 

       try{ 

        FileOutputStream fout =openFileOutput(fileName, MODE_PRIVATE); 

        byte [] bytes = message.getBytes(); 

        fout.write(bytes); 

         fout.close(); 

        } 

       catch(Exception e){ 

        e.printStackTrace(); 

       } 

   } 

//------------------------------------------------------- 

//讀文件在./data/data/com.tt/files/下面 

   public String readFileData(String fileName){ 

        String res=""; 

        try{ 

         FileInputStream fin = openFileInput(fileName); 

         int length = fin.available(); 

         byte [] buffer = new byte[length]; 

         fin.read(buffer);     

         res = EncodingUtils.getString(buffer, "UTF-8"); 

         fin.close();     

        } 

        catch(Exception e){ 

         e.printStackTrace(); 

        } 

        return res; 

    }   
六、       寫, 讀sdcard目錄上的文件,要用FileOutputStream, 不能用openFileOutput 



    //寫在/mnt/sdcard/目錄下面的文件 

   public voidwriteFileSdcard(String fileName,String message){ 

       try{ 

        //FileOutputStream fout = openFileOutput(fileName, MODE_PRIVATE); 

       FileOutputStream fout = newFileOutputStream(fileName); 

        byte [] bytes = message.getBytes(); 

        fout.write(bytes); 

         fout.close(); 

        } 

       catch(Exception e){ 

        e.printStackTrace(); 

       } 

   } 

  

   //讀在/mnt/sdcard/目錄下面的文件 

   public String readFileSdcard(String fileName){ 

        String res=""; 

        try{ 

         FileInputStream fin = new FileInputStream(fileName); 

         int length = fin.available(); 

         byte [] buffer = new byte[length]; 

         fin.read(buffer);     

         res = EncodingUtils.getString(buffer, "UTF-8"); 

         fin.close();     

        } 

        catch(Exception e){ 

         e.printStackTrace(); 

        } 

        return res; 

   } 



注: openFileOutput是在raw裏編譯過的,FileOutputStream是任何文件都可以 


參考:http://dev.10086.cn/cmdn/wiki/index.php?doc-view-6017.html
                        asc碼對照表 
------------------------------------------------------------- 
    ASCII Characters                            
                            
Dec   Hex       Char    Code   Dec   Hex  Char 
                            
0     0         NUL            64    40    @ 
1     1         SOH            65    41    A 
2     2         STX            66    42    B 
3     3         ETX            67    43    C 
4     4         EOT            68    44    D 
5     5         ENQ            69    45    E 
6     6         ACK            70    46    F 
7     7         BEL            71    47    G 
8     8         BS             72    48    H 
9     9         HT             73    49    I 
10    0A        LF             74    4A    J 
11    0B        VT             75    4B    K 
12    0C        FF             76    4C    L 
13    0D        CR             77    4D    M 
14    0E        SO             78    4E    N 
15    0F        SI             79    4F    O 
16    10        SLE            80    50    P 
17    11        CS1            81    51    Q 
18    12        DC2            82    52    R 
19    13        DC3            83    53    S 
20    14        DC4            84    54    T 
21    15        NAK            85    55    U 
22    16        SYN            86    56    V 
23    17        ETB            87    57    W 
24    18        CAN            88    58    X 
25    19        EM             89    59    Y 
26    1A        SIB            90    5A    Z 
27    1B        ESC            91    5B    [ 
28    1C        FS             92    5C    / 
29    1D        GS             93    5D    ] 
30    1E        RS             94    5E    ^ 
31    1F        US             95    5F    _ 
32    20    (space)            96    60    ` 
33    21        !              97    61    a 
34    22        "              98    62    b 
35    23        #              99    63    c 
36    24        $              100    64    d  
37    25        %              101    65    e 
38    26        &              102    66    f 
39    27        '              103    67    g 
40    28        (              104    68    h 
41    29        )              105    69    i 
42    2A        *              106    6A    j 
43    2B        +              107    6B    k 
44    2C        ,              108    6C    l 
45    2D        -              109    6D    m 
46    2E        .              110    6E    n 
47    2F        /              111    6F    o 
48    30        0              112    70    p 
49    31        1              113    72    q 
50    32        2              114    72    r 
51    33        3              115    73    s 
52    34        4              116    74    t 
53    35        5              117    75    u 
54    36        6              118    76    v 
55    37        7              119    77    w 
56    38        8              120    78    x 
57    39        9              121    79    y 
58    3A        :              122    7A    z 
59    3B        ;              123    7B    { 
60    3C        <              124    7C    | 
61    3D        =              125    7D    } 
62    3E        >              126    7E    ~ 
63    3F        ?              127    7F   

目前計算機中用得最廣泛的字符集及其編碼,是由美國國家標準局(ANSI)制定的ASCII碼(American Standard Code for Information Interchange,美國標準信息交換碼),它已被國際標準化組織(ISO)定爲國際標準,稱爲ISO 646標準。適用於所有拉丁文字字母,ASCII碼有7位碼和8位碼兩種形式。  

  因爲1位二進制數可以表示(21=)2種狀態:0、1;而2位二進制數可以表示(22)=4種狀態:00、01、10、11;依次類推,7位二進制數可以表示(27=)128種狀態,每種狀態都唯一地編爲一個7位的二進制碼,對應一個字符(或控制碼),這些碼可以排列成一個十進制序號0~127。所以,7位 ASCII碼是用七位二進制數進行編碼的,可以表示128個字符。  

  第0~32號及第127號(共34個)是控制字符或通訊專用字符,如控制符:LF(換行)、CR(回車)、FF(換頁)、DEL(刪除)、BEL(振鈴)等;通訊專用字符:SOH(文頭)、EOT(文尾)、ACK(確認)等; 

  第33~126號(共94個)是字符,其中第48~57號爲0~9十個阿拉伯數字;65~90號爲26個大寫英文字母,97~122號爲26個小寫英文字母,其餘爲一些標點符號、運算符號等。  

  注意:在計算機的存儲單元中,一個ASCII碼值佔一個字節(8個二進制位),其最高位(b7)用作奇偶校驗位。所謂奇偶校驗,是指在代碼傳送過程中用來檢驗是否出現錯誤的一種方法,一般分奇校驗和偶校驗兩種。奇校驗規定:正確的代碼一個字節中1的個數必須是奇數,若非奇數,則在最高位b7添1;偶校驗規定:正確的代碼一個字節中1的個數必須是偶數,若非偶數,則在最高位b7添1。  
    第128~255號爲擴展字符(不常用),如需要請下載:完整的8位ASCII字符表  
Android2.3的輸入事件流程與以前版本有了較大的不同,這裏做一下詳細的分析,最後我把自己分析時用的演示代碼放在了這裏: 

http://code.google.com/p/flying-on-android/ 

下面的分析都是基於這些源碼的,大家可以下載下來一邊看源碼一邊看文檔。源碼裏只要關注FlyingEvent這個類就可以了。如果只想看一下演示結果,可以直接把包裏的flying放到機器的/system/bin目錄執行,打開logcat後就可以看到演示輸出。運行程序時,機器屏幕會有異象產生,很正常,因爲這個程序原本是用於顯示SurfaceFlinger的,這次爲了演示EventHub稍微改了一下。大家只要關注 FlyingEvent.cpp這個文件就好了。 

大家也可以用源碼自己編譯出演示程序,只要把解壓後的flying文件夾放到/frameworks/base/cmds/目錄下,然後切換到flying目錄下使用mm編譯。 



先大致介紹一下整個流程,再做重點分析。輸入事件流程一共涉及到下面這幾個文件: 

/frameworks/base/services/java/com/android/server/WindowManagerService.java 

/frameworks/base/services/java/com/android/server/InputManager.java 

/frameworks/base/services/jni/com_android_server_InputManager.cpp 

/frameworks/base/libs/ui/InputReader.cpp 

/frameworks/base/libs/ui/InputDispatcher.cpp 

/frameworks/base/libs/ui/EventHub.cpp 

其中,WindowManagerService.java和InputManager.java主要向Android爲窗口系統提供服務,EventHub.cpp主要用來讀取設備文件中的RawEvent,而InputReader.cpp和InputDispatcher.cpp算是它們之間的對接層。 



它們的關係是:WindowManagerService通過InputManager提供的接口開啓一個線程驅動InputReader不斷地從 /dev/input/目錄下面的設備文件讀取事件,然後通過InputDispatcher分發給連接到WindowManagerService服務的客戶端。 

InputReader從設備文件中讀取的是RawEvent,在交給InputDispatcher進行分發之前,它需要先把RawEvent進行轉化分類,拆分成KeyEvent、MotionEvent、TrackEvent各種類型等。這篇文章主要關注的就是這個RawEvent的拆分過程,所以我們的重點在EventHub.cpp中。並且,爲了簡單化分析過程,在這裏我的分析只關注觸摸屏事件。看它是如何從RawEvent被拆分成應用層用戶事件MotionEvent的。 



看下面的分析之前,最好先去上面提到的地址把源碼下載下來,參照裏面的FlyingEvent.cpp。 



整個過程大致分成這麼幾步: 

一、初始化。 

先new一個EventHub的實例:mEventHub(new EventHub), 

接下來,開啓一個線程通過mEventHub不停地從設備文件中讀取RawEvent並處理: 

while (1) { 

    RawEvent event; 

    mEventHub->getEvent(&event); 

    process(event); 



EventHub在初始化的時候做一些事情, 

1、搜索當前的輸入設備每搜索到一個就會產生一個類型爲DEVICE_ADDED的事件,當讀取這種RawEvent時,InputReader會把搜索到的這個設備記錄下來。 

2、如果搜索到了鍵盤時,就會加載鍵盤佈局文件。加載完成後產生一個類型爲FINISHED_DEVICE_SCAN的事件。這樣,後邊從驅動讀取用戶按鍵時,就會去加載的鍵盤佈局文件中尋找映射的鍵值封裝成KeyEvent返回給用戶。 



二、EventHub初始化完畢後,就開始等待用戶輸入。線程一直阻塞在mEventHub->getEvent(&event),直到有用戶事件產生纔會返回。 

當有一個事件產生時,傳遞給process進行處理。 



三、事件拆分 

FlyingEvent.process裏面主要調用了FlyingEvent.consume方法來處理用戶事件。這裏只分析touch事件。touch事件可以分爲三種:down,move,up。 

down類型的touch事件需要四個RawEvent來完成,第一個是X座標(ABS_X),第二個是Y座標(ABS_Y),第三個代表方向(ABS_PRESSURE)(0的時候是up,1的時候是down,所以這裏應該是1),第四個是結束標誌(SYN_REPORT)。 

move類型的touch事件需要三個RawEvent來完成,第一個是X座標,第二個是Y座標,第三個是結束標誌。 

up類型的touch事件需要兩個RawEvent來完成,第一個代表方向(0的時候是up,1的時候是down,所以這裏應該是0),第四個是結束標誌。 

可能你已經注意到了up事件是沒有座標信息的,它的座標信息與down(沒有move時)或最後一個move(down和up之間有move事件產生)事件的座標相同。 



從FlyingEvent.consume方法中,每一個事件最終都會生成一個TouchEvent,然後調用printTouchEvent進行打印,最後把它存儲到eventBuffer中。 





參考文章 

李先靜的“Android輸入事件流程“,不過使用的Android版本比較老了。 

http://blog.csdn.net/absurd/archive/2009/05/17/4195363.aspx 

(摘自:http://blog.csdn.net/a345017062/article/details/6417929)
1.對文件和目錄的修改還原 
svn revert PATH... 
描述 
恢復所有對文件和目錄的修改,並且解決所有的衝突狀態。svn revert不會只是恢復工作拷貝中一個項目的內容,也包括了對屬性修改的恢復。最終,你可以使用它來取消所有已經做過的預定操作(例如,文件預定要添加或刪除可以“恢復”)。 

例子 
丟棄對一個文件的修改: 

$ svn revert foo.c 
Reverted foo.c 

如果你希望恢復一整個目錄的文件,可以使用--recursive選項: 

$ svn revert --recursive . 
Reverted newdir/afile 
Reverted foo.c 
Reverted bar.txt 

2.還原到以前版本 
svn update -r 200 test.php(將版本庫中的文件test.php還原到版本200) 

3.列出本地與SVN當前版本差異 
svn status -v path(顯示文件和子目錄狀態) 
簡寫:svn st 
第一列保持相同,第二列顯示工作版本號,第三和第四列顯示最後一次修改的版本號和修改人。 
另外,可執行script -q tty.log後,就開始記錄終端的輸入輸出信息,結束的時候按ctrl+D即可得到終端的內容文件tty.log

4. svn比較差異 
svn diff path(將修改的文件與基礎版本比較) 
例如:svn diff test.php 
svn diff -r m:n path(對版本m和版本n比較差異) 

注:svn status、svn diff和 svn revert這三條命令在沒有網絡的情況下也可以執行的,原因是svn在本地的.svn中保留了本地版本的原始拷貝。 

在Linux下查看內存我們一般用free命令: 
[root@scs-2 tmp]# free 
             total       used       free     shared    buffers     cached 
Mem:       3266180    3250004      16176          0     110652    2668236 
-/+ buffers/cache:     471116    2795064 
Swap:      2048276      80160    1968116 

下面是對這些數值的解釋: 
total:總計物理內存的大小。 
used:已使用多大。 
free:可用有多少。 
Shared:多個進程共享的內存總額。 
Buffers/cached:磁盤緩存的大小。 
第三行(-/+ buffers/cached): 
used:已使用多大。 
free:可用有多少。 
第四行就不多解釋了。 
區別:第二行(mem)的used/free與第三行(-/+ buffers/cache) used/free的區別。 這兩個的區別在於使用的角度來看,第一行是從OS的角度來看,因爲對於OS,buffers/cached 都是屬於被使用,所以他的可用內存是16176KB,已用內存是3250004KB,其中包括,內核(OS)使用+Application(X, oracle,etc)使用的+buffers+cached. 
第三行所指的是從應用程序角度來看,對於應用程序來說,buffers/cached 是等於可用的,因爲buffer/cached是爲了提高文件讀取的性能,當應用程序需在用到內存的時候,buffer/cached會很快地被回收。 
所以從應用程序的角度來說,可用內存=系統free memory+buffers+cached。 
如上例: 
2795064=16176+110652+2668236 

接下來解釋什麼時候內存會被交換,以及按什麼方交換。 當可用內存少於額定值的時候,就會開會進行交換。 
如何看額定值: 
cat /proc/meminfo 

[root@scs-2 tmp]# cat /proc/meminfo 
MemTotal:      3266180 kB 
MemFree:         17456 kB 
Buffers:        111328 kB 
Cached:        2664024 kB 
SwapCached:          0 kB 
Active:         467236 kB 
Inactive:      2644928 kB 
HighTotal:           0 kB 
HighFree:            0 kB 
LowTotal:      3266180 kB 
LowFree:         17456 kB 
SwapTotal:     2048276 kB 
SwapFree:      1968116 kB 
Dirty:               8 kB 
Writeback:           0 kB 
Mapped:         345360 kB 
Slab:           112344 kB 
Committed_AS:   535292 kB 
PageTables:       2340 kB 
VmallocTotal: 536870911 kB 
VmallocUsed:    272696 kB 
VmallocChunk: 536598175 kB 
HugePages_Total:     0 
HugePages_Free:      0 
Hugepagesize:     2048 kB 

用free -m查看的結果: 
[root@scs-2 tmp]# free -m 
             total       used       free     shared    buffers     cached 
Mem:          3189       3173         16          0        107       2605 
-/+ buffers/cache:        460       2729 
Swap:         2000         78       1921 


查看/proc/kcore文件的大小(內存鏡像): 
[root@scs-2 tmp]# ll -h /proc/kcore 
-r-------- 1 root root 4.1G Jun 12 12:04 /proc/kcore 

備註: 

佔用內存的測量 

測量一個進程佔用了多少內存,linux爲我們提供了一個很方便的方法,/proc目錄爲我們提供了所有的信息,實際上top等工具也通過這裏來獲取相應的信息。 

/proc/meminfo 機器的內存使用信息 

/proc/pid/maps pid爲進程號,顯示當前進程所佔用的虛擬地址。 

/proc/pid/statm 進程所佔用的內存 

[root@localhost ~]# cat /proc/self/statm 

654 57 44 0 0 334 0 

輸出解釋 

CPU 以及CPU0。。。的每行的每個參數意思(以第一行爲例)爲: 

參數 解釋 /proc//status 

Size (pages) 任務虛擬地址空間的大小 VmSize/4 

Resident(pages) 應用程序正在使用的物理內存的大小 VmRSS/4 

Shared(pages) 共享頁數 0 

Trs(pages) 程序所擁有的可執行虛擬內存的大小 VmExe/4 

Lrs(pages) 被映像到任務的虛擬內存空間的庫的大小 VmLib/4 

Drs(pages) 程序數據段和用戶態的棧的大小 (VmData+ VmStk )4 

dt(pages) 04 

查看機器可用內存 

/proc/28248/>free 

total used free shared buffers cached 

Mem: 1023788 926400 97388 0 134668 503688 

-/+ buffers/cache: 288044 735744 

Swap: 1959920 89608 1870312 

我們通過free命令查看機器空閒內存時,會發現free的值很小。這主要是因爲,在linux中有這麼一種思想,內存不用白不用,因此它儘可能的cache和buffer一些數據,以方便下次使用。但實際上這些內存也是可以立刻拿來使用的。

所以 空閒內存=free+buffers+cached=total-used 
一:update.zip包的製作 
   1:新建一個目標,在此目錄下準備好需要的文件,如system目錄文件、boot.img、recovery.img等. 
     mkdir testupdate 
     cp system/ testupdate/ -tf 
     注:如果文件是system.img鏡像可以用unyaffs解壓出來得到system 
   2:用make-update-script工具生成update-script腳本,如下 
     cp make-update-script testupdate/ 
     cp android-info.txt testupdate/ 
     cd testupdate 
     ./make-update-script system android-info.txt > update-script 
     rm make-update-script android-info.txt 
     vi update-script //根據需要適當修改些腳本 
      說明:system是要更新的目錄,android-info.txt是板的版本信息,update-script是輸出文件名 
   3:建立一個目錄名稱爲META-INF/com/google/android,把上面生成的腳本放進去 
      mkdir -p META-INF/com/google/android 
      mv update-script META-INF/com/google/android/ 
   4:壓縮文件 
     zip -r update.zip system META-INF 
   5:給壓縮文件添加簽名 
     mv update.zip ../signapk/ 
     cd ../signapk/ 
     java -jar signapk.jar testkey.x509.pem testkey.pk8 update.zip signed-update.zip 
   6:刪除多餘的文件,並把生成的包重命名 
     rm update.zip 
     mv signed-update.zip ../update.zip 
     cd ../ 
   7:大功告成,把更新包update.zip拷到sdcard根目錄下去驗證吧! 

   注意: 
   1)如果文件裏有連接,應該在獲取update-script之後在原文件裏刪除鏈接文件,再打包,否則symlink將出錯; 
   2)如果原文件裏有空目錄,所獲的簽名將失去此記錄,所以如果空目錄必須存在,更新之後的文件將與原文件不同(少了空目錄) 

二:ramdisk.img 製作 
   方法1: 
     解壓: 
        1) mv ramdisk.img ramdisk.img.gz 
        2) gunzip ramdisk,img.gz 
        3) mkdir ramdisk;cd ramdisk 
        4) cpio -i -F ../ramdisk.img 
     壓縮: 
        1) 產生要pack的目錄list,也可以自己列 
           cpio -i -t -F ../ramdisk.img > list 
        2) 利用剛生成的list文件列表,cpio歸檔 
           cpio -o -H newc -O new.img < list 
        3) gzip new.img 
   方法2: 
       解壓:  gunzip -c ../your-ramdisk-file | cpio -i 
       壓縮:  find . | cpio -o -H newc | gzip > ../newramdisk.cpio.gz 

   注意:在android裏的做法是 
       1)先得到ramdisk所需要的文件,比如root目錄 
       2)用mkbootfs製作ramdisk.img,用法如下 
          mkbootfs root | gzip > ramdisk.img 
       這裏需要驗證哪個能用android寫下去 

三:boot.img的製作 
    1:android正常做法 
        1):連接 
           mkbootimg --kernel your-kernel-file --ramdisk newramdisk.cpio.gz --cmdline "mem=128 console=ttymxc0,115200n8 init=/init rw" --output mynewimage.img 
           或 
           mkbootimg --kernel your-kernel-file --ramdisk newramdisk.cpio.gz --cmdline  --output mynewimage.img 

        2):提取img中的kernel和ramdisk 
           ./split_bootimg.pl mynewimage.img 

    2:uboot 
       直接把uImage重命名爲boot.img即可 

四:system.img的製作(只爲 yaffs2格式) 
        1)壓制:./mkyaffs2image system/ system.img 
        2)解壓:./unyaffs system.img 

四:system.img的製作(只爲yaffs2格式) 
        1)壓制:./mkyaffs2image system/ system.img 
        2)解壓:./unyaffs system.img 

五:recovery.img的製作 
        1:如果recovery的鏡像是隻有文件系統部分時候可以如第四所示範 
        2:如果recovery爲ramdisk形式 

============================================= 
制 作ramdisk的過程。 
1.在/mnt下創建rdmnt 和 rdimg 目錄 
mkdir rdmnt 
  mkdir rdimg 
2.創建一個ramdisk文件,大小32768 X 1k。 
dd if=/dev/zero of=rdimg/ramdisk bs=1k count=32768 
3.使用ext2方式格式該文件 
mke2fs  -F -v -m0 rdimg/ramdisk 
4.將該ramdisk文件和rdmnt掛載 
  mount -o loop rdimg/ramdisk  rdmnt/ 
5.拷貝文件到掛載目錄中。 
文件系統目錄在:/home/xrqun/workdir/filesys/ 
  cp –av /home/xrqun/workdir/filesys/*  rdmnt 
6.卸載ramdisk 
  umount rdmnt 
7壓縮 ramdisk文件 
  gzip –c -9 <rdimg/ramdisk > rdimg/ramdisk.gz 
8.拷貝該ramdisk.gz映像到tftpboot目錄下 
  cp rdimg/ramdisk.gz /tftpboot/ 
9. 使用mkimage工具 
    mkimage  -n "uboot.ramdisk.filesys" -A arm -O linux -T ramdisk -C gzip  -d ramdisk.gz  uboot.ramdisk.gz 

參考:http://liaowb1234.blog.163.com/blog/static/771555472010027104534626/ 
http://www.cnblogs.com/sdphome/archive/2011/03/20/1989826.html 

svn_externals: 
src/android ###/frameworks/base/core/java/android 
src/com ###/frameworks/base/core/java/com 
src/com/android/internal/policy ###/frameworks/base/policy/src/com/android/internal/policy 
src/com/android/server ###/frameworks/base/services/java/com/android/server 
src/com/android/systemui/statusbar ###/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar 
src/android/telephony ###/frameworks/base/telephony/java/android/telephony 
src/com/android/internal/telephony ###/frameworks/base/telephony/java/com/android/internal/telephony 
src/android/opengl ###/frameworks/base/opengl/java/android/opengl 
src/javax/microedition/khronos ###/frameworks/base/opengl/java/javax/microedition/khronos 
src/android/drm ###/frameworks/base/media/java/android/drm 
src/android/media ###/frameworks/base/media/java/android/media 
src/android/graphics ###/frameworks/base/graphics/java/android/graphics 
src/android/renderscript ###/frameworks/base/graphics/java/android/renderscript 
src/com/android/internal/graphics ###/frameworks/base/graphics/java/com/android/internal/graphics 

svn_ignore: 
assets 
libs 
build_oms.xml 
.classpath 
.project 
bin
無論是在linux還是在Unix環境中,make都是一個非常重要的編譯命令。不管是自己進行項目開發還是安裝應用軟件,我們都經常要用到make或make install。利用make工具,我們可以將大型的開發項目分解成爲多個更易於管理的模塊,對於一個包括幾百個源文件的應用程序,使用make和 makefile工具就可以簡潔明快地理順各個源文件之間紛繁複雜的相互關係。而且如此多的源文件,如果每次都要鍵入gcc命令進行編譯的話,那對程序員來說簡直就是一場災難。而make工具則可自動完成編譯工作,並且可以只對程序員在上次編譯後修改過的部分進行編譯。因此,有效的利用make和 makefile工具可以大大提高項目開發的效率。同時掌握make和makefile之後,您也不會再面對着Linux下的應用軟件手足無措了。 
  但令人遺憾的是,在許多講述linux應用的書籍上都沒有詳細介紹這個功能強大但又非常複雜的編譯工具。在這裏我就向大家詳細介紹一下make及其描述文件makefile。 
Makefile文件 
  Make工具最主要也是最基本的功能就是通過makefile文件來描述源程序之間的相互關係並自動維護編譯工作。而makefile 文件需要按照某種語法進行編寫,文件中需要說明如何編譯各個源文件並連接生成可執行文件,並要求定義源文件之間的依賴關係。makefile 文件是許多編譯器--包括 Windows NT 下的編譯器--維護編譯信息的常用方法,只是在集成開發環境中,用戶通過友好的界面修改 makefile 文件而已。 
  在 UNIX 系統中,習慣使用 Makefile 作爲 makfile 文件。如果要使用其他文件作爲 makefile,則可利用類似下面的 make 命令選項指定 makefile 文件: 
  $ make -f Makefile.debug 
  例如,一個名爲prog的程序由三個C源文件filea.c、fileb.c和filec.c以及庫文件LS編譯生成,這三個文件還分別包含自己的頭文件a.h 、b.h和c.h。通常情況下,C編譯器將會輸出三個目標文件filea.o、fileb.o和filec.o。假設filea.c和fileb.c都要聲明用到一個名爲defs的文件,但filec.c不用。即在filea.c和fileb.c裏都有這樣的聲明: 
  #include "defs" 
  那麼下面的文檔就描述了這些文件之間的相互聯繫: 
  --------------------------------------------------------- 
   #It is a example for describing makefile 
   prog : filea.o fileb.o filec.o 
   cc filea.o fileb.o filec.o -LS -o prog 
   filea.o : filea.c a.h defs 
   cc -c filea.c 
   fileb.o : fileb.c b.h defs 
   cc -c fileb.c 
   filec.o : filec.c c.h 
   cc -c filec.c 
  ---------------------------------------------------------- 
  這個描述文檔就是一個簡單的makefile文件。 
  從上面的例子注意到,第一個字符爲 # 的行爲註釋行。第一個非註釋行指定prog由三個目標文件filea.o、fileb.o和filec.o鏈接生成。第三行描述瞭如何從prog所依賴的文件建立可執行文件。接下來的4、6、8行分別指定三個目標文件,以及它們所依賴的.c和.h文件以及defs文件。而5、7、9行則指定了如何從目標所依賴的文件建立目標。 
  當filea.c或a.h文件在編譯之後又被修改,則 make 工具可自動重新編譯filea.o,如果在前後兩次編譯之間,filea.C 和a.h 均沒有被修改,而且 test.o 還存在的話,就沒有必要重新編譯。這種依賴關係在多源文件的程序編譯中尤其重要。通過這種依賴關係的定義,make 工具可避免許多不必要的編譯工作。當然,利用 Shell 腳本也可以達到自動編譯的效果,但是,Shell 腳本將全部編譯任何源文件,包括哪些不必要重新編譯的源文件,而 make 工具則可根據目標上一次編譯的時間和目標所依賴的源文件的更新時間而自動判斷應當編譯哪個源文件。 
Makefile文件作爲一種描述文檔一般需要包含以下內容: 
  ◆ 宏定義 
  ◆ 源文件之間的相互依賴關係 
  ◆ 可執行的命令 
  Makefile中允許使用簡單的宏指代源文件及其相關編譯信息,在linux中也稱宏爲變量。在引用宏時只需在變量前加$符號,但值得注意的是,如果變量名的長度超過一個字符,在引用時就必須加圓括號()。 
  下面都是有效的宏引用: 
  $(CFLAGS) 
  $2 
  $Z 
  $(Z) 
  其中最後兩個引用是完全一致的。 
  需要注意的是一些宏的預定義變量,在Unix系統中,$*、$@、$?和$<四個特殊宏的值在執行命令的過程中會發生相應的變化,而在GNU make中則定義了更多的預定義變量。關於預定義變量的詳細內容, 
  宏定義的使用可以使我們脫離那些冗長乏味的編譯選項,爲編寫makefile文件帶來很大的方便。 
  --------------------------------------------------------- 
   # Define a macro for the object files 
   OBJECTS= filea.o fileb.o filec.o 
   # Define a macro for the library file 
   LIBES= -LS 
   # use macros rewrite makefile 
   prog: $(OBJECTS) 
   cc $(OBJECTS) $(LIBES) -o prog 
   …… 
  --------------------------------------------------------- 
  此時如果執行不帶參數的make命令,將連接三個目標文件和庫文件LS;但是如果在make命令後帶有新的宏定義: 
  make "LIBES= -LL -LS" 
則命令行後面的宏定義將覆蓋makefile文件中的宏定義。若LL也是庫文件,此時make命令將連接三個目標文件以及兩個庫文件LS和LL。 
  在Unix系統中沒有對常量NULL作出明確的定義,因此我們要定義NULL字符串時要使用下述宏定義: 
  STRINGNAME= 
Make命令 
  在make命令後不僅可以出現宏定義,還可以跟其他命令行參數,這些參數指定了需要編譯的目標文件。其標準形式爲: 
  target1 [target2 …]:[:][dependent1 …][;commands][#…] 
  [(tab) commands][#…] 
  方括號中間的部分表示可選項。Targets和dependents當中可以包含字符、數字、句點和"/"符號。除了引用,commands中不能含有"#",也不允許換行。 
  在通常的情況下命令行參數中只含有一個":",此時command序列通常和makefile文件中某些定義文件間依賴關係的描述行有關。如果與目標相關連的那些描述行指定了相關的command序列,那麼就執行這些相關的command命令,即使在分號和(tab)後面的aommand字段甚至有可能是NULL。如果那些與目標相關連的行沒有指定command,那麼將調用系統默認的目標文件生成規則。 
  如果命令行參數中含有兩個冒號"::",則此時的command序列也許會和makefile中所有描述文件依賴關係的行有關。此時將執行那些與目標相關連的描述行所指向的相關命令。同時還將執行build-in規則。 
  如果在執行command命令時返回了一個非"0"的出錯信號,例如makefile文件中出現了錯誤的目標文件名或者出現了以連字符打頭的命令字符串,make操作一般會就此終止,但如果make後帶有"-i"參數,則make將忽略此類出錯信號。 
  Make命本身可帶有四種參數:標誌、宏定義、描述文件名和目標文件名。其標準形式爲: 
  Make [flags] [macro definitions] [targets] 
  Unix系統下標誌位flags選項及其含義爲: 
  -f file  指定file文件爲描述文件,如果file參數爲"-"符,那麼描述文件指向標準輸入。如果沒有"-f"參數,則系統將默認當前目錄下名爲 makefile或者名爲Makefile的文件爲描述文件。在linux中, GNU make 工具在當前工作目錄中按照GNUmakefile、makefile、Makefile的順序搜索 makefile文件。 
  -i   忽略命令執行返回的出錯信息。 
  -s   沉默模式,在執行之前不輸出相應的命令行信息。 
  -r   禁止使用build-in規則。 
  -n   非執行模式,輸出所有執行命令,但並不執行。 
  -t   更新目標文件。 
  -q   make操作將根據目標文件是否已經更新返回"0"或非"0"的狀態信息。 
  -p   輸出所有宏定義和目標文件描述。 
  -d   Debug模式,輸出有關文件和檢測時間的詳細信息。 
  linux下make標誌位的常用選項與Unix系統中稍有不同,下面我們只列出了不同部分: 
  -c dir   在讀取 makefile 之前改變到指定的目錄dir。 
  -I dir   當包含其他 makefile文件時,利用該選項指定搜索目錄。 
  -h   help文擋,顯示所有的make選項。 
  -w   在處理 makefile 之前和之後,都顯示工作目錄。 
  通過命令行參數中的target ,可指定make要編譯的目標,並且允許同時定義編譯多個目標,操作時按照從左向右的順序依次編譯target選項中指定的目標文件。如果命令行中沒有指定目標,則系統默認target指向描述文件中第一個目標文件。 
  通常,makefile 中還定義有 clean 目標,可用來清除編譯過程中的中間文件,例如: 
  clean: 
  rm -f *.o 
  運行 make clean 時,將執行 rm -f *.o 命令,最終刪除所有編譯過程中產生的所有中間文件。 
隱含規則 
  在make 工具中包含有一些內置的或隱含的規則,這些規則定義瞭如何從不同的依賴文件建立特定類型的目標。Unix系統通常支持一種基於文件擴展名即文件名後綴的隱含規則。這種後綴規則定義瞭如何將一個具有特定文件名後綴的文件(例如.c文件),轉換成爲具有另一種文件名後綴的文件(例如.o文件): 
  .c:.o 
  $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< 
  系統中默認的常用文件擴展名及其含義爲: 
  .o  目標文件 
  .c  C源文件 
  .f  FORTRAN源文件 
  .s  彙編源文件 
  .y  Yacc-C源語法 
  .l  Lex源語法 
  在早期的Unix系統系統中還支持Yacc-C源語法和Lex源語法。在編譯過程中,系統會首先在makefile文件中尋找與目標文件相關的.C文件,如果還有與之相依賴的.y和.l文件,則首先將其轉換爲.c文件後再編譯生成相應的.o文件;如果沒有與目標相關的.c文件而只有相關的.y文件,則系統將直接編譯.y文件。 
  而GNU make 除了支持後綴規則外還支持另一種類型的隱含規則--模式規則。這種規則更加通用,因爲可以利用模式規則定義更加複雜的依賴性規則。模式規則看起來非常類似於正則規則,但在目標名稱的前面多了一個 % 號,同時可用來定義目標和依賴文件之間的關係,例如下面的模式規則定義瞭如何將任意一個 file.c 文件轉換爲 file.o 文件: 
  %.c:%.o 
  $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< 
#EXAMPLE# 
  下面將給出一個較爲全面的示例來對makefile文件和make命令的執行進行進一步的說明,其中make命令不僅涉及到了C源文件還包括了Yacc 語法。本例選自"Unix Programmer's Manual 7th Edition, Volume 2A" Page 283-284 
  下面是描述文件的具體內容: 
  --------------------------------------------------------- 
   #Description file for the Make command 
   #Send to print 
   P=und -3 | opr -r2 
   #The source files that are needed by object files 
   FILES= Makefile version.c defs main.c donamc.c misc.c file.c 
   dosys.c gram.y lex.c gcos.c 
   #The definitions of object files 
   OBJECTS= vesion.o main.o donamc.o misc.o file.o dosys.o gram.o 
   LIBES= -LS 
   LINT= lnit -p 
   CFLAGS= -O 
   make: $(OBJECTS) 
   cc $(CFLAGS) $(OBJECTS) $(LIBES) -o make 
   size make 
   $(OBJECTS): defs 
   gram.o: lex.c 
   cleanup: 
   -rm *.o gram.c 
   install: 
   @size make /usr/bin/make 
   cp make /usr/bin/make ; rm make 
   #print recently changed files 
   print: $(FILES) 
   pr $? | $P 
   touch print 
   test: 
   make -dp | grep -v TIME>1zap 
   /usr/bin/make -dp | grep -v TIME>2zap 
   diff 1zap 2zap 
   rm 1zap 2zap 
   lint: dosys.c donamc.c file.c main.c misc.c version.c gram.c 
   $(LINT) dosys.c donamc.c file.c main.c misc.c version.c 
   gram.c 
   rm gram.c 
   arch: 
   ar uv /sys/source/s2/make.a $(FILES) 
  ---------------------------------------------------------- 
  通常在描述文件中應象上面一樣定義要求輸出將要執行的命令。在執行了make命令之後,輸出結果爲: 
  $ make 
  cc -c version.c 
  cc -c main.c 
  cc -c donamc.c 
  cc -c misc.c 
  cc -c file.c 
  cc -c dosys.c 
  yacc gram.y 
  mv y.tab.c gram.c 
  cc -c gram.c 
  cc version.o main.o donamc.o misc.o file.o dosys.o gram.o 
  -LS -o make 
  13188+3348+3044=19580b=046174b 

  最後的數字信息是執行"@size make"命令的輸出結果。之所以只有輸出結果而沒有相應的命令行,是因爲"@size make"命令以"@"起始,這個符號禁止打印輸出它所在的命令行。 
  描述文件中的最後幾條命令行在維護編譯信息方面非常有用。其中"print"命令行的作用是打印輸出在執行過上次"make print"命令後所有改動過的文件名稱。系統使用一個名爲print的0字節文件來確定執行print命令的具體時間,而宏$?則指向那些在print 文件改動過之後進行修改的文件的文件名。如果想要指定執行print命令後,將輸出結果送入某個指定的文件,那麼就可修改P的宏定義: 
  make print "P= cat>zap" 
  在linux中大多數軟件提供的是源代碼,而不是現成的可執行文件,這就要求用戶根據自己系統的實際情況和自身的需要來配置、編譯源程序後,軟件才能使用。只有掌握了make工具,才能讓我們真正享受到到Linux這個自由軟件世界的帶給我們無窮樂趣。 

另一篇,http://wiki.ubuntu.org.cn/%E8%B7%9F%E6%88%91%E4%B8%80%E8%B5%B7%E5%86%99Makefile 
build/envsetup.sh腳本分析 
在編譯源代碼之前通常需要在android源代碼頂層目錄執行 . ./build/envsetup.sh 目的是爲了使用 
腳本 envsetup.sh 裏面定義了一些函數: 
function help() 
function get_abs_build_var() 
function get_build_var() 
function check_product() 
function check_variant() 
function setpaths() 
function printconfig() 
function set_stuff_for_environment() 
function set_sequence_number() 
function settitle() 
function choosetype() 
function chooseproduct() 
function choosevariant() 
function tapas() 
function choosecombo() 
function print_lunch_menu() 
function lunch() 
function gettop 
function m() 
function findmakefile() 
function mm() 
function mmm() 
function croot() 
function pid() 
function gdbclient() 
function jgrep() 
function cgrep() 
function resgrep() 
function getprebuilt 
function tracedmdump() 
function runhat() 
function getbugreports() 
function startviewserver() 
function stopviewserver() 
function isviewserverstarted() 
function smoketest() 
function runtest() 
function runtest_py() 
function godir () 
choosecombo 命令分析: 
function choosecombo() 

choosesim $1 
echo 
echo 
choosetype $2 
echo 
echo 
chooseproduct $3 
echo 
echo 
choosevariant $4 
echo 
set_stuff_for_environment 
printconfig 

會依次進行如下選擇: 
Build for the simulator or the device? 
1. Device 
2. Simulator 
Which would you like? [1] 
Build type c 
Build type choices are: 
1. release 
2. debug 
Which would you like? [1] 
Product choices are: 
1. emulator 
2. generic 
3. sim 
4. littleton 
You can also type the name of a product if you know it. 
Which would you like? [littleton] 
Variant choices are: 
1. user 
2. userdebug 
3. eng 
Which would you like? [eng] user 
默認選擇以後會出現: 
TARGET_PRODUCT=littleton 
TARGET_BUILD_VARIANT=user 
TARGET_SIMULATOR=false 
TARGET_BUILD_TYPE=release 
TARGET_ARCH=arm 
HOST_ARCH=x86 
HOST_OS=linux 
HOST_BUILD_TYPE=release 
BUILD_ID= 
========== 
function chooseproduct()函數分析: 
choices=(`/bin/ls build/target/board/*/BoardConfig.mk vendor/*/*/BoardConfig.mk 2> /dev/null`) 
讀取 build/target/board/* 目錄下的板配置文件:BoardConfig.mk 
讀取 vendor/*/*/目錄下的板配置文件:BoardConfig.mk 
choices 的值爲: 
build/target/board/emulator/BoardConfig.mk 
build/target/board/generic/BoardConfig.mk 
build/target/board/sim/BoardConfig.mk 
vendor/marvell/littleton/BoardConfig.mk 
經過: 
for choice in ${choices[@]} 
do 
# The product name is the name of the directory containing 
# the makefile we found, above. 
prodlist=(${prodlist[@]} `dirname ${choice} | xargs basename`) 
done 
的處理,prodlist的值爲: 
emulator generic sim littleton 
所以選擇菜單爲: 
Product choices are: 
1. emulator 
2. generic 
3. sim 
4. littleton 
如果選擇 4,那麼 TARGET_PRODUCT 被賦值爲: littleton。 
board_config_mk := \ 
$(strip $(wildcard \ 
$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \ 
vendor/*/$(TARGET_DEVICE)/BoardConfig.mk \ 
)) 
怎樣添加一個模塊 
LOCAL_PATH:= $(call my-dir) 
#編譯靜態庫 
include $(CLEAR_VARS) 
LOCAL_MODULE = libhellos 
LOCAL_CFLAGS = $(L_CFLAGS) 
LOCAL_SRC_FILES = hellos.c 
LOCAL_C_INCLUDES = $(INCLUDES) 
LOCAL_SHARED_LIBRARIES := libcutils 
LOCAL_COPY_HEADERS_TO := libhellos 
LOCAL_COPY_HEADERS := hellos.h 
include $(BUILD_STATIC_LIBRARY) 
#編譯動態庫 
include $(CLEAR_VARS) 
LOCAL_MODULE = libhellod 
LOCAL_CFLAGS = $(L_CFLAGS) 
LOCAL_SRC_FILES = hellod.c 
LOCAL_C_INCLUDES = $(INCLUDES) 
LOCAL_SHARED_LIBRARIES := libcutils 
LOCAL_COPY_HEADERS_TO := libhellod 
LOCAL_COPY_HEADERS := hellod.h 
include $(BUILD_SHARED_LIBRARY) 
BUILD_TEST=true 
ifeq ($(BUILD_TEST),true) 
#使用靜態庫 
include $(CLEAR_VARS) 
LOCAL_MODULE := hellos 
LOCAL_STATIC_LIBRARIES := libhellos 
LOCAL_SHARED_LIBRARIES := 
LOCAL_LDLIBS += -ldl 
LOCAL_CFLAGS := $(L_CFLAGS) 
LOCAL_SRC_FILES := mains.c 
LOCAL_C_INCLUDES := $(INCLUDES) 
include $(BUILD_EXECUTABLE) 
#使用動態庫 
include $(CLEAR_VARS) 
LOCAL_MODULE := hellod 
LOCAL_MODULE_TAGS := debug 
LOCAL_SHARED_LIBRARIES := libc libcutils libhellod 
LOCAL_LDLIBS += -ldl 
LOCAL_CFLAGS := $(L_CFLAGS) 
LOCAL_SRC_FILES := maind.c 
LOCAL_C_INCLUDES := $(INCLUDES) 
include $(BUILD_EXECUTABLE) 
endif # ifeq ($(WPA_BUILD_SUPPLICANT),true) 
######################## 
#local_target_dir := $(TARGET_OUT)/etc/wifi 
#include $(CLEAR_VARS) 
#LOCAL_MODULE := wpa_supplicant.conf 
#LOCAL_MODULE_TAGS := user 
#LOCAL_MODULE_CLASS := ETC 
#LOCAL_MODULE_PATH := $(local_target_dir) 
#LOCAL_SRC_FILES := $(LOCAL_MODULE) 
#include $(BUILD_PREBUILT) 
######################## 
系統變量解析 
LOCAL_MODULE - 編譯的目標對象 
LOCAL_SRC_FILES - 編譯的源文件 
LOCAL_C_INCLUDES - 需要包含的頭文件目錄 
LOCAL_SHARED_LIBRARIES - 鏈接時需要的外部庫 
LOCAL_PRELINK_MODULE - 是否需要prelink處理 
BUILD_SHARED_LIBRARY - 指明要編譯成動態庫 
LOCAL_PATH - 編譯時的目錄 
$(call 目錄,目錄….) 目錄引入操作符 
如該目錄下有個文件夾名稱 src,則可以這樣寫 $(call src),那麼就會得到 src 目錄的完整路徑 
include $(CLEAR_VARS) -清除之前的一些系統變量 
CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk 
在 build/core/config.mk 定義 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk 
通過include 包含自定義的.mk文件(即是自定義編譯規則)或是引用系統其他的.mk文件(系統定義的編譯規則)。 
LOCAL_SRC_FILES - 編譯的源文件 
可以是.c, .cpp, .java, .S(彙編文件)或是.aidl等格式 
不同的文件用空格隔開。如果編譯目錄子目錄,採用相對路徑,如子目錄/文件名。也可以通過$(call 目錄),指明編譯某目錄 
下所有.c/.cpp/.java/.S/ .aidl文件.追加文件 LOCAL_SRC_FILES += 文件 
LOCAL_C_INCLUDES - 需要包含的頭文件目錄 
可以是系統定義路徑,也可以是相對路徑. 如該編譯目錄下有個include目錄,寫法是include/*.h 
LOCAL_SHARED_LIBRARIES - 鏈接時需要的外部共享庫 
LOCAL_STATIC_LIBRARIES - 鏈接時需要的外部外部靜態 
LOCAL_JAVA_LIBRARIES 加入jar包 
LOCAL_MODULE - 編譯的目標對象 
module 是指系統的 native code,通常針對c,c++代碼 
./system/core/sh/Android.mk:32:LOCAL_MODULE:= sh 
./system/core/libcutils/Android.mk:71:LOCAL_MODULE := libcutils 
./system/core/cpio/Android.mk:9:LOCAL_MODULE := mkbootfs 
./system/core/mkbootimg/Android.mk:8:LOCAL_MODULE := mkbootimg 
./system/core/toolbox/Android.mk:61:LOCAL_MODULE:= toolbox 
./system/core/logcat/Android.mk:10:LOCAL_MODULE:= logcat 
./system/core/adb/Android.mk:65:LOCAL_MODULE := adb 
./system/core/adb/Android.mk:125:LOCAL_MODULE := adbd 
./system/core/init/Android.mk:20:LOCAL_MODULE:= init 
./system/core/vold/Android.mk:24:LOCAL_MODULE:= vold 
./system/core/mountd/Android.mk:13:LOCAL_MODULE:= mountd 
LOCAL_PACKAGE_NAME 
Java 應用程序的名字用該變量定義 
./packages/apps/Music/Android.mk:9:LOCAL_PACKAGE_NAME := Music 
./packages/apps/Browser/Android.mk:14:LOCAL_PACKAGE_NAME := Browser 
./packages/apps/Settings/Android.mk:8:LOCAL_PACKAGE_NAME := Settings 
./packages/apps/Stk/Android.mk:10:LOCAL_PACKAGE_NAME := Stk 
./packages/apps/Contacts/Android.mk:10:LOCAL_PACKAGE_NAME := Contacts 
./packages/apps/Mms/Android.mk:8:LOCAL_PACKAGE_NAME := Mms 
./packages/apps/Camera/Android.mk:8:LOCAL_PACKAGE_NAME := Camera 
./packages/apps/Phone/Android.mk:11:LOCAL_PACKAGE_NAME := Phone 
./packages/apps/VoiceDialer/Android.mk:8:LOCAL_PACKAGE_NAME := VoiceDialer 
BUILD_SHARED_LIBRARY - 指明要編譯成動態庫。 
編譯的目標,用include 操作符 
UILD_STATIC_LIBRARY來指明要編譯成靜態庫。 
如果是java文件的話,會用到系統的編譯腳本host_java_library.mk,用BUILD_PACKAGE來指明。三個編譯 
------------------- 
include $(BUILD_STATIC_LIBRARY) 
BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk 
------------------- 
include $(BUILD_SHARED_LIBRARY) 
./build/core/config.mk:50:BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk 
------------------- 
include $(BUILD_HOST_SHARED_LIBRARY) 
BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk 
------------------- 
include $(BUILD_EXECUTABLE) 
build/core/config.mk:51:BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk 
------------------- 
include $(BUILD_HOST_EXECUTABLE) 
./build/core/config.mk:53:BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk 
------------------- 
BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk 
------------------- 
BUILD_JAVA_LIBRARY 
./build/core/config.mk:58:BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk 
------------------ 
BUILD_STATIC_JAVA_LIBRARY 編譯靜態JAVA庫 
./build/core/config.mk:59:BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk 
------------------ 
BUILD_HOST_JAVA_LIBRARY 編譯本機用的JAVA庫 
./build/core/config.mk:60:BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk 
------------------ 
BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk 
BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk 
BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk 
BUILD_RAW_STATIC_LIBRARY := $(BUILD_SYSTEM)/raw_static_library.mk 
BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk 
BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk 
BUILD_RAW_EXECUTABLE:= $(BUILD_SYSTEM)/raw_executable.mk 
BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk 
BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk 
BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk 
BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk 
BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk 
BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk 
BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk 
BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk 
BUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mk 
BUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mk 
BUILD_KEY_CHAR_MAP := $(BUILD_SYSTEM)/key_char_map.mk 
============ 
LOCAL_PRELINK_MODULE 
Prelink利用事先鏈接代替運行時鏈接的方法來加速共享庫的加載,它不僅可以加快起動速度,還可以減少部分內存開銷, 
是各種Linux架構上用於減少程序加載時間、縮短系統啓動時間和加快應用程序啓動的很受歡迎的一個工具。程序運行時的 
動態鏈接尤其是重定位(relocation)的開銷對於大型系統來說是很大的。 
動態鏈接和加載的過程開銷很大,並且在大多數的系統上, 函數庫並不會常常被更動, 每次程序被執行時所進行的鏈接 
動作都是完全相同的,對於嵌入式系統來說尤其如此。因此,這一過程可以改在運行時之前就可以預先處理好,即花一些時間 
利用Prelink工具對動態共享庫和可執行文件進行處理,修改這些二進制文件並加入相應的重定位等信息,節約了本來在程序 
啓動時的比較耗時的查詢函數地址等工作,這樣可以減少程序啓動的時間,同時也減少了內存的耗用。 
Prelink的這種做法當然也有代價:每次更新動態共享庫時,相關的可執行文件都需要重新執行一遍Prelink才能保 
證有效,因爲新的共享庫中的符號信息、地址等很可能與原來的已經不同了,這就是爲什麼 android framework代碼一改動, 
這時候就會導致相關的應用程序重新被編譯。 
這種代價對於嵌入式系統的開發者來說可能稍微帶來一些複雜度,不過好在對用戶來說幾乎是可以忽略的。 
-------------------- 
變量設置爲false那麼將不做prelink操作 
LOCAL_PRELINK_MODULE := false 
默認是需要prlink的,同時需要在 build/core/prelink-linux-arm.map 中加入 
libhellod.so 0x96000000 
這個map文件好像是制定動態庫的地址的,在前面註釋上面有一些地址範圍的信息,注意庫與庫之間的間隔數, 
如果指定不好的話編譯的時候會提示說地址空間衝突的問題。另外,注意排序,這裏要把數大的放到前面去, 
按照大小降序排序。 
解析 LOCAL_PRELINK_MODULE 變量 
build/core/dynamic_binary.mk:94:ifeq ($(LOCAL_PRELINK_MODULE),true) 
ifeq ($(LOCAL_PRELINK_MODULE),true) 
$(prelink_output): $(prelink_input) $(TARGET_PRELINKER_MAP) $(APRIORI) 
$(transform-to-prelinked) 
transform-to-prelinked定義: 
./build/core/definitions.mk:1002:define transform-to-prelinked 
define transform-to-prelinked 
@mkdir -p $(dir $@) 
@echo "target Prelink: $(PRIVATE_MODULE) ($@)" 
$(hide) $(APRIORI) \ 
--prelinkmap $(TARGET_PRELINKER_MAP) \ 
--locals-only \ 
--quiet \ 
$/build/tools/apriori” 
參考文檔: 
動態庫優化——Prelink(預連接)技術 
http://www.eefocus.com/article/09-04/71629s.html 
=============== 
LOCAL_ARM_MODE := arm 
目前Android大部分都是基於Arm處理器的,Arm指令用兩種模式Thumb(每條指令兩個字節)和arm指令(每條指令四個字節) 
LOCAL_CFLAGS += -O3 -fstrict-aliasing -fprefetch-loop-arrays 
通過設定編譯器操作,優化級別,-O0表示沒有優化,-O1爲缺省值,-O3優化級別最高 
LOCAL_CFLAGS += -W -Wall 
LOCAL_CFLAGS += -fPIC -DPIC 
LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter 
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE -DSH_HISTORY 
LOCAL_CFLAGS += -DUSEOVERLAY2 
根據條件選擇相應的編譯參數 
ifeq ($(TARGET_ARCH),arm) 
LOCAL_CFLAGS += -DANDROID_GADGET=1 
LOCAL_CFLAGS := $(PV_CFLAGS) 
endif 
ifeq ($(TARGET_BUILD_TYPE),release) 
LOCAL_CFLAGS += -O2 
endif 
LOCAL_LDLIBS := -lpthread 
LOCAL_LDLIBS += -ldl 
ifdef USE_MARVELL_MVED 
LOCAL_WHOLE_STATIC_LIBRARIES += lib_il_mpeg4aspdecmved_wmmx2lnx lib_il_h264decmved_wmmx2lnx 
LOCAL_SHARED_LIBRARIES += libMrvlMVED 
else 
LOCAL_WHOLE_STATIC_LIBRARIES += lib_il_h264dec_wmmx2lnx lib_il_mpeg4aspdec_wmmx2lnx 
endif 
==================== 
其他一些變量和腳本: 
HOST_JNILIB_SUFFIX 
LOCAL_MODULE_SUFFIX 
LOCAL_MODULE_SUFFIX := $(HOST_JNILIB_SUFFIX) 
HOST_GLOBAL_LDFLAGS 
TARGET_GLOBAL_LDFLAGS 
PRIVATE_LDFLAGS 
LOCAL_LDLIBS 
LOCAL_C_INCLUDES 
LOCAL_STATIC_LIBRARIES 
LOCAL_STATIC_LIBRARIES += codecJPDec_WMMX2LNX miscGen_WMMX2LNX 
LOCAL_SHARED_LIBRARIES 
LOCAL_SHARED_LIBRARIES += libMrvlIPP 
LOCAL_SHARED_LIBRARIES += $(common_SHARED_LIBRARIES) 
LOCAL_SHARED_LIBRARIES += libMrvlIPP 
LOCAL_SHARED_LIBRARIES += libdl 
ifeq ($(TARGET_PRODUCT),littleton) 
LOCAL_C_INCLUDES += vendor/marvell/littleton/m2d \ 
LOCAL_SHARED_LIBRARIES += libOmxCore 
endif 
vendor/marvell/littleton/littleton.mk:27:PRODUCT_NAME := littleton 
vendor/marvell/littleton/littleton.mk:28:PRODUCT_DEVICE := littleton 
vendor/marvell/littleton/AndroidProducts.mk:13: $(LOCAL_DIR)/littleton.mk 
vendor/sample/products/sample_addon.mk:40:PRODUCT_NAME := sample_addon 
vendor/htc/dream-open/htc_dream.mk:6:PRODUCT_NAME := htc_dream 
./vendor/htc/dream-open/htc_dream.mk:7:PRODUCT_DEVICE := dream-open 
./vendor/htc/dream-open/AndroidProducts.mk:3: $(LOCAL_DIR)/htc_dream.mk 
build/target/product/generic.mk:26:PRODUCT_NAME := generic 
build/target/product/generic_with_google.mk:20:PRODUCT_NAME := generic_with_google 
build/target/product/min_dev.mk:6:PRODUCT_NAME := min_dev 
build/target/product/core.mk:2:PRODUCT_NAME := 
build/target/product/sim.mk:7:PRODUCT_NAME := sim 
build/target/product/sdk.mk:37:PRODUCT_NAME := sdk 
build/tools/buildinfo.sh:20:echo "ro.product.name=$PRODUCT_NAME" 
lunch sample_addon-eng
發佈了24 篇原創文章 · 獲贊 2 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章