日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java基础之IO流(持续更新中)

發布時間:2023/12/8 java 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java基础之IO流(持续更新中) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
為什么要寫這篇文章?幫助更多大(xīn)佬(shǒu)學習,理解。 寫的很通俗,結合生活實際應該都比較容易理解。 本文主要內容有IO的理論部分,實際用法,原理,面試題,源碼
----------------------------------------------------------------------------------------


IO流概念 IO流:IO流簡單來說就是Input和Output流,IO流主要是用來處理設備之間的數據傳輸,Java對于數據的操作都是通過流實現,而java用于操作流的對象都在IO包中。
按數據內容分:字節流和字符流按流向分:輸入流(硬盤到內存)和輸出流(內存到硬盤)

字節流:因為計算機是以二進制的方式進行運算的,所以字節流能處理所有數據字符流:一開始是沒有字符流的
大家可以從源碼中看到發布的版本,字符流的原理是讀到數據后不直接處理,而是參照碼表后獲取對應的文字,然后再對文字進行操作,可以理解成 字符流=字節流+碼表,如果你想操作文字字符串類型的數據,那毫無疑問,優先考慮字符流沒錯~
-----------------------------------------------------------------------------------------------------------

IO流字符流的讀寫

接下來看一下Java提供了哪些技術來用于IO操作 首先提供了抽象類字節流的兩個父類:InputStream,OutputStream字符流的兩個父類:Reader,Writer

因為不斷向上抽取,所以功能變得不具體了,很抽象,形成了抽象類。所以要看父類,一看就知道是做什么用的。用子類,子類有很多具體的功能。

