??前言👀~
上一章我們介紹了多線程進階的相關內容,今天來介紹使用java代碼對文件的一些操作
文件(file)
文件路徑(Path)
文件類型
文件操作
文件系統操作(File類)
文件內容的讀寫( 流對象)
字符流(文本文件)
Reader類
Writer類
字節流(二進制文件)
InputStream類
outputStream類
字節流轉為字符流
緩沖區(buffer)
如果各位對文章的內容感興趣的話,請點點小贊,關注一手不迷路,講解的內容我會搭配我的理解用我自己的話去解釋如果有什么問題的話,歡迎各位評論糾正 🤞🤞🤞
個人主頁:N_0050-CSDN博客
相關專欄:java SE_N_0050的博客-CSDN博客??java數據結構_N_0050的博客-CSDN博客??java EE_N_0050的博客-CSDN博客
文件(file)
操作系統會將很多的硬件設備以及軟件資源抽象成"文件"統一進行管理,但是大部分情況"文件"指的是硬盤上的文件,也就是對硬盤的一種抽象。硬盤有機械硬盤(HDD)和固態硬盤(SSD),固態硬盤的效率比機械硬盤高,里面都是集成程度很高的芯片(類似cpu,內存),我們的電腦一般自帶的都是固態硬盤,想放更多資料可以加個機械硬盤
文件路徑(Path)
編程的時候我們通過文件的方式操作硬盤,如上面所說把硬盤抽象出來進行操作。計算機中有很多文件,我們通過"文件系統"(操作系統提供的模塊)進行組織和管理,操作系統中使用目錄(文件)這樣的結構來組件文件,采用樹形結構,想想也好理解樹有根結點理解為硬盤,點進去就是目錄/文件,也就是根節點的子結點以此類推。用目錄的層次結構來描述文件所在的位置稱為"路徑",C:\Windows\System32,類似這樣的字符串,可以看出當前文件在哪個目錄下
1.絕對路徑:就是上面這個以你的盤開頭的C:\Windows\System32
2.相對路徑:前提是指定了一個目錄,作為基準目錄,從基準目錄出發沿著路線找你指定的文件,以 .(當前目錄)或者 ..(當前目錄的上一級目錄)開頭,.后面跟的路徑代表咋們是在同一個文件下的,..后面跟的路徑,..代表是后面路徑的爹
文件類型
文件,根據其保存數據的不同,也經常被分為不同的類型,在編程角度,我們一般劃分為文本文件和二進制文件,不管屬于哪個在計算機中這些數據都是以二進制進行存儲的
1.文本類型:文件中保存的數據,都是字符串,保存的內容都屬于合法的字符
2.二進制類型:文件中保存的數據,都是二進制,保存的內容不一定是合法的字符
首先說什么是字符,字符就是字母、數字、符號等書面語言,不合法的字符指的是在某種字符編碼下無法正確顯示的字符(通常會顯示為亂碼),字符集則是字符的集合,它會給每一個字符分配一個唯一的編號,例如ASCALL碼和Unicode就是字符集,Unicode字符集包含幾乎所有已知的文字和符號,字符編碼就是將字符轉換為計算機能處理的數據,字符編碼方式有UTF-8、UTF-16等。所以如果你的文件是通過utf8進行編碼的話,此時保存的數據都是utf8編碼中合法的字符,那就是文本文件,如果出現不是utf8編碼的字符,那就是二進制了
其實判斷文件什么類型很簡單,打開是亂碼就算二進制類型,否則就是文本類型。可以使用記事本去測試,把文件往里丟,看里面的字符你認識不,認識的話一般就是文本類型了,不是的話就是二進制類型。文本文件和二進制文件的代碼編寫方式不同,要注意區分。下面演示一下亂碼
文件操作
分為兩類,文件系統的操作,例如創建文件、刪除文件、重命名等,也就是你右擊文件能干的事,在java中我們可以使用File類也能完成這些操作。文件內容的操作,流對象。這里的操作例如讀文件、寫文件。可以使用例如InputStream和OutPutStream后面進行詳細講解
文件系統操作(File類)
屬性:
pathSeparator,表示路徑的分隔符就是這個" \ ",windows這個" \ "和" / "都行,Mac和Linux上只能使用 / "作為分隔符。這個屬性可以根據當前系統自動變化,又體現了跨平臺性
構造方法:
一個File對象,就對應硬盤上的文件,構造對象的時候把文件路徑(絕對路徑或者相對路徑)以及文件擴展名,就是你要操作哪個文件,你把路徑丟到file的構造方法即可
方法:
下面是file的方法,后面會進行演示
前五個路徑方法演示:
public class Test {public static void main(String[] args) throws IOException {File file = new File("E:/test.txt");System.out.println(file.getParent());//獲取父目錄路徑System.out.println(file.getName());//獲取文件名System.out.println(file.getPath());//獲取文件路徑System.out.println(file.getAbsolutePath());//獲取絕對路徑System.out.println(file.getCanonicalFile());//獲取修飾過的絕對路徑}
}
輸出結果
可以發現即使這個文件我沒有也沒事
getCanonicalFile方法和get Absolute Path方法的區別可以看如下代碼
public class Test {public static void main(String[] args) throws IOException {File file = new File("./test.txt");System.out.println(file.getParent());//獲取父目錄路徑System.out.println(file.getName());//獲取文件名System.out.println(file.getPath());//獲取文件路徑System.out.println(file.getAbsolutePath());//獲取絕對路徑System.out.println(file.getCanonicalFile());//獲取修飾過的絕對路徑}
}
輸出結果,我把文件路徑改成相對路徑的時候就有區別了
三個判斷文件類型以及文件是否存在方法演示:
public class Test {public static void main(String[] args) throws IOException {File file = new File("E:/IO");System.out.println(file.exists());//判斷文件是否存在System.out.println(file.isDirectory());//判斷文件類型 是否是一個目錄System.out.println(file.isFile());//判斷文件類型 是不是普通文件}
}
輸出結果
createNewFile()創建文件的方法演示
public class Test {public static void main(String[] args) throws IOException {File file = new File("E:/IO/text.txt");System.out.println(file.createNewFile());}
}
輸出結果
?delete()和deleteOnExit()方法刪除文件的方法有兩個并且有區別下面進行演示
public class Test {public static void main(String[] args) throws IOException {File file = new File("E:/IO/text.txt");System.out.println(file.delete());}
}
輸出結果
public class Test {public static void main(String[] args) throws IOException, InterruptedException {File file = new File("E:/IO/text.txt");Thread.sleep(3000);file.deleteOnExit();//等JVM運行結束了再去刪除文件}
}
輸出結果
listFiles()方法獲取當前目錄下所有文件
public class Test {public static void main(String[] args) throws IOException, InterruptedException {File file = new File("E:/");File[] f = file.listFiles();//獲取當前目錄下所有文件for (File wow : f) {System.out.print(wow + " ");}}
}
輸出結果
mkdir()方法在當前目錄下創建文件
public class Test {public static void main(String[] args) throws IOException, InterruptedException {File file = new File("E:/IO/text");System.out.println(file.mkdir());//當前目錄下接著創建目錄(文件)}
}
輸出結果
mkdirs()方法和mkdir()方法的區別,在當前目錄下創建文件并且還可以接著創建
public class Test {public static void main(String[] args) throws IOException, InterruptedException {File file = new File("E:/IO/text/text2/text3");System.out.println(file.mkdirs());}
}
輸出結果
文件內容的讀寫( 流對象)
標準庫中,提供讀寫文件的流對象有很多,但是歸納為兩個大類,其他流都繼承這個兩個大類
什么叫輸入?什么叫輸出?輸入=>讀,輸出=>寫
要站在cpu的角度考慮,一個數據保存到硬盤,對于cpu即是輸出,一個數據從硬盤讀到cpu,對于cpu即是輸入
字符流(文本文件)
本質針對字節流進一步封裝,字符流能幫我們把文件中 幾個相鄰的字節 轉換成 一個字符。相當于完成了一個自動查字符集表,每次讀/寫最小單位為"字符"(1個字符對應多個字節),1個字符范圍是0-65535,至于1個字符對應幾個字節,看字符集是哪種,例如GBK一個中文字符對應兩個字節,UTF8一個中文字符對應三個字節,提供了兩個父類,Reader和Writer,接下來演示使用
Reader類
創建Reader對象的過程,就相當于打開文件的過程
read方法有三個參數的版本和無參的版本,并且返回值為int類型
為什么read方法返回類型為int?
0-65535這個范圍是一個無符號char能表示的范圍,一個字符對應兩個字節。在java中如果是使用char類型的時候,使用Unicode進行編碼的。使用String類型的時候則自動的把每個字符從Unicode編碼轉為UTF8編碼。例如一個char[ ] c數組包含的每個字符固定使用Unicode進行編碼。但是使用字符數組構造成String,例如String[ ] s=new String(c),此時自動的把每個字符轉成UTF8編碼,使用s.charAt(c),又會把UTF8編碼的數據轉換成Unicode。一個漢字,Unicode表示2個字節,UTF8表示3個字節。多個Unicode放到一起,難以區分哪到哪是一個完整的字符,UTF8可以做到就是針對連續多個字符傳輸的時候一種改進
總結按字節處理的時候采用Unicode編碼,按字符串處理的時候采用UTF8編碼
read()方法無參數,一次讀取一個字符
public class Test {public static void main(String[] args) throws IOException, InterruptedException {try (Reader reader = new FileReader("E:/IO/text.txt")) {int read = reader.read();if (read == -1) {return;}char c = (char) read;System.out.print(c);}}
}
輸出結果
read方法有參數一個字符數組,這個數組是空的字符數組,你把這個數組交給read方法,它把讀到的填入這個數組里去,然后交給你。這個能一次讀取多個字符
public class Test {public static void main(String[] args) throws IOException, InterruptedException {try (Reader reader = new FileReader("E:/IO/text.txt")) {char[] ch = new char[11];int read = reader.read(ch);System.out.println("讀到的個數:" + read);while (true) {for (char c : ch) {System.out.print(c);}break;}}}
}
輸出結果,有個注意點我這邊使用了try-Source關閉字符流防止文件資源泄露!!!
Writer類
和上面的差不多一個是讀文件,一個則是寫文件,有些注意的地方下面講解
writer方法,把你要寫的內容寫入文件中,注意一下會把原先的內容覆蓋掉,要是不想的話需要在構造方法中手動設置true這樣就不會了
public class Test {public static void main(String[] args) {try (Writer writer = new FileWriter("E:/IO/text.txt")) {writer.write("我是字符流的Writer");} catch (IOException e) {throw new RuntimeException(e);}}
}
基本流程:
1.先打開文件(構造方法)
2.讀文件(Read)/寫文件(Writer)
3.關閉文件(close)!!!
字節流(二進制文件)
每次讀/寫最小單位為"字節"(8bit)最少1字節,提供了兩個父類,InputStream和OuputStream
InputStream類
和字符流的Reader差不多,只是這里是字節表示,1個字節范圍是0-255,一般字節我們習慣使用16進制表示,1個字節表示8個比特位,也就是兩個16進制數字,bit就是位,也叫比特位,是計算機表示數據最小的單位。1個字節8bit,1byte=8bit。1byte就是1B,位就是bit也是b,1B=8b
public class Test {public static void main(String[] args) {try (InputStream inputStream = new FileInputStream("E:/IO/text.txt")) {byte[] s = new byte[6];int read = inputStream.read(s);System.out.println("讀取到的個數:" + read);for (int i = 0; i < s.length; i++) {System.out.printf("%x\n", s[i]);}} catch (IOException e) {throw new RuntimeException(e);}}
}
輸出結果,使用16進制輸出
去確認一下對不對
outputStream類
和字符流的Writer差不多,構造方法不設置true會覆蓋掉原來的內容
下面是代碼演示,注意一下我們這里將字符串轉為字節寫入,因為我們使用的是字節流
public class Test {public static void main(String[] args) {try (OutputStream outputStream = new FileOutputStream("E:/IO/text.txt")) {String s = "java之父";outputStream.write(s.getBytes());} catch (IOException e) {throw new RuntimeException(e);}}
}
輸出結果
字節流轉為字符流
有下面這幾種方法:
1.使用scanner搭配InputStream可以從文件中讀取數據了
public class Test {public static void main(String[] args) {try (InputStream inputStream = new FileInputStream("E:/IO/text.txt");) {Scanner scanner = new Scanner(inputStream);String s = scanner.next();System.out.println(s);} catch (IOException e) {throw new RuntimeException(e);}}
}
輸出結果
2.使用PrintWriter類把字節流轉字符流,把內容寫入指定路徑文件中
public class Test {public static void main(String[] args) {try (OutputStream outputStream = new FileOutputStream("E:/IO/text.txt")) {PrintWriter printWriter = new PrintWriter(outputStream);printWriter.printf("高斯林");} catch (IOException e) {throw new RuntimeException(e);}}
}
輸出結果,會發現寫入高斯林,沒有內容顯示
緩沖區(buffer)
"緩沖區"是內存空間的一部分,PrintWriter這樣的類,進行寫數據的時候,不一定直接寫入硬盤,而是先把數據寫到一個內存構成的"緩沖區",引入緩沖區也是為了提高效率,因為我們知道把數據寫到內存中比寫到硬盤中速度要快很多,所以我們先把數據寫到內存中,等內存中存的差不多了再寫到硬盤中,這樣能提供效率的同時減少讀寫硬盤的次數
但是要注意如果還沒來得及把緩沖區的數據寫入到硬盤中,此時進程結束了,數據就會丟失,所以為了確保數據能寫入硬盤中,在合適的時機使用flush方法,手動刷新緩沖區,這樣就可以確保數據寫入到硬盤中。在剛才的代碼加入flush方法,這樣就能確保數據從緩沖區寫到硬盤中了
public class Test {public static void main(String[] args) {try (OutputStream outputStream = new FileOutputStream("E:/IO/text.txt")) {PrintWriter printWriter = new PrintWriter(outputStream);printWriter.printf("高斯林");printWriter.flush();} catch (IOException e) {throw new RuntimeException(e);}}
}
以上便是關于如何使用java代碼去操作文件的內容,多用用就能掌握,我們下一章再見💕