1.File
File:java.io.File:代表一個實際的檔案或目錄。
常用構造方法File file = new File("path");
其它構造方法:
- File(String parent, String child):建立一個新的 File 例項,該例項的存放路徑是由 parent 和 child 拼接而成的。
- File(File parent, String child):建立一個新的 File 例項。 parent 代表目錄, child 代表檔名,因此該例項的存放路徑是 parent 目錄中的 child 檔案。
- File(URI uri):建立一個新的 File 例項,該例項的存放路徑是由 URI 型別的引數指定的。
構造File時,路徑需要符合作業系統的命名規則。
路徑分隔符File.pathSeperator:在windows中是“;”,在Linux中是":"
路徑分隔符File.pathSeperatorChar:在windows中是’;‘,在Linux中是':'
層次路徑分隔符File.seperator:在windows中是"\",在Linux中是"/"
層次路徑分隔符File.seperatorChar:在windows中是’\‘,在Linux中是’/’
File常用方法:
File.listRoots():列出根目錄
file.exists():檔案是否存在
fie.isDirectory():檔案是否是目錄
String[] list():返回一個字串陣列,這些字串代表此抽象路徑名錶示的目錄中的檔案和目錄。
String[] list(FilenameFilter filter):返回一個字串陣列,這些字串代表此抽象路徑名錶示的目錄中,滿足過濾器 filter 要求的檔案和目錄。
File[] listFiles():返回一個 File 物件陣列,表示此當前 File 物件中的檔案和目錄。
File[] listFiles(FilenameFilter filter):返回一個 File 物件陣列,表示當前 File 物件中滿足過濾器 filter 要求的檔案和目錄。
2.IO流
抽象輸入位元組流介面:InputStream 抽象輸出位元組流介面:OutputStream
常見的輸入流:new Scanner(System.in) 常見的輸出流:System.out.print();
按照傳輸的單位分為:位元組流和字元流。
位元組流通常用來處理二進位制檔案,如音樂、圖片檔案等,並且由於位元組是任何資料都支援的資料型別,因此位元組流實際可以處理任意型別的資料。而對於字元流,因為 Java 採用 Unicode 編碼,Java 字元流處理的即 Unicode 字元,所以在操作文字、國際化等方面,字元流具有優勢。
- FileInputStream:把一個檔案作為輸入源,從本地檔案系統中讀取資料位元組,實現對檔案的讀取操作。
- ByteArrayInputStream:把記憶體中的一個緩衝區作為輸入源,從記憶體陣列中讀取資料位元組。
- ObjectInputStream:對以前使用 ObjectOutputStream 寫入的基本資料和物件進行反序列化,用於恢復那些以前序列化的物件,注意這個物件所屬的類必須實現 Serializable 介面。
- PipedInputStream:實現了管道的概念,從執行緒管道中讀取資料位元組。主要線上程中使用,用於兩個執行緒間的通訊。
- SequenceInputStream:其他輸入流的邏輯串聯。它從輸入流的有序集合開始,並從第一個輸入流開始讀取,直至到達檔案末尾,接著從第二個輸入流讀取,依次類推。
- System.in:從使用者控制檯讀取資料位元組,在 System 類中,in 是 InputStream 型別的靜態成員變數。
InputStream常見方法:
int read():從輸入流中讀取資料的下一位元組,返回 0 ~ 255 範圍內的整型位元組值;如果輸入流中已無新的資料,則返回 -1。
int read(byte[] b):從輸入流中讀取一定數量的位元組,並將其儲存在位元組陣列 b 中,以整數形式返回實際讀取的位元組數(要麼是位元組陣列的長度,要麼小於位元組陣列的長度)。
int read(byte[] b, int off, int len):將輸入流中最多 len 個資料位元組讀入位元組陣列 b 中,以整數形式返回實際讀取的位元組數,off 指陣列 b 中將寫入資料的初始偏移量。
void close():關閉此輸入流,並釋放與該流關聯的所有系統資源。
int available():返回可以不受阻塞地從此輸入流讀取(或跳過)的估計位元組數。
void mark(int readlimit):在此輸入流中標記當前的位置。
void reset():將此輸入流重新定位到上次 mark 的位置。
boolean markSupported():判斷此輸入流是否支援 mark() 和 reset() 方法。
long skip(long n):跳過並丟棄此輸入流中資料的 n 位元組。
字元的輸入輸出流:
抽象字元輸入流:Reader 抽象字元輸出流:Writer
- FileReader :與 FileInputStream 對應,從檔案系統中讀取字元序列。
- CharArrayReader :與 ByteArrayInputStream 對應,從字元陣列中讀取資料。
- PipedReader :與 PipedInputStream 對應,從執行緒管道中讀取字元序列。
- StringReader :從字串中讀取字元序列。
字元輸出流的常用方法:
Writer append(char c):將指定字元 c 追加到此 Writer,此處是追加,不是覆蓋。
Writer append(CharSequence csq):將指定字元序列 csq 新增到此 Writer。
Writer append(CharSequence csq, int start, int end):將指定字元序列 csq 的子序列,追加到此 Writer。
void write(char[] cbuf):寫入字元陣列 cbuf。
void write (char[] cbuf, int off, int len):寫入字元陣列 cbuf 的某一部分。
void write(int c):寫入單個字元 c。
void write(String str):寫入字串 str。
void write(String str, int off, int len):寫入字串 str 的某一部分。
void close():關閉當前流。
位元組流、字元流都是無緩衝的輸入、輸出流,每次的讀、寫操作都會交給作業系統來處理。對系統的效能造成很大的影響,因為每次操作都可能引發磁碟硬體的讀、寫或網路的訪問,這些磁碟硬體讀、寫和網路訪問會佔用大量系統資源,影響效率。
3.裝飾器模式
通過方法,將物件進行包裝。
比如FileOutputStream放在緩衝位元組流BufferedOutputStream的構造方法中時,就變成了BufferedOutputStream。
再把BufferedOutputStream放在DataOutputStream的構造方法中,就變成了DataOutputStream。
雖然外觀都是OutputStream,但是功能得到了增強,提供了更加豐富的API。
4.Buffered流
緩衝流的目的是讓原位元組流、字元流新增緩衝的功能。
- BufferedInputStream
- BufferedOutputStream
- BufferedReader
- BufferedWriter
5.位元組流轉換為字元流:
使用InputStreamReader將位元組流轉換成InputStreamReader物件,再通過字元流的建構函式轉換成字元流。
Java沒有提供位元組流轉換成字元流的方式,因為位元組流是一個通用的流,而字元流只能傳輸文字型別的資源,但是傳輸效率較快。
6.Data流
DataStream允許流直接操作基本資料型別和字串。常用的方法有
dos.writeUTF();
dos.writeInt();
dis.readUTF();
dis.readInt();
注意讀取順序要和寫入順序一致。
public static void main(String[] args) { try { DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(new File("D:\\ideaproject\\Java02\\data.txt")))); dos.writeUTF("this"); dos.writeUTF("is"); dos.writeInt(4); dos.writeUTF("leellamarz"); dos.close(); DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(new File("D:\\ideaproject\\Java02\\data.txt")))); String a = dis.readUTF(); String b = dis.readUTF(); int d = dis.readInt(); String c = dis.readUTF(); System.out.println(a+" "+b+" "+d+" "+c); dis.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
7.XML
XML是可擴充標記語言,可以用來儲存資料、系統配置、資料交換。
XML的標籤可以自定義。
XML 文件總是以 XML 宣告開始,即告知處理程式,本文件是一個 XML 文件。在 XML 宣告中,通常包括版本、編碼等資訊,以 <?
開始,以 ?>
結尾。
<?xml version = "1.0" encoding="UTF-8"?>
XML 文件由元素組成,一個元素由一對標籤來定義,包括開始和結束標籤,以及其中的內容。元素之間可以巢狀(但不能交叉),也就是說元素的內容裡還可以包含元素。
標籤可以有屬性(屬性值要加引號)。屬性是對標籤的進一步描述和說明,一個標籤可以有多個屬性,每個屬性都有自己的名字和值,屬性是標籤的一部分。
8.解析XML
解析XML的技術主要有:
- DOM 即org.w3c.dom,W3C 推薦的用於使用 DOM 解析 XML 文件的介面
- SAX 即org.xml.sax,用 SAX 解析 XML 文件的介面
DOM 把一個 XML 文件對映成一個分層物件模型,而這個層次的結構,是一棵根據 XML 文件生成的節點樹。DOM 在對 XML 文件進行分析之後,不管這個文件有多簡單或多複雜,其中的資訊都會被轉化成一棵物件節點樹。在這棵節點樹中,有一個根節點,其他所有的節點都是根節點的子節點。節點樹生成之後,就可以通過 DOM 介面訪問、修改、新增、刪除樹中的節點或內容了。
DOM解析過程:
- 通過getInstance()建立DocumentBuilderFactory,即解析器工廠
- 通過build()建立DocumentBuilder
- 解析檔案得到Document物件
- 通過NodeList,開始解析結點(標籤)
9.Node常用方法
NodeList getChildNodes():返回此節點的所有子節點的 NodeList。
Node getFirstChild():返回此節點的第一個子節點。
Node getLastChild():返回此節點的最後一個子節點。
Node getNextSibling():返回此節點之後的節點。
Node getPreviousSibling():返回此節點之前的節點。
Document getOwnerDocument():返回與此節點相關的 Document 物件。
Node getParentNode():返回此節點的父節點。
short getNodeType():返回此節點的型別。
String getNodeName():根據此節點型別,返回節點名稱。
String getNodeValue():根據此節點型別,返回節點值。
String getTextContent():返回此節點的文字內容。
void setNodeValue(String nodeValue):根據此節點型別,設定節點值。
void setTextContent(String textContent):設定此節點的文字內容。
Node appendChild(Node newChild):將節點 newChild 新增到此節點的子節點列表的末尾。
Node insertBefore(Node newChild,Node refChild):在現有子節點 refChild 之前插入節點 newChild。
Node removeChild(Node oldChild):從子節點列表中移除 oldChild 所指示的子節點,並將其返回。
Node replaceChild(Node newChild, oldChild):將子節點列表中的子節點 oldChild 替換為 newChild,並返回 oldChild 節點。
10.Document常用方法
Element getDocumentElement():返回代表這個 DOM 樹根節點的 Element 物件。
NodeList getElementsByTagName(String tagname):按文件順序返回包含在文件中且具有給定標記名稱的所有 Element 的 NodeList。
NodeList常用方法:
int getLength():返回有序集合中的節點數。
Node item(int index):返回有序集合中的第 index 個項。
11.SAX解析
SAX是事件驅動的。通過繼承DefaultHandler類,重寫五個關鍵方法實現解析。
startDocument():開始文件的標誌
endDocument():結束文件的標誌
startElement(String uri, String localName, String qName, Attributes attributes):通過比較localName,找到指定的元素,開啟元素
endElement(String uri, String localName, String qName):通過比較localName,找到指定的元素,結束元素
characters(char[] ch, int start, int length):解析每個元素時呼叫的方法
@Override public void startDocument() throws SAXException { System.out.println("books2文件開始解析"); } @Override public void endDocument() throws SAXException { System.out.println("books2文件結束解析"); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.equals("book")) { for(int i=0;i<attributes.getLength();i++){ System.out.println("編號:"+attributes.getValue(i)); } } this.tagName = qName; } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if("book".equals(localName)){} this.tagName = null; } @Override public void characters(char[] ch, int start, int length) throws SAXException { if (this.tagName != null) { String data = new String(ch, start, length); if (this.tagName.equals("bookname")) { System.out.println("書名:"+data); } if (this.tagName.equals("bookauthor")) { System.out.println("作者:"+data); } if (this.tagName.equals("bookprice")) { System.out.println("價格:"+data); } } }
12.練習
如果子類異常塊放在父類異常塊後面,就會報編譯錯誤。
try { int[] a = {1,2,3}; System.out.print(a[3]); System.out.print(1); } catch(Exception e) { System.out.print(2); System.exit(0);//2 } finally { System.out.print(3); }
不同於return,System.exit(0)的優先順序高於finally,在前面遇到會直接退出程式。
異常向外丟擲,再被外部trycatch接受,會造成死迴圈
ArrayList<String> a = new ArrayList<String>(); a.add(true); a.add(123); a.add("abc"); System.out.print(a); //執行後,控制檯輸出為?編譯錯誤 //集合定義時加了泛型後,就不能新增不匹配泛型的元素。
List a = new ArrayList(); a.add(1); a.add(2); a.add(3); a.remove(1); System.out.print(a); //執行後,控制檯輸出為? 1 3 //ArrayList 有 2 個刪除方法:a.remove(Object o); 和 a.remove(int index); 那麼這裡的 1 到底是匹配 Object 還是 int 型別呢?我們考慮一下這兩個方法的來歷就行了。 //a.remove(Object o); 是父介面的方法,a.remove(int index); 是子類重寫的方法,所以這裡應該是呼叫子類重寫的方法。
Set ts = new TreeSet(); ts.add("zs"); ts.add("ls"); ts.add("ww"); System.out.print(ts); //執行後,控制檯輸出為? //TreeSet 對於字串來說預設按照字典升序進行排序,所以答案為:[ls, ww, zs]
//假設檔案 c:/a.txt 的內容為 abc //以下程式碼 try { File f = new File("c:/a.txt"); System.out.print(f.length()); OutputStream out = new FileOutputStream(f); System.out.print(f.length()); out.write(97); System.out.print(f.length()); out.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } //執行後,控制檯輸出為?301
File 物件 new 出來後,f.length() 返回值為 3。
FileOutputStream 物件 new 出來後,由於預設方法是覆蓋已經存在的檔案,所以f.length() 返回值為 0,如果想不覆蓋,應該使用new FileOutputStream(f,false);。
out.write(97) 寫入字母 a 後,f.lenght() 返回值為 1。
if(node2 instanceof Element){ String string = node2.getNodeName(); String ste = node2.getTextContent(); System.out.println(string+" "+ste); }
出現這種問題的原因主要是使用org.w3c.dom.Node的進行解析的,它會將你的回車也作為一個節點。在你的程式碼中你列印str.getLenth();得到的數值肯定比你寫的節點要多。
如果:node2 instanceof Text,則輸出:#text
如果:node2 instanceof Element,則輸出:標籤名
或者將檔案中多餘的空格和回車都去掉。