Java基礎——Java IO詳解

一、概述


1、Java IO

? ? ? ?Java IO即Java 輸入輸出系統。不管我們編寫何種應用,都難免和各種輸入輸出相關的媒介打交道,其實和媒介進行IO的過程是十分復雜的,這要考慮的因素特別多,比如我們要考慮和哪種媒介進行IO(文件、控制臺、網絡),我們還要考慮具體和它們的通信方式(順序、隨機、二進制、按字符、按字、按行等等)。Java類庫的設計者通過設計大量的類來攻克這些難題,這些類就位于java.io包中。

? ? ? ?在JDK1.4之后,為了提高Java IO的效率,Java又提供了一套新的IO,Java New IO簡稱Java NIO。它在標準java代碼中提供了高速的面向塊的IO操作。本篇文章重點介紹Java IO,關于Java NIO請參考我的另兩篇文章:

Java NIO詳解(一)?
Java NIO詳解(二)


2、流

? ? ? ?在Java IO中,流是一個核心的概念。流從概念上來說是一個連續的數據流。你既可以從流中讀取數據,也可以往流中寫數據。流與數據源或者數據流向的媒介相關聯。在Java IO中流既可以是字節流(以字節為單位進行讀寫),也可以是字符流(以字符為單位進行讀寫)。


3、IO相關的媒介

Java的IO包主要關注的是從原始數據源的讀取以及輸出原始數據到目標媒介。以下是最典型的數據源和目標媒介:

  • 文件
  • 管道
  • 網絡連接
  • 內存緩存
  • System.in, System.out, System.error(注:Java標準輸入、輸出、錯誤輸出)


二、Java IO類庫的框架


1、Java IO的類型

雖然java IO類庫龐大,但總體來說其框架還是很清楚的。從是讀媒介還是寫媒介的維度看,Java IO可以分為:

? ? ? ?1)輸入流:InputStream和Reader

? ? ? ?2)輸出流:OutputStream和Writer


而從其處理流的類型的維度上看,Java IO又可以分為:

? ? ? ?1)字節流:InputStream和OutputStream

? ? ? ?2)字符流:Reader和Writer


下面這幅圖就清晰的描述了JavaIO的分類:

? 字節流 字符流
輸入流 InputStream Reader
輸出流 OutputStream Writer


? ? ? ?我們的程序需要通過InputStream或Reader從數據源讀取數據,然后用OutputStream或者Writer將數據寫入到目標媒介中。其中,InputStream和Reader與數據源相關聯,OutputStream和writer與目標媒介相關聯。 以下的圖說明了這一點:



2、IO類庫
? ? ? ?上面我們介紹了Java IO中的四各類:InputStream、OutputStream、Reader、Writer,其實在我們的實際應用中,我們用到的一般是它們的子類,之所以設計這么多子類,目的就是讓每一個類都負責不同的功能,以方便我們開發各種應用。各類用途匯總如下:

  • 文件訪問
  • 網絡訪問
  • 內存緩存訪問
  • 線程內部通信(管道)
  • 緩沖
  • 過濾
  • 解析
  • 讀寫文本 (Readers / Writers)
  • 讀寫基本類型數據 (long, int etc.)
  • 讀寫對象

下面我們就通過兩張圖來大體了解一下這些類的繼承關系及其作用

圖1:java io 類的集成關系



圖2:java io中各個類所負責的媒介



三、Java IO的基本用法


1、Java IO:字節流

? ? ? ?通過上面的介紹我們已經知道,字節流對應的類應該是InputStreamOutputStream,而在我們實際開發中,我們應該根據不同的媒介類型選用相應的子類來處理。下面我們就用字節流來操作文件媒介:

