6.IO流
6.1 File
系統(tǒng)中我們一眼看到的就是文件或者文件夾
本質(zhì)是一個路徑(字符串);用字符串來表示這個路徑不符合面向?qū)ο?/p>
File類對路徑的字符串進(jìn)行面向?qū)ο蟮姆庋b,是文件和文件夾路徑的抽象表現(xiàn)形式
基本操作:
-
構(gòu)造方法
File(String pathname) 將給定的路徑名字符串轉(zhuǎn)為抽象路徑名來創(chuàng)建一個File實(shí)例 例子: new File("D:java/testDoc/test.java") //文件路徑 new File("D:java/testDoc") //文件夾路徑 File(String parent, String child) 根據(jù)父路徑字符串和子路徑字符串創(chuàng)建一個File實(shí) 例子:new File("D:java","/testDoc/test.java") //文件 例子:new File("D:java","/testDoc") //文件夾
-
創(chuàng)建
-
創(chuàng)建文件夾
mkdir():創(chuàng)建文件夾 mkdirs():?創(chuàng)建多級文件夾
-
創(chuàng)建文件
createNewFile():創(chuàng)建文件
-
重命名
renameTo():給文件或文件夾重命名
-
-
判斷
exists():判斷此路徑是否存在 isFile():判斷是否文件 isDirectory():判斷是否文件夾
-
獲取
getAbsolutePath():獲取絕對路徑,包括根路徑 getName():獲取相對路徑(文件名或者文件夾名).不包括根路徑 length():獲取文件的大小,單位是字節(jié)
-
刪除
delete():刪除文件 deleteOnExit():在程序退出的時(shí)候刪除文件
-
示例代碼:
//創(chuàng)建File實(shí)例對象,路徑的抽象表現(xiàn) File file = new File("D:java/testDoc/test.java"); // File file = new File("D:java/testDoc"); // File file = new File("D:java","testDoc/test.java"); //判斷路徑是否存在 if (!file.exists()){ //判斷是否是文件路徑 if (file.isFile()){ //創(chuàng)建文件 file.createNewFile(); } //判斷是否是文件夾路徑 if (file.isDirectory()){ //創(chuàng)建文件夾 file.mkdir(); } } //獲取絕對路徑 System.out.println(file.getAbsoluteFile()); // 輸出 /D:java/testDoc/test.java //獲取相對路徑(文件名或者文件夾名) System.out.println(file.getName()); // 輸出test.java
File類的高級獲取
- 方法:
listFiles():返回一個File數(shù)組,包括了路徑名下的的所有文件和文件夾路徑名
listRoots():此方法是靜態(tài)的,返回路徑名下的所有根路徑
listFiles(FileFilter filter):返回File數(shù)組,數(shù)組是有經(jīng)過過濾器FileFilter篩選的
FileFilter 重寫的方法: accept(File pathname) 返回true表示需包含在數(shù)組內(nèi),不要去掉
-
示例代碼1:
if (file != null && file.isDirectory()) { //打印文件夾 System.out.println(file); //列出所有的文件和文件夾路徑 File[] files = file.listFiles(); for (File f : files) { //遞歸調(diào)用,找出所有的文件 文件夾 testFileSearch(f); } } else { //打印文件 System.out.println(file); }
-
示例代碼2
if (file != null && file.isDirectory()) { File[] files = file.listFiles(new FileFilter() { @Override public boolean accept(File file) { //.class結(jié)尾的需要保留,不要去掉 return file.getName().endsWith(".class"); } }); }
6.2 IO流基類
字節(jié)輸入流 InputStream
字節(jié)輸出流 OutputStream
字符輸入流 Reader
字符輸出流 Writer
特點(diǎn):
-
四大基類都是抽象類,核心功能一句話總結(jié):讀進(jìn)來,寫出去
輸出流:將數(shù)據(jù)寫到目標(biāo)中去
輸入流:從源中讀取數(shù)據(jù)
所有的流都是資源對象谁榜,最后使用完都必須關(guān)閉資源
字節(jié)流比較通用
-
IO流的操作模板
1):定義源或目標(biāo) 源:輸入流 目標(biāo):輸出流 2):根據(jù)源和目標(biāo)創(chuàng)建流對象 3):進(jìn)行讀/寫操作 4):關(guān)閉資源
6.2.1 字節(jié)流
字節(jié)輸入流 InputStream
字節(jié)輸出流 OutputStream
字節(jié)文件流
1-1.FileOutputStream
將數(shù)據(jù)寫到目標(biāo)文件中
-
構(gòu)造方法
FileOutputStream(File file) 創(chuàng)建向指定File對象的目標(biāo)文件中寫入數(shù)據(jù)的文件輸出流 FileOutputStream(String name) 創(chuàng)建向指定名稱的目標(biāo)文件中寫入數(shù)據(jù)的文件輸出流 FileOutputStream(String name, boolean append) append 是否在源數(shù)據(jù)中追加
-
常用方法
write(int b) //將指定數(shù)量的字節(jié)寫到輸入流 write(byte[] b,int off, int len ) 將指定的byte數(shù)組從off索引開始的len個字節(jié)寫到輸出流
-
分析流對象的創(chuàng)建
1.創(chuàng)建了輸出流對象 2.通知系統(tǒng)去檢查目標(biāo)文件,如果不存在則創(chuàng)建出來 3.將這個輸出流對象與硬盤上的文件關(guān)聯(lián)起來
-
示例代碼:
String dest = "d:/java/test.txt"; //輸出的目標(biāo)文件路徑 try { //創(chuàng)建流對象,如果文件不存在,則會自動創(chuàng)建文件 FileOutputStream fo = new FileOutputStream(dest); byte[] bytes = "hello".getBytes();//需要寫到流的數(shù)據(jù) fo.write(bytes,2,3); fo.close();//關(guān)閉流,釋放資源,等待GC回收 } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
1-2.FileInputStream
從源文件讀取數(shù)據(jù)
-
構(gòu)造方法
FileInputStream(String name) FileInputStream(File file) 創(chuàng)建從源文件中讀取數(shù)據(jù)的輸入流對象
-
常用方法
read() 從輸入流中讀取數(shù)據(jù)的下一個字節(jié), 返回值是讀取到的字節(jié),如果為-1表示已讀完 read(byte[] b) 從輸入流中讀取數(shù)據(jù)的一定數(shù)量字節(jié),并存儲到緩沖數(shù)組b中. 返回值是讀取的字節(jié)個數(shù),如果為-1表示已讀完
-
示例代碼:
//源 String path = "d:/java/in.txt"; //根據(jù)源創(chuàng)建輸入流對象 try { FileInputStream fi = new FileInputStream(path); //定義一個緩沖數(shù)組 byte[] bytes = new byte[1024 * 1024]; fi.read(bytes); int len;//記錄讀取了多少個字節(jié) while ((len = fi.read(bytes)) != -1) { //不等于-1 表示還有數(shù)據(jù) System.out.println(new String(bytes, 0, len)); } fi.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
緩沖流
-
特點(diǎn)
緩沖字節(jié)流和普通字節(jié)流在使用上沒有區(qū)別 ,在效率上緩沖流效率更高
-
為什么會比較效率?
緩沖流對象底層自帶一個8k的緩沖區(qū),這個緩沖區(qū)跟我們輸入流的自定義的緩沖數(shù)組沒有關(guān)系
緩沖流對象的緩沖區(qū)指的是管道的粗細(xì),而自定義的緩沖數(shù)組指的的是讀取到的數(shù)據(jù)儲存的地方
緩沖流將管道加粗了,從而使輸入和輸出更加效率
字節(jié)緩沖流
2-1.BufferedInputStream
-
構(gòu)造方法
BufferedInputStream(InputStream in)
-
示例代碼
FileInputStream in = new FileInputStream("d:/java/test.java"); BufferedInputStream bufin = new BufferedInputStream(in);
2-2.BufferedOutputStream
-
構(gòu)造方法
BufferedOutputStream(OutputStream out)
-
示例代碼
FileOutputStream out = new FileOutputStream("d:/java/test.java"); BufferedOutputStream bufOut= new BufferedOutputStream(out);
對象流
-
作用
把內(nèi)存中的對象輸出到文件中或者把文件中保存的對象輸入到內(nèi)存
-
為什么保存到文件中?
目的是為了進(jìn)程之間的數(shù)據(jù)做交流
-
序列化和反序列化
序列化:內(nèi)存中的對象寫出到文件
反序列化:將文件中的對象讀進(jìn)內(nèi)存
-
序列化對象
保存的對象需要經(jīng)過序列化,開啟序列化可以通過實(shí)現(xiàn)Serializable接口
實(shí)現(xiàn)Serializable接口需要在對象中顯示聲明序列化ID;不顯式聲明時(shí),會根據(jù)類上的信息產(chǎn)生不同的序列化ID,由于編譯器的不同,可能導(dǎo)致反序列化出現(xiàn)意外
3-1.ObjectOutputStream
ObjectOutputStream extends OutputStream implements ObjectOutput, ObjectStreamConstants
序列化:把內(nèi)存中的對象保存到硬盤中
-
構(gòu)造方法
ObjectOutputStream(OutputStream out) 創(chuàng)建寫入指定OutputStream的對象
-
常用方法
void writeObject(Object obj) 將對象寫到流中
-
示例代碼
public class ShareData implements Serializable { private static final long serialVersionUID = -1190188205817401171L; } ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("data")); ShareData data = new ShareData(); out.writeObject(data); out.close();
3-2.ObjectInputStream
ObjectInputStream extends InputStream implements ObjectInput, ObjectStreamConstants
反序列化:將文件中的對象讀取到內(nèi)存中
一個程序去讀取另一個程序序列化的數(shù)據(jù),達(dá)到進(jìn)程通信
-
構(gòu)造方法
ObjectInputStream(InputStream in)
-
常用方法
readObject()
-
示例代碼
ObjectInputStream in = new ObjectInputStream(new FileInputStream("data")); Object object = in.readObject(); in.close();
字節(jié)數(shù)組流
4-1.ByteArrayOutputStream
ByteArrayOutputStream extends OutputStream
-
特點(diǎn)
會將數(shù)據(jù)寫入到底層緩沖區(qū)的byte數(shù)組,緩沖區(qū)會隨著數(shù)據(jù)的不斷寫入而自動增長
-
使用場景:
在需要接收大量是數(shù)據(jù)時(shí),有些數(shù)據(jù)不適合一次性全部接收,我們可以使用每次收集1小部分的形式,拿到零散的數(shù)據(jù),再將零散的數(shù)據(jù)統(tǒng)一收集起來,最后統(tǒng)一使用,此時(shí)就要用到這個ByteArrayOutputStream
-
構(gòu)造方法
ByteArrayOutputStream()
-
常用方法
byte[] toByteArray() //將緩沖數(shù)組的數(shù)據(jù)放到一個新的數(shù)組 String toString() 用默認(rèn)字符集將緩沖區(qū)數(shù)據(jù)解碼成字符串 String toString(String charsetName) 用指定字符集將緩沖區(qū)數(shù)據(jù)解碼成字符串 void write(byte[] b, int off, int len) 將數(shù)組b寫到流中
-
示例代碼
ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); //模擬每次有一部分?jǐn)?shù)據(jù)過來 //這個方法就是將零散的數(shù)據(jù)先暫時(shí)保存起來 byteOut.write(new byte[]{'a', 'b', 'c'}); byteOut.write(new byte[]{'d', 'e', 'e'}); byteOut.write(new byte[]{100, 127, 32}); byte[] bytes = byteOut.toByteArray();//將保存的零散數(shù)據(jù)使用起來 System.out.println(new String(bytes)); System.out.println(byteOut.toString());//解碼流的數(shù)據(jù)為字符串
4-2.ByteArrayIntputStream
ByteArrayInputStream extends InputStream
-
特點(diǎn)
包含一個內(nèi)部緩沖區(qū),該緩沖區(qū)包含從流中讀取的字節(jié)
關(guān)閉 ByteArrayIntputStream無效,其方法在關(guān)閉后仍可被調(diào)用,而不會產(chǎn)生IOException
-
構(gòu)造方法
ByteArrayInputStream(byte[] buf) 創(chuàng)建一個流對象,使用buf作為其緩沖區(qū)數(shù)組
-
示例代碼
byte[] bs = new byte[]{9,98,100};//把字節(jié)數(shù)組轉(zhuǎn)成流對象 ByteArrayInputStream byteIn = new ByteArrayInputStream(bs); byte[] buf = new byte[1024]; int len; while ((len = byteIn.read(buf)) != -1){ System.out.println(new String(buf,0,len)); }
6.2.2 字符流
字符輸入流 Reader
字符輸出流 Writer
-
為什么使用字符流
使用字節(jié)流讀取文件可能會出現(xiàn)亂碼的情況,因?yàn)樽止?jié)流是一次只讀取一個字節(jié),而有些數(shù)據(jù)不是一個字節(jié)構(gòu)成,如漢字占兩個字節(jié)或3個字節(jié),在解析的時(shí)候不知道用幾個字節(jié)去解析,因此容易出現(xiàn)亂碼.
-
字符流工作過程
字符流底層有一個1kb大小的緩沖區(qū),讀寫都是跟緩沖區(qū)有關(guān)的
字符輸入流的緩沖區(qū)的作用:用于讀取數(shù)據(jù)后解析數(shù)據(jù),如果解析成功就會存入緩沖數(shù)組中;如果解析失敗,則會再讀一個數(shù)據(jù)一起解析;如果要解析的字節(jié)在編碼表中找不到對應(yīng)的就會轉(zhuǎn)成問號!
字符輸出流的緩沖區(qū)作用: 先寫入數(shù)據(jù)到緩沖區(qū),然后調(diào)用flush()方法將數(shù)據(jù)從緩沖數(shù)組中寫到文件中,或者緩沖數(shù)組滿了也會寫出去
1-1. FileReader
FileReader extends InputStreamReader
擅長從文件讀取字符的類
-
構(gòu)造方法
FileReader(String fileName)
-
常用方法
int read() 每次讀取一個字符 int read(char[] cbuf) 將字符讀入緩沖數(shù)組中
-
示例代碼
String path = "d:/java/test.txt"; try { FileReader fr = new FileReader(path); char[] chrs = new char[3];//讀取多少個字符到緩沖數(shù)組 int len;//記錄讀取了多少個字符 while ((len = fr.read(chrs)) != -1) { String s = new String(chrs, 0, len); System.out.println(s); } fr.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }
1-2.FileWriter
FileWriter extends OutputStreamWriter
擅長寫出字符到文件的類
-
構(gòu)造方法
FileWriter(String fileName)
-
常用方法
void write(String str) 將字符串寫出到文件 flush() 將緩沖的數(shù)據(jù)寫出到文件 ,在關(guān)閉流之前調(diào)用
-
注意事項(xiàng)
字符流底層存在一個緩沖數(shù)組,調(diào)用write方法時(shí),會將數(shù)據(jù)臨時(shí)保存在緩沖數(shù)組中,當(dāng)緩沖數(shù)組存滿后,會自動把數(shù)組中的數(shù)據(jù)真正寫到文件中.我們可以手動調(diào)用flush()方法,刷新緩存區(qū),讓數(shù)據(jù)寫到文件
-
示例代碼
String dest = "d:/java/write.txt"; try { FileWriter fw = new FileWriter(dest); String needData = "hossss"; fw.write(needData); //刷新數(shù)據(jù) fw.flush(); fw.close(); } catch (IOException e) { e.printStackTrace(); }
轉(zhuǎn)換字符流
特點(diǎn):
- 將字節(jié)流轉(zhuǎn)換成字符流
為什么要轉(zhuǎn)換?
字節(jié)流是基本流,一般流對象都設(shè)計(jì)成字節(jié)流,比較通用
有時(shí)流對象并不是我們自己創(chuàng)建的,而是別的地方返回的,而返回的一般是字節(jié)流,如果字節(jié)流用來處理文本數(shù)據(jù)可能會出現(xiàn)亂碼,所以必須將字節(jié)流轉(zhuǎn)成字符流
2-1.InputStreamReader
轉(zhuǎn)換輸入流
-
構(gòu)造方法
InputStreamReader(InputStream in) InputStreamReader(InputStream in, String charsetName) 指定字符集讀取字節(jié)并解碼為字符
-
示例代碼
FileInputStream in = new FileInputStream("d:/java/test.java"); InputStreamReader reader = new InputStreamReader(in, "UTF-8"); char[] chars = new char[1024]; int len; while ((len = reader.read(chars)) != -1){ System.out.println(new String(chars,0,len)); } reader.close();
2-2.OutputStreamWriter
轉(zhuǎn)換輸出流
-
構(gòu)造方法
OutputStreamWriter(OutputStream out) OutputStreamWriter(OutputStream out, String charsetName) 指定字符集將字符編碼成字節(jié)寫到流中
-
示例代碼
FileOutputStream out = new FileOutputStream("d:/java/test.java"); OutputStreamWriter writer = new OutputStreamWriter(out,"UTF-8"); writer.write("你好啊"); writer.close();//轉(zhuǎn)換流的close包含了刷新數(shù)據(jù),關(guān)閉資源操作
字符緩沖流
3-1.BufferedReader
-
構(gòu)造方法
BufferedReader(Reader in)
-
特有方法
String readLine() 讀取一行文本
-
示例代碼
BufferedReader reader =new BufferedReader(new FileReader("d:/java/test2.java")); String data; //記錄讀取到的內(nèi)容 while ((data = reader.readLine()) != null){ System.out.println(data); } reader.close();
3-2.BufferedWriter
-
構(gòu)造方法
BufferedWriter(Writer out)
-
特有方法
void newLine() 寫入一個行分隔符(換行)
-
示例代碼
BufferedWriter writer = new BufferedWriter(new FileWriter("d:/java/test.java")); writer.write("哈哈"); writer.newLine();//換行 writer.write("我是哈哈"); writer.flush(); writer.close();
6.3 文件拷貝
-
字節(jié)流拷貝
字節(jié)流可以讀寫文本文件和二進(jìn)制文件
//需求:將test1.java的內(nèi)容拷貝到test2.java FileInputStream in = new FileInputStream("d:/java/test1.java"); FileOutputStream out = new FileOutputStream("d:/java/test2.java"); byte[] bytes = new byte[1024]; int len; while ((len = in.read(bytes)) != -1) { //將讀取到的數(shù)據(jù)寫出去,邊讀邊寫 out.write(bytes, 0, len); } in.close(); out.close();
-
字符流拷貝
字符流只能拷貝純文本文件,拷貝二進(jìn)制文件肯定是打不開的
拷貝二進(jìn)制文件的問題:
讀取回來的字節(jié)數(shù)據(jù)在轉(zhuǎn)換成字符的過程中,發(fā)現(xiàn)找不到對應(yīng)的字符和它對應(yīng),而轉(zhuǎn)成了?(63)只有一個字節(jié),所以寫出去的就丟失了字節(jié),最終導(dǎo)致拷貝的數(shù)據(jù)變少了
//需求:將test1.java的內(nèi)容拷貝到test2.java FileReader reader = new FileReader("d:/java/test1.java"); FileWriter writer = new FileWriter("d:/java/test2.java"); char[] chars = new char[1024]; int len; while ((len = reader.read(chars)) != -1) { writer.write(chars, 0, len); writer.flush(); } reader.close(); writer.close();
6.4 IO流異常處理
-
異常處理的核心:
所有的編譯時(shí)期異常必須try-catch
保證流對象得到關(guān)閉
-
異常一般處理示例代碼
FileReader reader = null; FileWriter writer = null; try { reader = new FileReader("d:/java/test1.java"); writer = new FileWriter("d:/java/test2.java"); //需求:將test1.java的內(nèi)容拷貝到test2.java char[] chars = new char[1024]; int len; while ((len = reader.read(chars)) != -1) { writer.write(chars, 0, len); writer.flush(); } } catch (Exception e) { e.printStackTrace(); }finally { if (reader != null){ try { reader.close(); } catch (Exception e) { e.printStackTrace(); }finally { if (writer != null){ try { writer.close(); } catch (Exception e) { e.printStackTrace(); } } } } }
從上面的代碼可以看出處理異常的代碼邏輯比IO操作還多,結(jié)構(gòu)嵌套很深
-
異常高級處理
-
try-with-resource
java1.7開始出現(xiàn)的跟資源有關(guān)的
相關(guān)的對象需要實(shí)現(xiàn)AutoCloseable接口,流對象都實(shí)現(xiàn)了此接口
應(yīng)用了此語法的流對象不用關(guān)閉資源,會自動關(guān)閉
這個語法只能在Java7或者更高的版本使用
-
語法
try ( ... 創(chuàng)建AutoCloseable對象的代碼 ... ) { 可能出現(xiàn)異常的代碼 } catch (異常類型 變量名) { }
-
示例代碼
try ( //創(chuàng)建資源對象的代碼放在這里 FileReader reader = new FileReader("d:/java/test1.java"); FileWriter writer = new FileWriter("d:/java/test2.java"); ) { char[] chars = new char[1024]; int len; while ((len = reader.read(chars)) != -1) { writer.write(chars, 0, len); writer.flush(); } //不用關(guān)閉資源 //reader.close(); //writer.close(); } catch (Exception e) { e.printStackTrace(); }
-
6.5 字符的編碼和解碼
-
編碼表
所謂編碼表就是用一個整數(shù)去對應(yīng)一個字符
如: ASCII編碼表字符's' s --> 10 -->0000 1010(二進(jìn)制)
- ASCII
- 是用**一個 8 位的字節(jié)**來表示空格篙耗、標(biāo)點(diǎn)符號、數(shù)字轿腺、大小寫字母或者控制字符的向瓷,其中最高位為 "0"业踢,其他位可以自由組合成 128 個字符的碼表
- **ASCII的漢字是1個字節(jié)**
- IOS-8859-1
是國際標(biāo)準(zhǔn)化組織 ISO 字符編碼標(biāo)準(zhǔn) ISO-8859 的一部分玻淑,它在 ASCII 編碼空置的 0xA0-0xFF 的范圍內(nèi)加入了其他符號字母以供西歐來使用嗽冒,所以也叫 "西歐語言",另外 ISO 的編碼還有其他的一些語言編碼补履,這些都是**單字節(jié) 8 位編碼**添坊。
- GB*
- GB2312 共收錄了七千個字符,由于 GB2312 支持的漢字太少而且不支持繁體中文干像,所以 GBK 對 GB2312 進(jìn)行了擴(kuò)展帅腌,對低字節(jié)不再做大于 127 的規(guī)定驰弄,以支持繁體中文和更多的字符麻汰,GBK 共支持大概 22000 個字符,GB18030 是在 GBK 的基礎(chǔ)上又增加了藏文戚篙、蒙文五鲫、維吾爾文等主要的少數(shù)民族文字。
- **GBK的漢字是2個字節(jié)**
- Unicode
- 一個全球性的編碼方案把所有字母和符號都統(tǒng)一編碼進(jìn)去
- UTF-8以字節(jié)為單位對Unicode進(jìn)行編碼
- **UTF-8的漢字是3個字節(jié)**
-
編碼和解碼
編碼和解碼都必須依靠一個工具作為橋梁,這個工具就是編碼表
-
編碼: 把字符變成字節(jié)(整數(shù))
String類的編碼方法:
byte[] getBytes() 使用平臺默認(rèn)字符集(一般默認(rèn)GBK)將String編碼為byte,并存到byte數(shù)組中 byte[] getBytes(String charsetName) 使用指定字符集將String編碼為byte,并存到byte數(shù)組中
-
解碼: 把字節(jié)(整數(shù))變成字符
String類的解碼方法:
String(byte[] bytes) 使用默認(rèn)字符集將字節(jié)數(shù)組解碼成一個String對象 String(byte[] bytes,String charsetName) 使用指定字符集將字節(jié)數(shù)組解碼成一個String對象
編碼和解碼的字符集必須一致,不然在多個字節(jié)的數(shù)據(jù)中,會出現(xiàn)亂碼
-
示例代碼
String str = "你好啊"; byte[] bytes = str.getBytes();//使用默認(rèn)字符集GBK進(jìn)行編碼 String s = new String(bytes); //使用默認(rèn)字符集GBK進(jìn)行解碼 //編碼和解碼的字符集必須一致 byte[] bUtf = str.getBytes("UTF-8");//使用UTF-8編碼 String sUtf = new String(bUtf,"UTF-8");//使用UTF-8解碼
-
6.6 屬性文件 properties
-
使用背景
一般來說,一些簡單的改動都需要經(jīng)過修改源碼-編譯-運(yùn)行,這樣拓展不強(qiáng),不好維護(hù),靈活性不夠.
我們可以把一些程序中的變量提取出來,放在java代碼的外部,用一個文件保存,這個文件是不需要編譯的,在程序運(yùn)行的時(shí)候再去動態(tài)的讀取這些變量信息.
-
實(shí)際應(yīng)用
在項(xiàng)目中使用屬性文件,文件必須以.properties結(jié)尾,在程序運(yùn)行時(shí)用流去讀取信息,Java中專門去讀取屬性文件并解析的類Properties
-
Properties
Properties extends Hashtable<Object, Object>
Properties 可以從流中加載數(shù)據(jù)或者將數(shù)據(jù)保存在流中,屬性列表中的鍵值都是字符串
-
構(gòu)造方法
Properties()
-
常用方法
void load(Reader reader) 從輸入字符流中讀取屬性鍵值對 String getProperty(String key) 獲得指定鍵的屬性值
-
屬性文件的寫法
src=e:/qq.exe dest=d:/java/test.java
-
示例代碼
Properties properties = new Properties(); FileReader reader =new FileReader("local.properties"); //從流中加載屬性文件 properties.load(reader); //根據(jù)屬性鍵獲得屬性值 String src = properties.getProperty("src"); String dest = properties.getProperty("dest");
6.7 RandomAccessFile
RandomAccessFile implements DataOutput, DataInput, Closeable
支持對隨機(jī)訪問文件的讀取和寫入
-
特征:
可以讀也可以寫
底層是byte[]
包含一個索引叫文件指針
發(fā)送讀或?qū)懖僮骱笪募羔槙耙苿?/p>
-
構(gòu)造方法
RandomAccessFile(String name, String mode) RandomAccessFile(File file, String mode) mode參數(shù): r:表示只支持讀,調(diào)用write方法會拋出異常 rw:表示支持讀寫操作,如文件不存在,則會嘗試創(chuàng)建文件
-
常用方法
long getFilePointer() 獲得當(dāng)前指針?biāo)饕? seek(long offset) 設(shè)置指針位置
-
示例代碼
//創(chuàng)建讀寫的流對象 RandomAccessFile rw = new RandomAccessFile("d:/java/test.txt", "rw"); rw.writeInt(100); rw.writeChar(98); long index = rw.getFilePointer();//獲得指針?biāo)饕? //進(jìn)行讀操作前,需要先將指針回到開始位置,因?yàn)橹斑M(jìn)行寫操作,指針已移動至當(dāng)前寫的位置 rw.seek(0); int a = rw.readInt(); char c = rw.readChar(); rw.close();
-
實(shí)際運(yùn)用
可用于斷點(diǎn)下載
操作步驟:
- 先獲取到要下載的文件的大小
- 使用一個隨機(jī)讀寫文件記錄下載的最新位置
- 使用兩個隨機(jī)讀取文件對要下載的文件進(jìn)行關(guān)聯(lián),一個負(fù)責(zé)讀,一個負(fù)責(zé)寫
- 每次操作都記錄下文件的最新位置并且存入硬盤
- 發(fā)送斷點(diǎn)后,讀取最新的記錄,從最新的歷史記錄繼續(xù)讀取
6.8 正則表達(dá)式
-
使用場景
使用正確的規(guī)則對字符串進(jìn)行相關(guān)操作(匹配/替換/切割)
-
基本字符
x 字符x \\ 反斜線字符
-
字符類(多個中匹配1個)
[abc] a b 或c [^abc] 任何字符,除了a,b或c [a-zA-Z] a到z,或 A到Z,兩頭的字母包含在內(nèi) [a-d[m-p]] a到d,或者m到p:[a-dm-p](并集) [a-z&&[def]] d,e或者f(交集)
-
特殊意義字符(類似關(guān)鍵字)
. 任何字符(與行結(jié)束符可能匹配也可能不匹配) \d 數(shù)字:[0-9] \D 非數(shù)字:[^0-9] \s 空白字符:[\t\n\x0B\f\r] \S 非空白字符:[^\s] \w 單詞字符:[a-zA-Z_0-9] \W 非單詞字符:[^\w]
-
數(shù)量詞
X? X, 一次或者一次也沒有, <=1 X* X, 零次或者多次, >=0 X+ X, 一次或多次, >=1 X{n} X, 恰好n次, =n X{n,} X, 至少n次, >=n X{n,m} X, 至少n次,但不超過m次, >=n <=m
-
字符串正則的常用方法
boolean matches(String regex) 判斷此字符串是否匹配給定的正則表達(dá)式 String[] split(String regex) 根據(jù)給定的正則拆分字符串 String replaceAll(String regex,String replacement) 用指定的字符串替換所有匹配正則的內(nèi)容
-
正則中需要注意的
匹配文本中含有的正則特殊字符: \\d , \\[ , \\{ , \\S 匹配文本的一個反斜杠: \\\\ 匹配文本中的\r\n制表符時(shí): \r\n
-
示例代碼
//1開頭,11位數(shù)字,第二個數(shù)字必須為3 5 7 String tel = "13788888843"; String regex1 = "1[357]\\d{9}"; boolean ma = tel.matches(regex1); System.out.println(ma); String exe = "png-jpg;gif-jpeg"; String regex2 = "[-;]"; String[] split = exe.split(regex2); for (String s : split) { System.out.println(s); } String str = "你個S B"; String regex3 = "S.*B"; System.out.println(str.replaceAll(regex3,"*"));