大家對文本應該都比較熟悉,所以先來介紹一下Writer的子類FileWriter,這些體系的子類都以父類名作為后綴,前綴就是該對象的功能,比如FileWriter,一看就知道是寫文件的便捷類。FileWriter import java.io.FileWriter; import java.io.IOException; public class FileWriterDemo {private static final String LINE_SEPARATOR = System.getProperty("line.separator");//解決不同操作平臺寫入換行問題 public static void main(String[] args) throws IOException {FileWriter fileWriter = new FileWriter("abc.txt",true);//創建FileWriter對象,構造函數填寫目的地,true代表可以續寫,不覆蓋 fileWriter.write("456" + LINE_SEPARATOR + "789");//寫到緩存區中一個字符串 fileWriter.flush();//刷出緩沖區,寫到硬盤中 fileWriter.close();//關閉,關閉前會調用一次flush方法。因為寫的功能調用的是windows的系統資源,所以用完了要關了,但關了再寫就不能寫了 //想象一下記事本 //write就像寫了后沒保存,斷電后就沒了 //flush就相當于保存操作,把你寫到內存的東西保存到了硬盤 //close就相當于關閉了記事本,但是關閉時候提示了你保存(關閉前保存) } }

執行完成后,看一下


寫完事了,在玩一下讀。讀的話用的哪個類,猜也能猜的差不多。FileReader

首先是一個字符一個字符讀,這個比較簡單,就是讀到了就返回,都不到就返回-1

public class FileReaderDemo {public static void main(String[] args) throws IOException {FileReader fileReader = new FileReader("abc.txt");//讀這個文件 int c;//用于接收單個字符 while((c = fileReader.read()) != -1)//如果當前讀到的字符不是-1,就一直讀。-1是規定的沒讀到的標識 {System.out.print((char)c);//讀到后轉一下顯示 }} }

一個一個讀不爽?一堆一堆讀!


這是我們要讀取的文件

這是讀的源碼

FileReader fileReader = new FileReader("abc.txt");//讀這個文件 char[] c = new char[3]; int len; //一次讀滿數組,如果讀到了,返回讀了幾個,如果沒讀到返回-1 while((len = fileReader.read(c)) != -1) {//輸出每次讀到的數組轉換成字符串 System.out.print(new String(c,0,len));//new String(char[] c,start,length)重新構造一個字符串,start作為開始索引,length是要獲取幾個 }

看一下過程,首先我們聲明了一個數組c,利用fileReader.read(c)讀取。

第一次就把數組讀滿了,結果為123,返回的是讀到的個數,是3


第二次在讀的時候,讀到了456,也是讀滿了數組


第三次讀的時候,讀到了換行符,可以看到在windows下,換行符是\r\n(這不是重點。。)


以此類推還是依此類推?不管了,反正再往下讀,就是89J,最后一次讀到QK的時候,發現讀不滿數組了,讀到的長度為2,數組的前兩個位置被替換變成了QK,最后一個元素由于沒有讀到被替換,所以還是上回讀到的值


最后一次讀不到了,返回讀到的長度為-1,不進循環,程序結束!


讀寫都會了后,來個小practice試一試。拷貝D盤的abc.txt到E盤

public class CopyFileDemo {public static void main(String[] args) throws IOException {//拷貝文件的原理就是先讀在寫 FileReader fileReader = new FileReader("D:/abc.txt"); FileWriter fileWriter = new FileWriter("E:/abc.txt"); char[] c = new char[3]; int len; while((len = fileReader.read(c)) != -1){fileWriter.write(c,0,len);//每次讀幾個就寫幾個 }fileWriter.flush(); fileWriter.close(); fileReader.close(); } }

--------------------------------------------------------------------------

緩沖區

緩沖區怎么理解呢?就比如你吃瓜子,毛嗑,向日葵,其實是一個東西。你撥一個吃一個肯定不爽,你有空就撥出來,然后放在一個盒子里面,想吃的時候直接拿,就非常海皮。在比如說,你去超市買東西,你推了一個購物車,買一個扔進去一個,到結賬的時候,你還得一個一個拿出來,不如在購物車里面加個框,最后把筐給它就完事了(學到沒有?)。計算機里面也是,讀一次寫一次效率肯定不高,可以先讀到一個緩沖區里面,然后最后緩沖區裝滿了,一次性把緩沖區的內容寫完,這樣效率就得到了提高。緩沖區的出現用于提高流的效率。

BufferedWriter

public static void main(String[] args) throws IOException {FileWriter fileWriter = new FileWriter("abc.txt"); BufferedWriter bw = new BufferedWriter(fileWriter);//緩沖區只是作為緩沖對象,真正的寫操作還是FileWriter來操作的 bw.write("123");//寫入數據到緩沖區 bw.flush();//刷到硬盤 bw.close();//bw關閉,底層關閉的是fileWriter }

BufferedReader

這個方法有個readLine()方法,可以一次讀一行,如果讀不到就返回null,你也可以選擇一個一個讀,也是用read方法,只不過重寫了父類的read方法。為什么要重寫呢?這就需要分析一下原理了。

public static void main(String[] args) throws IOException {FileReader reader = new FileReader("abc.txt"); BufferedReader br = new BufferedReader(reader); String str = null; while((str = br.readLine()) != null){System.out.print(str); } }

BufferedReader中read()方法實現原理

其實就好你去廚房吃饅頭,吃一個拿一個肯定不爽嘛,不如拿個筐去,裝在筐里面,想吃的時候直接從筐里取就很快。緩沖區也是,先拿到一些到內存中,用的時候直接從內存取就非常快了。如果不重寫這個方法,就會調用父類的read,而父類的read并不是從緩沖區里面讀的,效率比較低。重寫后拿到的數據都是緩沖區里面的數據。 原理就是先獲取一批數據放到一個數組里,然后調用一次read方法就從數組里面取一次,取沒了就再拿一次放到數組里,取到沒有為止。下面的代碼是模擬緩沖區read和readLine方法的實現。readLine就是用StringBuffer作為緩沖區,如果讀到了換行符就結束方法并返回一行的數據。 public class MyBufferedReader {FileReader fileReader; public MyBufferedReader(FileReader fileReader)構造函數傳遞需要被緩沖的對象 {this.fileReader = fileReader; }char[] cArr = new char[1024];//緩沖區 int count;//緩沖區里面元素的數量 int pos;//用于獲取緩沖區的角標 //自定義read方法 public int read() throws IOException {//筐里面沒有饅頭,去廚房取 if(count == 0) {count = fileReader.read(cArr);//如果緩沖區沒有了,就去拿 pos = 0;//重新獲取之后,要把角標重新設置為0 }//廚房也沒有饅頭了 //如果沒有數據,拿不到了,返回-1 if(count < 0){return -1; }//在筐里拿饅頭吃 char c = cArr[pos++];//每次自增變量獲取 count--;//緩沖區數量減少 return c; }//自定義readLine方法 public String readLine() throws IOException {StringBuffer sb = new StringBuffer(); //判斷/r/n int c; while((c = this.read()) != -1)//循環讀 {if(c == '\r')//如果是/r就跳過去,不追加到字符串中 {continue; }if(c == '\n')//如果是/n,就代表讀到了換行符,返回一行的字符串 {return sb.toString(); }sb.append(c);//日常追加字符串 }return sb.toString(); } }

------------------------------------------------------------------------------------- 不明白原理也沒關系,其實開發中也用不上,但最好了解一下把,不然面試的時候要問呢?

字符流說完了,總結一下把,首先要了解字符流的兩個抽象父類,Writer和Reader,下面有一些子類,其中FileReader是讀文件用的(輸入),常用的方法有int read(),int read(char)。FileWriter是寫文件用的(輸出),常用的方法有writer(); flush(); close(); 還有給這兩位緩沖用的對象,BufferedWriter和BufferedReader,BufferWriter不用多說了,BufferWriter常用的方法有int read();和 String?readLine();這兩個方法都是重寫過的。還有一個LineNumberReader對象沒有說,就是讀到后加行號,一般用不上,非常簡單,自己看下就行了。


-----------------------------------------------------------------------------------------------------


字節流

接下來看字節流,字節流相比字符流就比較萬能了,但是對于處理文本來說還是要優先考慮字符流的。可以說字節流能處理任何類型的文件,比如.txt的,jgp的,mp3,mp4,mp5的,mp6有嘛?avi視頻文件等等。

InputStream -> FileInputStream,用字節流玩一玩文件,見名知意,寫文件用的。

public class FileInputStreamDemo {public static void main(String[] args) throws IOException {FileInputStream fis = new FileInputStream("abc.txt"); //一個一個讀 int i; while((i = fis.read()) != -1){System.out.print((char)i); }//一堆一堆讀 byte[] c = new byte[1024]; int len; while((len = fis.read(c)) != -1){System.out.print(new String(c,0,len)); }//讀小文件用,慎用 byte[] c2 = new byte[fis.available()];//fis.available文件字節數 int len2 = fis.read(c2); System.out.print(new String(c2,0,len2)); } }

和字符流都差不多,只不過接受用的是byte字節,還多了一個fis.available()方法,大批量讀不建議使用。

讀完事了,來一個寫。用到了FileOutputStream

public class FileOutputStreamDemo {public static void main(String[] args) throws IOException {FileOutputStream fos = new FileOutputStream("abc.txt"); fos.write("123456".getBytes()); fos.flush();//字節流不需要調用flush方法,不需要先寫到緩沖區,直接和文件打交道。可以看到繼承了父類的flush,并沒有重寫, fos.close();//關閉還是要調用的,子類也進行了重寫 } }

都是和字符流用法差不多,非常簡單。

來一個拷貝mp3的練習,順便用一下緩沖區,和字符流也差不多,不過多解釋。


public class CopyMP3Demo {public static void main(String[] args) throws IOException {FileInputStream is = new FileInputStream("River flows in you.mp3"); BufferedInputStream bis = new BufferedInputStream(is); FileOutputStream os = new FileOutputStream("abc.mp3"); BufferedOutputStream bos = new BufferedOutputStream(os); byte[] c = new byte[1024]; int len; while((len = bis.read(c)) != -1){bos.write(c,0,len); bos.flush(); }bos.close(); bis.close(); } }

----------------------------------------------------------------------------------------------------------------------------

轉換流

需求:讓用戶輸入一段話,按回車結束。如果不是over就輸出,是over結束程序。

如果不用轉換流,InputStream不存在字符流中的readLine()方法,所以自己寫要判斷換行符,非常麻煩。這時候就需要將字節流轉換成字符流解碼

InputStreamReader

InputStream is = System.in; InputStreamReader isr = new InputStreamReader(is);//將字節流轉換成字符流,放入一個字節流 BufferedReader br = new BufferedReader(isr);//緩沖區高效讀取 String line; while((line = br.readLine()) != null) {if(line.equals("over"))break; System.out.print(line.toString()); }



OutputStreamWriter編碼




----------------------------------------------------------------------


學了這么多流對象?到底怎么實戰?

1.首先明確源和目的地

源:InputStream Reader

目的地:OutputStream Writer


2.明確數據是否是純文本

? ? |--是,Reader

? ?|--否,InputStream

目的地:

? ? |--是,Writer

? ? |--否,OutputStream

3.明確具體的設備

源設備:硬盤File,鍵盤System.in,內存Array,網絡Socket

目的地設備:硬盤File,控制臺System.out,內存Array,網絡Socket


4.是否需要額外功能

? ? 高效緩沖區,轉換流

-----------------------------------------------------------------------------------------------------------------

明確了這四點之后,來看幾個需求

1.復制一個文本文件

? ? 首先是純文本,選擇Reader和Writer,具體設備是硬盤,選擇FileReader和FileWriter,再看是否需要額外功能,需要緩沖區高效讀寫,那么選擇BufferedReader和BufferedWriter

2.讀取鍵盤錄入的數據寫到硬盤中

? ? 首先也是純文本,選擇Reader和Writer,具體設備是控制臺System.in和硬盤File,選擇InputStream is = System.in;

? ? 和FileWriter,需要額外功能嗎?考慮讀取到的數據需要轉換成字符會更好操作,所以選擇轉換流,字節轉換成字符選用

????InputStreamReader,需要高效嗎?需要!

????那就BufferedReader br = new BufferedReader(new InputStreamReader(System));

? ? BufferedWriter bw = new BufferedWriter(new FileWriter("abc.txt"));

3.將一個文本上的數據顯示在控制臺上

? ? 首先是純文本,選擇Reader和Writer,具體設備是硬盤和控制臺,選擇FileReader和OutputStream os = System.out;

? ? 需要額外功能嘛?需要轉換流,OutputStreamWriter(System.out),需要高效嘛?需要!

? ? BufferedReader br = new BufferedReader(new FileReader("abc.txt"));

? ? BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

4.將控制臺輸入的文本,輸出在控制臺上

? ? 純文本,Reader和Writer,具體設備控制臺,選擇InputStream is = System.in;和OutputStream os = System.out;

? ? 需要額外功能?轉換和高效

? ? BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

????BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

ok,只要明確了對象,使用的話就比較簡單了。


---------------------------------------------------------------------------------------------------


到這里,IO的基本對象就學的差不多了

字節流FileInputStream,FileOutputStream,BufferedInputStream,BufferedOutputStream

字符流FileReader,FileWriter,InputStreamReader,OutputStreamWriter,BufferedReader,BufferedWriter

但是這些對象都是操作的數據,操作不了屬性。比如獲取文件名稱,文件大小,操作文件夾等等。

這時候就出現了File類

File類將文件和文件夾封裝成了對象,更方便的操作文件和文件夾。沒有什么技術含量,就寫API的Demo了

//-----------------File構造的幾種方式--------------- File f1 = new File("abc.mp3"); File f2 = new File("c:\\","abc.txt"); File f = new File("c:\\"); File f3 = new File(f,"abc.txt"); File f4 = new File("c:" + File.separator + "abc.txt"); //----------------File常用獲取------------------ String name = f1.getName();//獲取文件名稱 String path = f1.getPath();//獲取相對路徑 String absPath = f1.getAbsolutePath();//獲取絕對路徑 long len = f1.length();//獲取長度 long time = f1.lastModified();//獲取最后修改時間 //看上去爽一點的 最后修改時間 Date date = new Date(time); DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG); String timeStr = df.format(date); System.out.println(name); System.out.println(path); System.out.println(absPath); System.out.println(len); System.out.println(time); System.out.println(timeStr); //-----------------------創建與刪除-------------------------- //和輸出流不同的是,如果沒有就創建,有就不做操作 File f5 = new File("abc.txt"); boolean b = f5.createNewFile();//創建一個新的文件 File f6 = new File("abc"); boolean b2 = f6.mkdir();//創建文件夾 File f7 = new File("abc\\def"); boolean b3 = f7.mkdirs();//創建多個文件夾 File f8 = new File("abc\\def"); boolean b4 = f8.delete();//刪除,如果文件夾里面有內容,是不可以刪除的 f8.deleteOnExit();//在程序退出后刪除,比如IO流讀取完文件,把文件刪除 //----------------------------判斷-------------------------------- File f9 = new File("abc.txt"); boolean bb = f9.exists();//判斷文件或文件夾之前一定要判斷文件是否存在 boolean b5 = f9.isDirectory(); boolean b6 = f9.isFile(); //----------------------------替換--------------------------------- File f10 = new File("123.txt"); f10.renameTo(new File("456.txt")); //---------------------系統根目錄獲取容量---------------------------- File[] files = File.listRoots();//獲取所有盤符 for(File fx : files) {System.out.print(fx); }File fJ = new File("c:\\"); System.out.println(fJ.getFreeSpace());//可用 System.out.println(fJ.getTotalSpace());//總共 System.out.println(fJ.getUsableSpace());//已用 //--------------------------獲取目錄內容------------------------------------ File fQ = new File("c:\\"); String[] list = fQ.list(); for(String s : list) {System.out.println(s); }//--------------------------------過濾目錄內容----------------------------------- //找到所有.java的文件 File fK = new File("c;\\"); fK.list(new FilenameFilter() {@Override public boolean accept(File dir, String name) {return name.endsWith(".java"); } });

深度遍歷文件夾 -- 遞歸思想

使用遞歸時,要注意兩點

1.結束條件

2.遞歸次數,小心內存溢出(光壓棧不彈棧)

public static void main(String[] args) {depthDir(new File("d:\\123"),0); }public static void depthDir(File f,int level) {System.out.println(printSpace(level) + f.getName()); level++; File[] files = f.listFiles(); for(int x = 0; x < files.length; x++){//如果當前是文件夾,就在進去遍歷 if(files[x].isDirectory()){depthDir(files[x],level); }else {System.out.println(printSpace(level)+ files[x].getName()); }} }private static String printSpace(int level) {StringBuffer sb = new StringBuffer(); for(int x = 0; x < level; x++){sb.append(" "); }return sb.toString(); }

遍歷刪除文件夾,Windows下刪除文件只能從里往外刪

public static void main(String[] args) {File f = new File("d:\\123"); deleteDir(f); }private static void deleteDir(File f) {//遍歷,如果不是文件夾就刪除,是就繼續進去,等到進到最后一個了開始刪除 File[] files = f.listFiles(); for(int x = 0; x < files.length; x++){if(files[x].isDirectory()){deleteDir(files[x]); }else {files[x].delete(); }}f.delete(); }

總結

以上是生活随笔為你收集整理的Java基础之IO流(持续更新中)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。