IO作用:解決設(shè)備和設(shè)備之間數(shù)據(jù)傳輸問(wèn)題,內(nèi)存->硬盤,硬盤->內(nèi)存,鍵盤數(shù)據(jù)->內(nèi)存
數(shù)據(jù)存到硬盤上,就做到了永久保存,數(shù)據(jù)一般是以文件形式保存到硬盤上,sun用File描述文件文件夾
File類的構(gòu)造方法
new File(String pathname);
通過(guò)將給定路徑來(lái)創(chuàng)建一個(gè)新File實(shí)例。
new File(String parent, String child); 根據(jù)parent路徑名字符串和child路徑名創(chuàng)建一個(gè)新File實(shí)例。
new File(File parent, String child); 根據(jù)parent抽象路徑名和child路徑名創(chuàng)建一個(gè)新File實(shí)例。
File類的常用方法
關(guān)于路徑
windows下級(jí)用"\"
linux下級(jí)用“/”
File類常用方法
創(chuàng)建:
createNewFile() 在指定位置創(chuàng)建一個(gè)空文件,成功就返回true,如果已存在就不創(chuàng)建然后返回false
mkdir() 在指定位置創(chuàng)建目錄,這只會(huì)創(chuàng)建最后一級(jí)目錄,如果上級(jí)目錄不存在就拋異常。
mkdirs() 在指定位置創(chuàng)建目錄,這會(huì)創(chuàng)建路徑中所有不存在的目錄。
renameTo(File dest) 重命名文件或文件夾,也可以操作非空的文件夾,文件不同時(shí)相當(dāng)于文件的剪切,剪切時(shí)候不能操作非空的文件夾。移動(dòng)/重命名成功則返回true,失敗則返回false。
renameTo()重命名,如果源文件和目標(biāo)文件在同一級(jí)下,作用是重命名,如果目標(biāo)文件和源文件不是在同一文件夾下,作用是剪切,且不能操作文件夾
刪除:
delete() 刪除文件或一個(gè)空文件夾,如果是文件夾且不為空,則不能刪除,成功返回true,失敗返回false。
判斷:
exists() 文件或文件夾是否存在。
isFile() 是否是一個(gè)文件,如果不存在,則始終為false。
isDirectory() 是否是一個(gè)目錄,如果不存在,則始終為false。
isHidden() 是否是一個(gè)隱藏的文件或是否是隱藏的目錄。
isAbsolute() 測(cè)試此抽象路徑名是否為絕對(duì)路徑名。
獲取:
getName() 獲取文件或文件夾的名稱,不包含上級(jí)路徑。
getPath() 返回絕對(duì)路徑
getAbsolutePath() 獲取文件的絕對(duì)路徑,與文件是否存在沒關(guān)系
length() 獲取文件的大?。ㄗ止?jié)數(shù)),如果文件不存在則返回0L,如果是文件夾也返回0L。
getParent() 返回此抽象路徑名父目錄的路徑名字符串;如果此路徑名沒有指定父目錄,則返回null。
lastModified() 獲取最后一次被修改的時(shí)間。
文件夾相關(guān):
staic File[] listRoots() 列出所有的根目錄(Window中就是所有系統(tǒng)的盤符)
list() 返回目錄下的文件或者目錄名,包含隱藏文件。對(duì)于文件這樣操作會(huì)返回null。
list(FilenameFilter filter) 返回指定當(dāng)前目錄中符合過(guò)濾條件的子文件或子目錄。對(duì)于文件這樣操作會(huì)返回null。
listFiles() 返回目錄下的文件或者目錄對(duì)象(File類實(shí)例),包含隱藏文件。對(duì)于文件這樣操作會(huì)返回null。
listFiles(FilenameFilter filter) 返回指定當(dāng)前目錄中符合過(guò)濾條件的子文件或子目錄。對(duì)于文件這樣操作會(huì)返回null。
流的分類
1、按方向
輸入流
輸出流
2、按處理單位
字節(jié)流
就是用于讀取文件的字節(jié)數(shù)據(jù),讀取到的數(shù)據(jù)不會(huì)進(jìn)行任何處理
字符流
讀取到的字節(jié)數(shù)據(jù)會(huì)轉(zhuǎn)成讀得懂的字符數(shù)據(jù),讀取的是以字符為單位 字符流=字節(jié)流+解碼
InputStream抽象類輸入字節(jié)流
FileInputStream讀取文件數(shù)據(jù)的輸入字節(jié)流
使用FileInputStream讀取文件數(shù)據(jù)
//方式1 無(wú)法完整讀取文件數(shù)據(jù)
public static void read1(){
//1、找到目標(biāo)文件
File file = new File("f:\\a.txt");
FileInputStream fileInputStream = null;
try {
//2、建立數(shù)據(jù)的輸入通道
fileInputStream = new FileInputStream(file);
//3、讀取文件數(shù)據(jù)
int content = fileInputStream.read();//返回的是讀取的數(shù)據(jù),沒辭職會(huì)讀取一個(gè)字節(jié)
System.out.println("讀到的內(nèi)容"+(char)content);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//4、關(guān)閉資源(釋放資源文件)
try {
fileInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//方式2 每次可以讀一個(gè)字節(jié)數(shù)據(jù),可以完整讀取數(shù)據(jù)
public static void read2(){
//1、找到目標(biāo)文件
File file = new File("f:\\a.txt");
FileInputStream fileInputStream = null;
try {
//2、建立數(shù)據(jù)的輸入通道
fileInputStream = new FileInputStream(file);
//3、讀取文件數(shù)據(jù)
int content = 0;//用于保存讀到的數(shù)據(jù)
while((content = fileInputStream.read()) != -1){//read()方法如果讀到-1,表示結(jié)束
System.out.print((char)content);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//4、關(guān)閉資源(釋放資源文件)
try {
fileInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
但是方式2的效率又不高,就像你給全班同學(xué)買水,每次買一瓶
//方式3 使用字節(jié)數(shù)組
public static void read3(){
//1、找到目標(biāo)文件
File file = new File("f:\\a.txt");
FileInputStream fileInputStream = null;
try {
//2、建立數(shù)據(jù)的輸入通道
fileInputStream = new FileInputStream(file);
//3、讀取文件數(shù)據(jù)
byte[] buf = new byte[1024];
int length = fileInputStream.read(buf);//先把讀取到的數(shù)據(jù)存儲(chǔ)到字節(jié)數(shù)組中,然后返回本次讀取到的字節(jié)數(shù)
System.out.println("新生成的字符串"+new String(buf,0,length));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//4、關(guān)閉資源(釋放資源文件)
try {
fileInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
如果文件夠大,法三也不好
//方式4 使用循環(huán)配合緩沖讀取數(shù)據(jù)
public static void read4(){
//1、找到目標(biāo)文件
File file = new File("f:\\a.txt");
FileInputStream fileInputStream = null;
try {
//2、建立數(shù)據(jù)的輸入通道
fileInputStream = new FileInputStream(file);
//3、讀取文件數(shù)據(jù)
byte[] buf = new byte[1024];//緩沖字節(jié)數(shù)組越大效率越高,一般都是1024的倍數(shù)
int length = 0;//記錄本次讀字節(jié)個(gè)數(shù)
while((length = fileInputStream.read(buf)) != -1){
System.out.print(new String(buf,0,length));
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//4、關(guān)閉資源(釋放資源文件)
try {
fileInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
如果相比較運(yùn)行效率,可以在程序開始前和程序開始后各定義一個(gè)startTime和endTime,即
//方式4 使用循環(huán)配合緩沖讀取數(shù)據(jù)
public static void read4(){
long startTime = System.currentTimeMillis();
//1、找到目標(biāo)文件
File file = new File("f:\\a.txt");
FileInputStream fileInputStream = null;
try {
//2、建立數(shù)據(jù)的輸入通道
fileInputStream = new FileInputStream(file);
//3、讀取文件數(shù)據(jù)
byte[] buf = new byte[1024];
int length = 0;//記錄本次讀字節(jié)個(gè)數(shù)
while((length = fileInputStream.read(buf)) != -1){
System.out.print(new String(buf,0,length));
}
long endTime = System.currentTimeMillis();
System.out.println(endTime-startTime);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//4、關(guān)閉資源(釋放資源文件)
try {
fileInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
現(xiàn)在來(lái)驗(yàn)證一下為何要釋放資源
當(dāng)打斷點(diǎn)時(shí)刪除文件,會(huì)提示無(wú)法刪除
OutputStream所有輸出字節(jié)流的父類
FileOutputStream向輸出數(shù)據(jù)的輸出字節(jié)流
//方式1 每次只能寫一個(gè)字節(jié)的數(shù)據(jù)
public static void write1(){
//1、找到目標(biāo)文件
File file = new File("f:\\b.txt");
FileOutputStream fileOutputStream = null;
try {
//2、建立數(shù)據(jù)的輸出通道
fileOutputStream = new FileOutputStream(file);
//3、把數(shù)據(jù)寫出
fileOutputStream.write('h');
fileOutputStream.write('l');
fileOutputStream.write('l');
fileOutputStream.write('o');
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
fileOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//方式2
public static void write2(){
//1、找到目標(biāo)文件
File file = new File("f:\\b.txt");
FileOutputStream fileOutputStream = null;
try {
//2、建立數(shù)據(jù)的輸出通道
fileOutputStream = new FileOutputStream(file);
//3、準(zhǔn)備數(shù)據(jù),把數(shù)據(jù)寫出
String str = "hllo";
//4、把字符串轉(zhuǎn)成字節(jié)數(shù)組
byte[] buf = str.getBytes();
fileOutputStream.write(buf);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
fileOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
FileOutputStream要注意的細(xì)節(jié):
1. new FileOutputStream 的時(shí)候,如果目標(biāo)文件不存在,那么會(huì)先創(chuàng)建目標(biāo) 文件,然后再寫入。
2. new FileOutputStream(file) 如果目標(biāo)文件已經(jīng)存在,那么會(huì)先清空 目標(biāo)文件的數(shù)據(jù),然后再寫入新的數(shù)據(jù).
3. 寫入數(shù)據(jù)的時(shí)候如果需要以追加的形式寫入,那么需要使用new FileOutputStream(file,true) 這個(gè)構(gòu)造函數(shù)。
4. 使用write(int b)方法的時(shí)候,雖然參數(shù)接受的一個(gè)int類型的數(shù)據(jù),但是實(shí)際上只會(huì)把數(shù)據(jù)的低八位寫出,其他24位丟棄。
練習(xí) 拷貝圖片
public static void copyPic(){
//找到目標(biāo)文件
File inFile = new File("F:\\37.jpg");
File outFile = new File("F:\\37_1.jpg");
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
//建立數(shù)據(jù)通道
fileInputStream = new FileInputStream(inFile);
fileOutputStream = new FileOutputStream(outFile);
//建立緩沖字節(jié)數(shù)組,邊讀邊寫
byte[] buf = new byte[1024];
int length = 0;//記錄每次讀取字節(jié)個(gè)數(shù)
while((length = fileInputStream.read(buf)) != -1){//假設(shè)最后一次讀了700個(gè)字節(jié),最后數(shù)組中剩余的空間也會(huì)被拷貝
fileOutputStream.write(buf,0,length);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
//原則 先開后關(guān),后開先關(guān)
try {
fileOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
fileInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
由上,我們可以看出緩沖帶來(lái)的效率之快,因此sun公司設(shè)計(jì)了緩沖字節(jié)流,凡是緩沖流,都會(huì)以Buffered開頭
BufferedInputStream 緩沖輸入字節(jié)流 該類本質(zhì)就是在類內(nèi)部維護(hù)了大小為8kb的字節(jié)數(shù)組,凡是緩沖流都沒有讀寫文件的能力,BuffereInputStream 的close方法實(shí)際上關(guān)閉的就是你傳遞進(jìn)去的FileInputStream對(duì)象。
public static void buffer1(){
//1、找到目標(biāo)文件
File file = new File("f:\\b.txt");
FileInputStream fileInputStream = null;
BufferedInputStream bufferedInputStream = null;
try {
//2、建立數(shù)據(jù)的輸入通道
fileInputStream = new FileInputStream(file);
//3、建立緩沖輸入字節(jié)流
bufferedInputStream = new BufferedInputStream(fileInputStream);
int content = 0;
while((content = bufferedInputStream.read()) != -1){
System.out.print((char)content);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
bufferedInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
BufferedOutputStream 緩沖輸出流,為了提高寫文件的效率
public static void buffer2(){
//1、找到目標(biāo)文件
File file = new File("f:\\b.txt");
FileOutputStream fileOutputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
//2、建立數(shù)據(jù)的輸出通道
fileOutputStream = new FileOutputStream(file);
//3、建立緩沖輸出字節(jié)流
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
//4、寫數(shù)據(jù)
String str = "hello world";
bufferedOutputStream.write(str.getBytes());
bufferedOutputStream.flush();//把緩沖字節(jié)數(shù)組的數(shù)據(jù)寫到硬盤中
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
bufferedOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
BufferedOutputStream 需要注意的事項(xiàng): BufferedInputStream
1. 使用BufferedOutputStream的write方法時(shí)候,數(shù)據(jù)其實(shí)是寫入了BufferedOutputStream內(nèi)部維護(hù)的字節(jié)數(shù)組中,只有你調(diào)用
BufferedOutputStream的close方法或者是flush方法數(shù)據(jù)才會(huì)真正的寫到硬盤上去或者內(nèi)部維護(hù)的字節(jié)數(shù)組已經(jīng)存儲(chǔ)滿數(shù)據(jù)了,這時(shí)候
數(shù)據(jù)也會(huì)寫到硬盤上去。
2/. BufferedOutputStream 的close方法實(shí)際上關(guān)閉的就是你傳入的OutputStream對(duì)象的close方法。
練習(xí) 利用緩沖輸入輸出字節(jié)流拷貝圖片
public static void copyPic1(){
File inFile = new File("F:\\37.jpg");
File outFile = new File("F:\\37_2.jpg");
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
BufferedInputStream bufferedInputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
fileInputStream = new FileInputStream(inFile);
fileOutputStream = new FileOutputStream(outFile);
bufferedInputStream = new BufferedInputStream(fileInputStream);
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
int content = 0;
while((content = bufferedInputStream.read()) != -1){
bufferedOutputStream.write(content);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
bufferedOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
bufferedInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
這里提一下,不需要每次循環(huán)都flush一下,可以用前后執(zhí)行時(shí)間比對(duì),會(huì)發(fā)現(xiàn)不加flush速度更快
字符流
向文件中寫入中文
public static void chineseWrite(){
File file = new File("F:\\b.txt");
String str = "今晚好";
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(str.getBytes());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
因?yàn)閷懽止?jié)流時(shí)字節(jié)流不具備編碼和解碼格式的限制,因此寫中文不會(huì)亂碼,但是,讀取文件中數(shù)據(jù)會(huì)如何?
public static void chineseRead(){
File file = new File("F:\\b.txt");
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
int content = 0;
while((content = fileInputStream.read()) != -1){
System.out.print((char)content);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
會(huì)發(fā)現(xiàn)亂碼,因?yàn)橐粋€(gè)漢字有兩個(gè)字節(jié)構(gòu)成,而以上的讀法每次只讀一個(gè)字節(jié)
public static void chineseRead(){
File file = new File("F:\\b.txt");
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
int length = 0;
byte[] buf = new byte[2];
while((length = fileInputStream.read(buf)) != -1){
System.out.print(new String(buf,0,length));
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
可以看出非常麻煩,因此引出字符流,字符流是指讀取的數(shù)據(jù)是以字符為單位的,會(huì)把讀到的字節(jié)數(shù)據(jù)轉(zhuǎn)換成我們看的字符,字符流 = 字節(jié)流+編碼(解碼)
輸入字符流
Reader 抽象類 所有輸入字符流的基類
FileReader 讀取文件數(shù)據(jù)的輸入字符流
//法1 每次只會(huì)讀取一個(gè)字符數(shù)據(jù)
public static void readTest1(){
//1、找到目標(biāo)對(duì)象
File file = new File("F:\\b.txt");
FileReader fileReader = null;
try {
//2、建立數(shù)據(jù)的輸入通道
fileReader = new FileReader(file);
//3、讀取文件數(shù)據(jù)
int content = 0;
while((content = fileReader.read()) != -1){//FileReader的read方法每次讀取一個(gè)字符的數(shù)據(jù),如果讀到文件結(jié)束,返回-1
System.out.print((char)content);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//法2 使用緩沖字符數(shù)組讀取文件數(shù)據(jù)
public static void readTest2(){
//1、找到目標(biāo)對(duì)象
File file = new File("F:\\b.txt");
FileReader fileReader = null;
try {
//2、建立數(shù)據(jù)的輸入通道
fileReader = new FileReader(file);
//3、建立字符數(shù)組讀取數(shù)據(jù)
char[] cbuf = new char[1024];
int length = 0;
while((length = fileReader.read(cbuf)) != -1){
System.out.print(new String(cbuf,0,length));
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
輸出字符流
Writer抽象類 輸出字符流的基類
FileWriter 向文件寫出數(shù)據(jù)輸出字符流
public static void writeTest1(){
//1、找到目標(biāo)對(duì)象
File file = new File("F:\\b.txt");
FileWriter fileWriter = null;
try {
//2、建立數(shù)據(jù)輸出通道
fileWriter = new FileWriter(file);
//3、準(zhǔn)備數(shù)據(jù)
String str = "現(xiàn)在雨停了";
fileWriter.write(str);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
try {
fileWriter.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
FileWriter 要注意的事項(xiàng):
1. new FileWriter(file)的時(shí)候 , 如果目標(biāo)文件不存在,那么會(huì)創(chuàng)建目標(biāo)文件對(duì)象, 如果目標(biāo)文件已經(jīng)存在了,那么則不再重新創(chuàng)建。
2. 使用new FileWriter(file) 這個(gè)構(gòu)造方法的時(shí)候,默認(rèn)是會(huì)先清空文本的數(shù)據(jù),然后再寫入新的數(shù)據(jù)。如果需要追加數(shù)據(jù)則需要使用 new FileWriter(file,true)這個(gè)構(gòu)造方法。
3. 使用FileWriter的write方法的時(shí)候,數(shù)據(jù)是寫入了FileWriter內(nèi)部維護(hù)的字符數(shù)組中,如果需要把數(shù)據(jù)真正的寫到硬盤上去,需要調(diào)用flush方法或者 是close方法
或者是內(nèi)部維護(hù)的字符數(shù)組已經(jīng)滿了,這時(shí)候也會(huì)寫到硬盤上。