IO流
輸入輸出流,即Input Output的縮寫
特點:
1)IO流用來處理設備間的數據傳輸。
2)Java對數據的操作是通過流的方式。
3)Java用於操作流的對象都在IO包中。
4)流按操作數據分爲兩種:字節流和字符流。
5)流按流向分爲:輸入流和輸出流。
注意:流只能操作數據,而不能操作文件。
IO流的常用基類
1)字節流的抽象基流:InputStream和OutputStream
2)字符流的抽象基流:Reader和Writer
字符流中的對象融合了編碼表。使用的是默認的編碼,即當前系統的編碼。字符流只用於處理文字數據,而字節流可以處理媒體數據。
字符流的讀寫
<span style="font-family:Arial;font-size:10px;">import java.io.*;
class IODemo{
public static void main(String[] args){
FileWriter fw =null;
FileReader fr = null;
//檢測異常
try{
//創建讀寫對象,並指定目的地
fw = new FileWriter("Demo.txt");
fr = new FileReader("Demo.txt");
//將數據寫入到指定文件中
for(int i=0;i<5;i++){
fw.write("abcde" + i + "\r\n");
fw.flush();
}
//從指定文件中讀取數據
int len = 0;
char[] ch = new char[1024];
while((len=fr.read(ch))!=-1){
System.out.println(new String(ch,0,len));
}
}
//捕獲異常
catch (IOException e){
throw new RuntimeException("讀寫文件失敗");
}
//最終關閉兩個流資源
finally{
if(fw!=null){
try{
fw.close();
}
catch (IOException e){
throw new RuntimeException("關閉流資源失敗。");
}
}
if(fr!=null){
try{
fr.close();
}
catch (IOException e){
throw new RuntimeException("讀取流資源失敗。");
}
}
}
}
}
</span>
文件的拷貝:
原理:其實就是將一個磁盤下的文件數據存儲到另一個磁盤的一個文件中
步驟:
1、在D盤上創建一個文件,用於存儲E盤文件中的數據
2、定義讀取流和E盤文件關聯
3、通過不斷讀寫完成數據存儲
方式一:讀取一個字符,存入一個字符
方式二:先將讀取的數據存入到內存中,再將存入的字符取出寫入D盤
4、關閉流資源:輸入流資源和輸出流資源。
<span style="font-family:Arial;">import java.io.*;
class CopyDemo
{
public static void main(String [] args)
{
FileReader fr = null;
FileWriter fw = null;
try{
fr = new FileReader("E:\\Dmeo.txt");
fw = new FileWriter("D:\\Dmeo.txt");
char[] ch = new char[1024];
int len = 0;
//用ch將讀取的文件和寫入的文件關聯起來
while((len=fr.read(ch))!=-1)
{
fw.write(ch,0,ch.length);
}
}
catch (IOException e){
throw new RuntimeException("文件讀寫失敗");
}
finally{
if(fr!=null){
try{
fr.close();
}
catch (IOException e){
throw new RuntimeException("讀取流資源關閉失敗。");
}
}
if(fw!=null){
try{
fw.close();
}
catch (IOException e){
throw new RuntimeException("寫入流資源關閉失敗。");
}
}
}
}
}</span>
字符流緩衝區:BufferedWriter和BufferedReader
1、緩衝區的出現:提高了流的讀寫效率,所以在緩衝區創建前,要先創建流對象,即先將流對象初始化到構造函數中。
2、緩衝技術原理:此對象中封裝了數組,將數據存入,在一次性取出。
3、寫入流緩衝區BufferedWriter的步驟:
1)創建一個字符寫入流對象
2)爲提高字符寫入流效率,加入緩衝技術,只要將需要被提高效率的流對象作爲參數傳遞給緩衝區的構造函數即可。
注意,只要用到緩衝去就需要刷新。
3)其實關閉緩衝區就是在關閉緩衝區中的流對象。該緩衝區中提供了一個跨平臺的換行符:newLine()。
4、讀取流緩衝區BufferedReader的步驟:
1)創建一個讀取流對象和文件關聯
2)爲提高效率,加入緩衝技術,將字符讀取流對象作爲參數傳遞給緩衝對象的構造函數。
3)該緩衝區提供了一個一次讀一行的方法readLine(),方便與對文本數據的獲取,當返回null時,表示讀到文件末尾。
readLine()方法返回的時只返回回車符之前的數據內容,並不返回回車符,即讀取的內容中不包含任何行終止符(回車符和換行符)。
readLine()方法原理:無論是讀一行,或讀取多個字符,其實最終都是在硬盤上一個一個讀取。所以最終使用的還是read方法一次讀一個。
5、使用緩衝技術拷貝文件,提高效率
<span style="font-family:Arial;">import java.io.*;
class CopyBufferedDemo{
public static void main(String[] args) {
BufferedReader bufr = null;
BufferedWriter bufw = null;
try{
//創建緩衝區,將讀寫流對象作爲參數傳入
bufr = new BufferedReader(new FileReader("D:\\JAVA\\IO\\buffered\\myJava.txt"));
bufw = new BufferedWriter(new FileWriter("D:\\JAVA\\IO\\文件拷貝\\myJava.txt"));
//定義字符串,通過readLine一次讀一行,並存入緩衝區
String line = null;
while((line=bufr.readLine())!=null)
{
//將讀取到緩衝區的數據通過line存入寫入流中
bufw.write(line);
//換行符方法
bufw.newLine();
//將數據刷新到指定文件中
bufw.flush();
}
}
catch (IOException e){
throw new RuntimeException("讀寫文件失敗。");
}
finally{
if(bufr!=null){
try{
bufr.close();
}
catch (IOException e){
throw new RuntimeException("讀取流資源關閉失敗。");
}
}
if(bufw!=null){
try{
bufw.close();
}
catch (IOException e){
throw new RuntimeException("寫入流資源關閉失敗。");
}
}
}
}
}
</span>
6、自定義BufferedReader
原理:可根據BufferedReader類中特有發那個發readLine()的原理,自定義一個類中包含相同功能的方法
步驟:a.初始化自定義的類,加入流對象。
b.定義一個臨時容器,原BufferedReader封裝的是字符數組,此類中可定義一個StringBuilder的容器,最終可實現字符串的提取。
import java.io.*;
//自定義一個功能與BufferedReader相似的類,繼承Reader
class MyBufferedReader extends Reader
{
//定義變量,用於全局
private Reader r;
//構造函數,傳入讀取流對象
MyBufferedReader(Reader r)
{
this.r = r;
}
//複寫readLine放,並將異常拋出,有調用者處理
public String MyReadLine()throws IOException
{
//定義存儲字符串的容器
StringBuilder sb = new StringBuilder();
int ch = 0;
//read()方法遍歷文件,當達末尾時判斷是否爲-1結束循環
while((ch=r.read())!=-1)
{
//判斷是否有行終止符,有則不存入
if(ch=='\r')
continue;
//當讀到結尾,需要將緩衝區中存放的數據變爲字符串返回
if(ch=='\n')
return sb.toString();
else
//將讀取的字符存入容器
sb.append((char)ch);
}
//對於最後一行沒有終止符的情況,需要將讀取到的加入容器中
if(sb.length()!=0)
return sb.toString();
//讀到結尾處,返回null
return null;
}
/*
覆蓋抽象方法:
*/
public int read(char[] cbuf,int off,int len)throws IOException
{
return r.read(cbuf,off,len);
}
//覆蓋close方法
public void close()throws IOException
{
r.close();
}
//創建自定義close方法
public void MyClose()throws IOException
{
r.close();
}
}
//測試
class MyBufferedDemo{
public static void main(String [] args){
MyBufferedReader mbr = null;
//檢測異常
try{
mbr = new MyBufferedReader(new FileReader("Demo.txt"));
String line = null;
//遍歷文件,讀取數據
while ((line=mbr.MyReadLine())!=null){
System.out.println(line);
}
}
//捕獲異常
catch (IOException e){
throw new RuntimeException("讀取文件失敗。");
}
//最終關閉資源
finally{
if(mbr!=null){
try{
mbr.MyClose();
}
catch (IOException e){
throw new RuntimeException("讀取流關閉失敗。");
}
}
}
}
}
7、LineNumberReader
在BufferedReader中有個直接的子類LineNumberReader,其中有特有的方法獲取和設置行號:setLineNumber()和getLineNumber()
示例:
......
try
{
fr = new FileReader("myJava.txt");
lnr = new LineNumberReader(fr);
lnr.setLineNumber(100);
String line = null;
while((line=lnr.readLine())!=null)
{
System.out.println(lnr.getLineNumber() + ": " + line);
}
}
......
裝飾設計模式
1、簡述:當想對已有對象進行功能增強是,可定義類:將已有對象傳入,基於已有對象的功能,並提供加強功能,那麼自定義的該類稱之爲裝飾類。即對原有類進行了優化。
2、特點:裝飾類通常都會通過構造方法接收被裝飾的對象,並基於被裝飾的對i型那個的功能提供更強的功能。
3、裝飾和繼承的區別:
1)裝飾模式比繼承要靈活,通過避免了繼承體系的臃腫,且降低了類與類間的關係。
2)裝飾類因爲增強已有對象,具備的功能和已有的是相同的,只不過提供了更強的功能,所以裝飾類和被裝飾的類通常都是屬於一個體系。
3)從繼承結構轉爲組合結構。
注:在定義類的時候,不要以繼承爲主;可通過裝飾設計模式進行增強類功能。靈活性較強,當裝飾類中的功能不適合,可再使用被裝飾類的功能。
要繼承相應的父類,就需要將所有的抽象方法實現,或交給子類實現。
示例:其中MyBufferedReader的例子就是最好的裝飾設計模式的例子。
字節流和字符流的原理是相似的,只不過字節流可以對媒體進行操作。
由於媒體數據中都是以字節存儲的,所以,字節流對象可直接對媒體進行操作,而不用再進行刷流動作。
拷貝媒體文件:
1、思路:
1)用字節流讀取流對象和媒體文件相關聯
2)用字節寫入流對象,創建一個媒體文件,用於存儲獲取到的媒體文件數據
3)通過循環讀寫,完成數據的存儲
4)關閉資源
import java.io.*;
class CopyPic
{
public static void main(String[] args)
{
//創建流對象引用
FileOutputStream fos = null;
FileInputStream fis = null;
try{
//創建讀寫流對象
fos = new FileOutputStream("2.gif");
fis = new FileInputStream("1.gif");
int len = 0;
//定義字節數組,存儲讀取的字節流
byte[] arr = new byte[1024];
//循環讀寫流,完成數據存儲
while((len=fis.read(arr))!=-1){
fos.write(arr,0,len);
}
}catch (IOException e){
throw new RuntimeException("複製圖片失敗");
}
//最終關閉資源
finally{
if(fos!=null){
try{
fos.close();
}catch (IOException e){
throw new RuntimeException("寫入流關閉失敗");
}
}
if(fos!=null){
try{
fis.close();
}catch (IOException e){
throw new RuntimeException("讀取流關閉失敗");
}
}
}
}
}
字節流緩衝區:
1、讀寫特點:
read():會將字節byte型值提升爲int型值
write():會將int型強轉爲byte型,即保留二進制數的最後八位。
2、原理:將數據拷貝一部分,讀取一部分,循環,直到數據全部讀取完畢。
1)先從數據中抓取固定數組長度的字節,存入定義的數組中,再通過然後再通過read()方法讀取數組中的元素,存入緩衝區
2)循環這個動作,知道最後取出一組數據存入數組,可能數組並未填滿,同樣也取出包含的元素
3)每次取出的時候,都有一個指針在移動,取到數組結尾就自動回到數組頭部,這樣指針在自增
4)取出的時候,數組中的元素再減少,取出一個,就減少一個,直到減到0即數組取完
5)到了文件的結尾處,存入最後一組數據,當取完數組中的元素,就會減少到0,這是全部數據就取完了
自定義字節流緩衝區:
思路:
1、定義一個固定長度的數組
2、定義一個指針和計數器用於讀取數組長度,和計數數組元素是否取完爲0
3、每次將字節數據存入元素要先將數組中的元素取完
注:取出的是byte型,返回的是int型,這裏存在提升的動作,
當byte中的八位全爲1的時候是byte的-1,提升爲int類型,就變爲int型的-1,,read循環條件就結束了
變爲-1的原因是由於在提升時,將byte的八位前都補的是1,即32位的數都是1,即爲int型的-1了。
如何保證提升後的最後八位仍爲1呢?就需要將前24位補0,就可以保留原字節數據不變,又可以避免轉爲int型出現-1的情況;
那麼要如何做呢?
這就需要將提升爲int的數據和前24位爲0,後八位仍爲原字節數據的這個值做與運算。即和255做與運算即可
import java.io.*;
class MyBufferedInputStream
{
private InputStream in;
byte[] by = new byte[1024*4];
private int pos=0,count=0;
//傳入加強的類
MyBufferedInputStream(InputStream in)
{
this.in = in;
}
//自定義讀取方法
public int myRead()throws IOException
{
//先判斷計數器
if(count==0)
{
//計數器爲0則存入數據
count = in.read(by);
//計數器爲負則返回-1,說明結束數據讀取
if(count<0)
return -1;
//每次從數組中讀取數據完,指針要歸零,重新移動指針
pos = 0;
//獲取存入數組的元素,並需要讓指針和計數器相應變化
byte b = by[pos];
count--;
pos++;
//返回讀取的值,需要與運算
return b&255;
}
//計數器大於零時,不需要存數據,只需讀取
else if(count>0)
{
byte b = by[pos];
count--;
pos++;
return b&0xff;
}
//爲-1時即到數據結尾
return -1;
}
public void myClose()throws IOException
{
in.close();
}
}
File類
文件和目錄路徑的抽象表現形式
特點:
1)用來將文件或文件夾封裝成對象
2)方便於對文件與文件夾的屬性信息進行操作
3)File對象可以作爲多數傳遞給流的構造函數
創建File對象:
方式一:File f1 = new File("a.txt"); 將a.txt封裝成對象,可將已有的和未出現的文件或文件夾封裝成對象
方式二:File f2 = new File("c:\\abc","b.txt"); 分別指定文件夾和文件。好處:降低了兩者的關聯程度,
方式三:File d = new File("c:\\abc"); File f3 = new File(d,"c.txt"); 可以傳入父目錄和文件名。
目錄分隔符:調用File.separator,相當於是反斜槓 \
File類常見方法:1、創建:
boolean createNewFile() 在指定位置創建文件,若文件存在,則返回true,與輸出流不同,輸出流對象已建立就創建文件,如果存在,就會被覆蓋
boolean mkdir() 創建文件夾,只能創建一級目錄
boolean mkdirs() 創建多級文件夾。
2、刪除:
boolean delete() 刪除文件。文件存在,返回true;文件不存在或者正在被執行,返回false
void deleteOnExit() 在程序結束時刪除文件
3、判斷:
boolean canExecute() 當前文件是否能被執行
boolean exists() 當前文件是否存在
boolean isFile() 當前文件是否是文件
boolean isDirectory() 當前文件是否是文件夾(目錄);注意:在判斷文件對象是否是文件或目錄是們必須要判斷該文件對象封裝的內容是否存在,通過exists判斷
boolean isHidden() 當前文件是否是隱藏文件
boolean isAbsolute() 測試此抽象路徑名是否爲絕對路徑名
4、獲取信息:
String getName() 獲取文件名
String getPath() 獲取文件的相對路徑(即創建的對象傳入的參數是什麼就獲取到什麼)
String getParent() 獲取父目錄,該方法返回絕對路徑中的父目錄,獲取相對路徑,返回null, 如果相對路徑中有上一級目錄,則返回的即爲該目錄
String getAbsolutePath() 獲取絕對路徑
long length() 返回文件的大小
long lastModified() 返回上次修改的時間
static File[] listRoots() 獲取文件的系統根,即各個盤符
String[] list() 列出當前目錄所有文件,包含隱藏文件。注:調用了list方法的file對象,必須是封裝了一個目錄,且該目錄必須存在。
boolean renameTo(File dest) 對文件重命名爲dest
5、列出及過濾文件:
String[] list() 列出當前目錄所有文件,包含隱藏文件,調用list方法的file對象,必須是封裝了一個目錄,且該目錄必須存在。
File[] list(FilenameFilter filter)
FilenameFilter:文件名過濾器,是一個接口,其中包含一個方法,accept(File dir,String name),返回的是boolean型,對不符合條件的文件過濾掉。
File[] listFiles() 獲取當前文件夾下的文件和文件夾,返回類型爲File數組
ListFiles(FilenameFilter filter) 同list,是對獲取的 當前文件夾下的文件和文件夾的 文件名過濾器。
Properties類
Properties是Hashtable的子類,它具備Map集合的特點,而且它裏面還有存儲的鍵值對,都是字符串,無泛型定義。是集合中和IO技術想結合的集合容器。
特點:
1)可用於鍵值對形式的配置文件
2)在加載時,需要數據有固定的格式,常用的是:鍵=值
特有方法:
1、設置和獲取元素:
Object setProperty(String key,String value) 調用Hashtable的方法put
String getProperty(String key) 指定key搜索value
Set<String> stringPropertyName() 返回屬性列表的鍵集,存入Set集合
void load(InputStream ism) 從輸入字符流中讀取屬性列表
void load(Reader reader) 從輸入字符流中讀取屬性列表
//load方法
public static void loadMthod()throws IOException
{
Properties pop =new Properties();
FileInputStream fis = new FileInputStream("info.txt");
//將流中的數據加載進集合
pop.load(fis);
pop.setProperty("zz","25");
pop.setProperty("ww","24");
FileOutputStream fos = new FileOutputStream("info.txt");
pop.store(fos,"hehe");
pop.list(System.out);
fis.close();
fos.close();
}
//將流中的數據存儲到集合中
public static void method()throws IOException
{
BufferedReader bufr = null;
try
{
Properties pop = new Properties();
bufr = new BufferedReader(new FileReader("info.txt"));
String line = null;
while((line=bufr.readLine())!=null)
{
String[] arr = line.split("=");
pop.setProperty(arr[0],arr[1]);
}
System.out.println(pop);
}
catch (IOException e)
{
throw new RuntimeException("文件操作失敗");
}
finally
{
try
{
if(bufr!=null)
bufr.close();
}
catch (IOException e)
{
throw new RuntimeException("關閉流資源操作失敗");
}
}
}
用於記錄應用程序運行次數
如果使用次數已到,那麼給出註冊提示需要使用計數器,但是在程序結束後,會在內存中消失,此時就需要將其存入到文件中,所以需要一個配置文件,用於記錄該軟件使用的次數。便於閱讀和操作數據
鍵值對數據 ---> Map集合;數據以文件形式存儲 ---> IO技術。 --->Map+IO=Properties
import java.util.*;
import java.io.*;
class RunCount
{
public static void main(String [] args)throws IOException
{
//創建一個Properties對象,集合和io的結合
Properties pop = new Properties();
//創建一個文件對象,用於操作文件
File file = new File("count.ini");
//先判斷文件是否存在,如果不存在就創建一個
if(!file.exists())
file.createNewFile();
//創建讀取流對象,讀取文件中的信息
FileInputStream fis = new FileInputStream(file);
//將流中的文件信息存入集合中
pop.load(fis);
//定義計數器
int count = 0;
//獲取文件中鍵所對應的值
String value = pop.getProperty("time");
//判斷值是否爲null,不爲空就將值傳給計數器
if(value!=null)
{
count = Integer.parseInt(value);
//判斷計數器是否爲到達次數
if(count>=5)
{
System.out.println("次數已到,請註冊");
return ;
}
}
count++;
//將獲得的鍵值設置後存入集合中
pop.setProperty("time",count+"");
FileOutputStream fos = new FileOutputStream(file);
pop.store(fos,"");
fos.close();
fis.close();
}
}
詳細請查看: http://edu.csdn.net