例1,用字節流寫文件

  public static void writeByteToFile() throws IOException{String hello= new String( "hello word!");byte[] byteArray= hello.getBytes();File file= new File( "d:/test.txt");//因為是用字節流來寫媒介,所以對應的是OutputStream //又因為媒介對象是文件,所以用到子類是FileOutputStreamOutputStream os= new FileOutputStream( file);os.write( byteArray);os.close();}
例2,用字節流讀文件

  public static void readByteFromFile() throws IOException{File file= new File( "d:/test.txt");byte[] byteArray= new byte[( int) file.length()];//因為是用字節流來讀媒介,所以對應的是InputStream//又因為媒介對象是文件,所以用到子類是FileInputStreamInputStream is= new FileInputStream( file);int size= is.read( byteArray);System. out.println( "大小:"+size +";內容:" +new String(byteArray));is.close();}


2、Java IO:字符流

? ? ? ?同樣,字符流對應的類應該是ReaderWriter。下面我們就用字符流來操作文件媒介:

例3,用字符流讀文件

  public static void writeCharToFile() throws IOException{String hello= new String( "hello word!");File file= new File( "d:/test.txt");//因為是用字符流來讀媒介,所以對應的是Writer,又因為媒介對象是文件,所以用到子類是FileWriterWriter os= new FileWriter( file);os.write( hello);os.close();}

例4,用字符流寫文件

  public static void readCharFromFile() throws IOException{File file= new File( "d:/test.txt");//因為是用字符流來讀媒介,所以對應的是Reader//又因為媒介對象是文件,所以用到子類是FileReaderReader reader= new FileReader( file);char [] byteArray= new char[( int) file.length()];int size= reader.read( byteArray);System. out.println( "大小:"+size +";內容:" +new String(byteArray));reader.close();}


3、Java IO :字節流轉換為字符流
? ? ? ?字節流可以轉換成字符流,java.io包中提供的 InputStreamReader類就可以實現,當然從其命名上就可以看出它的作用。其實這涉及到另一個概念,IO流的 組合,后面我們詳細介紹。下面看一個簡單的例子:

例5 ,字節流轉換為字符流

  public static void convertByteToChar() throws IOException{File file= new File( "d:/test.txt");//獲得一個字節流InputStream is= new FileInputStream( file);//把字節流轉換為字符流,其實就是把字符流和字節流組合的結果。Reader reader= new InputStreamReader( is);char [] byteArray= new char[( int) file.length()];int size= reader.read( byteArray);System. out.println( "大小:"+size +";內容:" +new String(byteArray));is.close();reader.close();}


4、Java IO :IO類的組合

? ? ? ?從上面字節流轉換成字符流的例子中我們知道了IO流之間可以組合(或稱嵌套),其實組合的目的很簡單,就是把多種類的特性融合在一起以實現更多的功能。組合使用的方式很簡單,通過把一個流放入另一個流的構造器中即可實現,兩個流之間可以組合,三個或者更多流之間也可組合到一起。當然,并不是任意流之間都可以組合。關于組合就不過多介紹了,后面的例子中有很多都用到了組合,大家好好體會即可。


5、Java IO:文件媒介操作

? ? ? ?File是Java IO中最常用的讀寫媒介,那么我們在這里就對文件再做進一步介紹。


1)File媒介

例6 ,File操作

public class FileDemo {public static void main(String[] args) {//檢查文件是否存在File file = new File( "d:/test.txt");boolean fileExists = file.exists();System. out.println( fileExists);//創建文件目錄,若父目錄不存在則返回falseFile file2 = new File( "d:/fatherDir/subDir");boolean dirCreated = file2.mkdir();System. out.println( dirCreated);//創建文件目錄,若父目錄不存則連同父目錄一起創建File file3 = new File( "d:/fatherDir/subDir2");boolean dirCreated2 = file3.mkdirs();System. out.println( dirCreated2);File file4= new File( "d:/test.txt");//判斷長度long length = file4.length();//重命名文件boolean isRenamed = file4.renameTo( new File("d:/test2.txt"));//刪除文件boolean isDeleted = file4.delete();File file5= new File( "d:/fatherDir/subDir");//是否是目錄boolean isDirectory = file5.isDirectory();//列出文件名String[] fileNames = file5.list();//列出目錄File[]   files = file4.listFiles();}
}


2)隨機讀取File文件
? ? ? ?通過上面的例子我們已經知道,我們可以用FileInputStream(文件字符流)或FileReader(文件字節流)來讀文件,這兩個類可以讓我們分別以字符和字節的方式來讀取文件內容,但是它們都有一個不足之處,就是只能從文件頭開始讀,然后讀到文件結束。

? ? ? ?但是有時候我們只希望讀取文件的一部分,或者是說隨機的讀取文件,那么我們就可以利用RandomAccessFile。RandomAccessFile提供了seek()方法,用來定位將要讀寫文件的指針位置,我們也可以通過調用getFilePointer()方法來獲取當前指針的位置,具體看下面的例子:

例7,隨機讀取文件

  public static void randomAccessFileRead() throws IOException {// 創建一個RandomAccessFile對象RandomAccessFile file = new RandomAccessFile( "d:/test.txt", "rw");// 通過seek方法來移動讀寫位置的指針file.seek(10);// 獲取當前指針long pointerBegin = file.getFilePointer();// 從當前指針開始讀byte[] contents = new byte[1024];file.read( contents);long pointerEnd = file.getFilePointer();System. out.println( "pointerBegin:" + pointerBegin + "\n" + "pointerEnd:" + pointerEnd + "\n" + new String(contents));file.close();}


例8,隨機寫入文件

  public static void randomAccessFileWrite() throws IOException {// 創建一個RandomAccessFile對象RandomAccessFile file = new RandomAccessFile( "d:/test.txt", "rw");// 通過seek方法來移動讀寫位置的指針file.seek(10);// 獲取當前指針long pointerBegin = file.getFilePointer();// 從當前指針位置開始寫file.write( "HELLO WORD".getBytes());long pointerEnd = file.getFilePointer();System. out.println( "pointerBegin:" + pointerBegin + "\n" + "pointerEnd:" + pointerEnd + "\n" );file.close();}


6、Java IO:管道媒介

? ? ? ?管道主要用來實現同一個虛擬機中的兩個線程進行交流。因此,一個管道既可以作為數據源媒介也可作為目標媒介。
? ? ? ?需要注意的是java中的管道和Unix/Linux中的管道含義并不一樣,在Unix/Linux中管道可以作為兩個位于不同空間進程通信的媒介,而在java中,管道只能為同一個JVM進程中的不同線程進行通信。和管道相關的IO類為: PipedInputStreamPipedOutputStream,下面我們來看一個例子:

例9,讀寫管道

public class PipeExample {public static void main(String[] args) throws IOException {final PipedOutputStream output = new PipedOutputStream();final PipedInputStream  input  = new PipedInputStream(output);Thread thread1 = new Thread( new Runnable() {@Overridepublic void run() {try {output.write( "Hello world, pipe!".getBytes());} catch (IOException e) {}}});Thread thread2 = new Thread( new Runnable() {@Overridepublic void run() {try {int data = input.read();while( data != -1){System. out.print(( char) data);data = input.read();}} catch (IOException e) {} finally{try {input.close();} catch (IOException e) {e.printStackTrace();}}}});thread1.start();thread2.start();}
}


7、Java IO:網絡媒介

? ? ? ?關于Java IO面向網絡媒介的操作即Java 網絡編程,其核心是Socket,同磁盤操作一樣,java網絡編程對應著兩套API,即Java IO和Java NIO,關于這部分我會準備專門的文章進行介紹。


8、Java IO:BufferedInputStream和BufferedOutputStream

? ? ? ?BufferedInputStream顧名思義,就是在對流進行寫入時提供一個buffer來提高IO效率。在進行磁盤或網絡IO時,原始的InputStream對數據讀取的過程都是一個字節一個字節操作的,而BufferedInputStream在其內部提供了一個buffer,在讀數據時,會一次讀取一大塊數據到buffer中,這樣比單字節的操作效率要高的多,特別是進程磁盤IO和對大量數據進行讀寫的時候。

? ? ? ?使用BufferedInputStream十分簡單,只要把普通的輸入流和BufferedInputStream組合到一起即可。我們把上面的例2改造成用BufferedInputStream進行讀文件,請看下面例子:

例10 ,用緩沖流讀文件

public static void readByBufferedInputStream() throws IOException {File file = new File( "d:/test.txt");byte[] byteArray = new byte[( int) file.length()];//可以在構造參數中傳入buffer大小InputStream is = new BufferedInputStream( new FileInputStream(file),2*1024);int size = is.read( byteArray);System. out.println( "大小:" + size + ";內容:" + new String(byteArray));is.close();
}

? ? ? ?關于如何設置buffer的大小,我們應根據我們的硬件狀況來確定。對于磁盤IO來說,如果硬盤每次讀取4KB大小的文件塊,那么我們最好設置成這個大小的整數倍。因為磁盤對于順序讀的效率是特別高的,所以如果buffer再設置的大寫可能會帶來更好的效率,比如設置成4*4KB或8*4KB。
? ? ? ?還需要注意一點的就是磁盤本身就會有緩存,在這種情況下,BufferedInputStream會一次讀取磁盤緩存大小的數據,而不是分多次的去讀。所以要想得到一個最優的buffer值,我們必須得知道磁盤每次讀的塊大小和其緩存大小,然后根據多次試驗的結果來得到最佳的buffer大小。

? ? ? ?BufferedOutputStream的情況和BufferedInputStream一致,在這里就不多做描述了。


9、Java IO:BufferedReader和BufferedWriter

? ? ? ?BufferedReader、BufferedWriter?的作用基本和BufferedInputStream、BufferedOutputStream一致,具體用法和原理都差不多 ,只不過一個是面向字符流一個是面向字節流。同樣,我們將改造字符流中的例4,給其加上buffer功能,看例子:

public static void readByBufferedReader() throws IOException {File file = new File( "d:/test.txt");// 在字符流基礎上用buffer流包裝,也可以指定buffer的大小Reader reader = new BufferedReader( new FileReader(file),2*1024);char[] byteArray = new char[( int) file.length()];int size = reader.read( byteArray);System. out.println( "大小:" + size + ";內容:" + new String(byteArray));reader.close();
}


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446981.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446981.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446981.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java基礎——Java NIO詳解(二)

一、簡介 在我的上一篇文章Java NIO詳解(一)中介紹了關于標準輸入輸出NIO相關知識, 本篇將重點介紹基于網絡編程NIO(異步IO)。 二、異步IO 異步 I/O 是一種沒有阻塞地讀寫數據的方法。通常,在代碼進行 rea…

Java基礎——Java NIO詳解(一)

一、基本概念 1、I/0簡介 I/O即輸入輸出,是計算機與外界世界的一個借口。IO操作的實際主題是操作系統。在java編程中,一般使用流的方式來處理IO,所有的IO都被視作是單個字節的移動,通過stream對象一次移動一個字節。流IO負責把對象…

MAC上Git安裝與GitHub基本使用

參考鏈接 MAC上Git安裝與GitHub基本使用

Java基礎——深入理解Java線程池

簡介 我們使用線程的時候就去創建一個線程,這樣實現起來非常簡便,但是就會有一個問題: 如果并發的線程數量很多,并且每個線程都是執行一個時間很短的任務就結束了,這樣頻繁創建線程就會大大降低系統的效率,…

密碼機項目安裝軟件時候出現的問題以及對應的解決辦法

Could NOT find Boost (missing: locale) (found version "1.65.1") 使用命令 apt-get install libboost-locale-dev 進行安裝 解決普通用戶cmake版本11,而root用戶版本15,clion對于版本兼容的問題 修改clion里面的toolchain,將其…

Java基礎——線程及并發機制

前言 在Java中,線程是一個很關鍵的名詞,也是很高頻使用的一種資源。那么它的概念是什么呢,是如何定義的,用法又有哪些呢?為何說Android里只有一個主線程呢,什么是工作線程呢。線程又存在并發,并…

密碼機 密鑰管理項目安裝配置 從零開始

安裝gcc 更新sudo apt-get update下載gcc sudo apt-get install gcc參考鏈接 不推薦 安裝g 下載g sudo apt-get install g 安裝make sudo apt -get install make參考鏈接 安裝cmake 下載地址參考鏈接 安裝ssh sudo apt-get install ssh 安裝git和配置 sudo apt-get inst…

Androud 如何有效減少重復代碼

前言 重復的代碼一直都是可維護性的大敵,重構的重要任務之一也就是要去除掉重復的代碼,有效的減少重復代碼,可以大大提高軟件的擴展性。 在Android開發中,很容易產生重復的代碼。因為Android是組件,模板式開發&#xf…

解決在sample文件夾里面寫代碼,在測試的時候因為virtual原因,make編譯報錯

代碼的結構 錯誤顯示 解決辦法 添加一句話,具體的cpp依據情況而定set_source_files_properties(${PROJECT_SOURCE_DIR}/src/sample_storage_test.cpp COMPILE_FLAGS "-Wno-unused-parameter")

Android SharedPreferences總結及優化

一、SharedPreferences簡介 Android 中的 SharedPreferences(后續簡稱SP)是輕量級的數據存儲方式,能夠保存簡單的數據類型,比如 String、int、boolean 值等。應用場合主要是數據比較少的配置信息。其內部是以 XML 結構保存在 /dat…

Java基礎——深入理解ReentrantLock

一、簡介在Java中通常實現鎖有兩種方式,一種是synchronized關鍵字,另一種是Lock。二者其實并沒有什么必然聯系,但是各有各的特點,在使用中可以進行取舍的使用。二、ReentrantLock與synchronized的比較相同點: &#xf…

使用開源的openssl的md5頭文件,實現對于文件的md5代碼

需要安裝openssl的庫 sudo apt-get install opensslsudo apt-get install libssl-dev參考鏈接 代碼 #include "openssl/md5.h" #include <iostream> #include <fstream> #include <iomanip>//#define MAX_DATA_BUFF 1024; //#define MD5_LENGTH…

Android 多進程開發

前言正常情況下&#xff0c;一個apk啟動后只會運行在一個進程中&#xff0c;其進程名為AndroidManifest.xml文件中指定的應用包名&#xff0c;所有的基本組件都會在這個進程中運行。但是如果需要將某些組件&#xff08;如Service、Activity等&#xff09;運行在單獨的進程中&am…

clion中鏈接openssl庫

錯誤顯示 前提條件 apt-get install opensslapt-get install openssl-dev 解決辦法 在CMakeLists.txt文件中加入如下命令link_libraries(crypto) 參考鏈接 無法將openssl庫鏈接到CLion C 程序c - 無法將openssl庫鏈接到CLion C程序

Java中String、StringBuffer、StringBuilder三者的區別

一、簡介String、StringBuffer、StringBuilder三個類之間的區別主要是在兩個方面&#xff1a;運行速度和線程安全。二、區別1、運行速度&#xff0c;或者說是執行速度在這方面運行速度快慢為&#xff1a;StringBuilder > StringBuffer > String StringString為字符串常量…

Ubuntu環境下,使用clion編譯器,使用開源opensll的對稱AES算法對于文件進行加密,C++代碼

前提準備條件 需要安裝openssl需要安裝openssl-dev需要配置CMakeLists.txt文件集體內容可以參考我提供的相關參考鏈接 AES_file.h #include <openssl/aes.h> #include <iostream> #include <fstream> #include <cstring>#define RELEASE_ARRAY(P) if…

Java提高篇 —— Java關鍵字之static的四種用法

一、前言 在java的關鍵字中&#xff0c;static和final是兩個我們必須掌握的關鍵字。不同于其他關鍵字&#xff0c;他們都有多種用法&#xff0c;而且在一定環境下使用&#xff0c;可以提高程序的運行性能&#xff0c;優化程序的結構。下面我們先來了解一下static關鍵字及其用法…

C++ 使用move來刪除用戶指定的文件

代碼 #include <iostream>bool remove_file(std::string path){if (remove(path.c_str())0){std::cout << "success!" << std::endl;}else{std::cout << "False!" << std::endl;} } int main() {std::string path "/…

Java提高篇 —— Java關鍵字之final的幾種用法

一、前言 在java的關鍵字中&#xff0c;static和final是兩個我們必須掌握的關鍵字。不同于其他關鍵字&#xff0c;他們都有多種用法&#xff0c;而且在一定環境下使用&#xff0c;可以提高程序的運行性能&#xff0c;優化程序的結構。下面我們來了解一下final關鍵字及其用法。 …