JAVA打怪之路 - IO流

IO流

IO流是Java處理設備之間的數據傳輸的重要方式,文件的讀取和寫入實現數據的獲取和存儲,按照不同的劃分標準流可以分爲輸入流和輸出流、字節流和字符流,節點流和處理流。系統的學習IO流的原理對於數據的寫入和寫出有很重要的作用。同時這也是菜鳥級別的程序員慢慢走向成熟的表現,慢慢理解編程的概念,伴隨着知識的積累,逐漸積攢開發經驗。

一、File 類的使用

① File類介紹:
在這裏插入圖片描述
② File類常用構造器:
在這裏插入圖片描述
③ 路徑分隔符:
在這裏插入圖片描述
④ File類常用方法
在這裏插入圖片描述
在這裏插入圖片描述
二、IO流原理及流的分類

① IO流的原理

1.1 I/O是Input/Output的縮寫,用於處理設備之間的數據傳輸。
1.2 Java程序中,對於數據的輸入/輸出操作以“流(stream)” 的方式進行。
1.3 java.io包下提供了各種“流”類和接口,用以獲取不同種類的數據。

② IO流的分類
在這裏插入圖片描述
③ IO流體系
在這裏插入圖片描述

三、IO流基類概述(inputStream、Reader、outputStream、Writer)

① InputStream & Reader
在這裏插入圖片描述
② OutputStream & Writer
在這裏插入圖片描述
四、節點流 (文件流) (FileInputStream、FileoutputStream、FileReader、FileWriter)

① 讀取文件

//1.建立一個流對象,將已存在的一個文件加載進流。
FileReader fr = new FileReader(new File(“Test.txt”));
//2.創建一個臨時存放數據的數組。
char[] ch = new char[1024];
//3.調用流對象的讀取方法將流中的數據讀入到數組中。
fr.read(ch);
//4. 關閉資源。
fr.close();

② 寫入文件

//1.創建流對象,建立數據存放文件
FileWriter fw = new FileWriter(new File(“Test.txt”));
//2.調用流對象的寫入方法,將數據寫入流
fw.write(“atguigu-songhongkang”);
//3.關閉流資源,並將流中的數據清空到文件中。
fw.close();

③ 節點流 ( 文件流 ) 注意點
在這裏插入圖片描述
五、緩衝流( BufferedInput(output)Stream、BufferedReader 、BufferedWriter )
在這裏插入圖片描述
在這裏插入圖片描述
代碼示例:

BufferedReader br = null;
BufferedWriter bw = null;
try {
    // 創建緩衝流對象:它是處理流,是對節點流的包裝
    br = new BufferedReader(new FileReader("d:\\IOTest\\source.txt"));
    bw = new BufferedWriter(new FileWriter("d:\\IOTest\\dest.txt"));
    String str;
    while ((str = br.readLine()) != null) { // 一次讀取字符文本文件的一行字符
        bw.write(str); // 一次寫入一行字符串
        bw.newLine(); // 寫入行分隔符
    }
    bw.flush(); // 刷新緩衝區
} catch (IOException e) {
    e.printStackTrace();
} finally {
    // 關閉IO流對象
    try {
        if (bw != null) {
            bw.close(); // 關閉過濾流時,會自動關閉它所包裝的底層節點流
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        if (br != null) {
            br.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

六、轉換流 (InputStreamReader、OutputStreamWriter)
①  InputStreamReader
代碼示例:

public void testMyInput() throws Exception {
    FileInputStream fis = new FileInputStream("dbcp.txt");
    FileOutputStream fos = new FileOutputStream("dbcp5.txt");
    InputStreamReader isr = new InputStreamReader(fis, "GBK");
    OutputStreamWriter osw = new OutputStreamWriter(fos, "GBK");
    BufferedReader br = new BufferedReader(isr);
    BufferedWriter bw = new BufferedWriter(osw);
    String str = null;
    while ((str = br.readLine()) != null) {
        bw.write(str);
        bw.newLine();
        bw.flush();
    }
    bw.close();
    br.close();
}

七、標準輸入、輸出流(System.in、System.out)
在這裏插入圖片描述
代碼示例:

System.out.println("請輸入信息(退出輸入e或exit):");
// 把"標準"輸入流(鍵盤輸入)這個字節流包裝成字符流,再包裝成緩衝流
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = null;
try {
    while ((s = br.readLine()) != null) { // 讀取用戶輸入的一行數據 --> 阻塞程序
        if ("e".equalsIgnoreCase(s) || "exit".equalsIgnoreCase(s)) {
            System.out.println("安全退出!!");
            break;
        }
        // 將讀取到的整行字符串轉成大寫輸出
        System.out.println("-->:" + s.toUpperCase());
        System.out.println("繼續輸入信息");
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    try {
        if (br != null) {
            br.close(); // 關閉過濾流時,會自動關閉它包裝的底層節點流
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

八、打印流( PrintStream、PrintWriter )
在這裏插入圖片描述
代碼示例:

PrintStream ps = null;
try {
    FileOutputStream fos = new FileOutputStream(new File("D:\\IO\\text.txt"));
    // 創建打印輸出流,設置爲自動刷新模式(寫入換行符或字節 '\n' 時都會刷新輸出緩衝區)
    ps = new PrintStream(fos, true);
    if (ps != null) {// 把標準輸出流(控制檯輸出)改成文件
        System.setOut(ps);
    }
    for (int i = 0; i <= 255; i++) { // 輸出ASCII字符
        System.out.print((char) i);
        if (i % 50 == 0) { // 每50個數據一行
            System.out.println(); // 換行
        }
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} finally {
    if (ps != null) {
        ps.close();
    }
}

九、數據流(DataInputStream、DataOutputStream)
在這裏插入圖片描述
代碼示例:

DataOutputStream dos = null;
try { // 創建連接到指定文件的數據輸出流對象
    dos = new DataOutputStream(new FileOutputStream("destData.dat"));
    dos.writeUTF("我愛北京天安門"); // 寫UTF字符串
    dos.writeBoolean(false); // 寫入布爾值
    dos.writeLong(1234567890L); // 寫入長整數
    System.out.println("寫文件成功!");
} catch (IOException e) {
    e.printStackTrace();
} finally { // 關閉流對象
    try {
        if (dos != null) {
        // 關閉過濾流時,會自動關閉它包裝的底層節點流
        dos.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}
DataInputStream dis = null;
try {
    dis = new DataInputStream(new FileInputStream("destData.dat"));
    String info = dis.readUTF();
    boolean flag = dis.readBoolean();
    long time = dis.readLong();
    System.out.println(info);
    System.out.println(flag);
    System.out.println(time);
} catch (Exception e) {
    e.printStackTrace();
} finally {
    if (dis != null) {
        try {
            dis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

十、對象流( ObjectInputStream、OjbectOutputSteam )
在這裏插入圖片描述
在這裏插入圖片描述
序列化和反序列化實例:

//序列化:將對象寫入到磁盤或者進行網絡傳輸。
//要求對象必須實現序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“data.txt"));
Person p = new Person("韓梅梅", 18, "中華大街", new Pet());
oos.writeObject(p);
oos.flush();
oos.close();

//反序列化:將磁盤中的對象數據源讀出。
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(“data.txt"));
Person p1 = (Person)ois.readObject();
System.out.println(p1.toString());
ois.close();

面試題: 談談你對java.io.Serializable接口的理解,我們知道它用於序列化,是空方法接口,還有其它認識嗎?

答:
① 實現了Serializable接口的對象,可將它們轉換成一系列字節,並可在以後完全恢復回原來的樣子。這一過程亦可通過網絡進行。這意味着序列化機制能自動補償操作系統間的差異。換句話說,可以先在Windows機器上創建一個對象,對其序列化,然後通過網絡發給一臺Unix機器,然後在那裏準確無誤地重新“裝配”。不必關心數據在不同機器上如何表示,也不必關心字節的順序或者其他任何細節。

② 由於大部分作爲參數的類如String、Integer等都實現了java.io.Serializable的接口,也可以利用多態的性質,作爲參數使接口更靈活。

十一、隨機存取文件流(RandomAccessFile)
在這裏插入圖片描述

RandomAccessFile使用:

  1. RandomAccessFile直接繼承於java.lang.Object類,實現了DataInput和DataOutput接口。
  2. RandomAccessFile既可以作爲一個輸入流,又可以作爲一個輸出流。
  3. 如果RandomAccessFile作爲輸出流時,寫出到的文件如果不存在,則在執行過程中自動創建。如果寫出到的文件存在,則會對原有文件內容進行覆蓋。(默認情況下,從頭覆蓋)
  4. 可以通過相關的操作,實現RandomAccessFile“插入”數據的效果。

在這裏插入圖片描述
實例1: 讀取文件內容

RandomAccessFile raf = new RandomAccessFile(“test.txt”, “rw”);
raf.seek(5);
byte [] b = new byte[1024];
int off = 0;
int len = 5;
raf.read(b, off, len);
String str = new String(b, 0, len);
System.out.println(str);
raf.close();

實例2: 寫入文件內容

RandomAccessFile raf = new RandomAccessFile("test.txt", "rw");
raf.seek(5);
//先讀出來
String temp = raf.readLine(); 
raf.seek(5);
raf.write("xyz".getBytes());
raf.write(temp.getBytes());
raf.close();

實例3: 使用RandomAccessFile實現數據的插入效果

@Test
public void test3() throws IOException {
    RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");
    raf1.seek(3);//將指針調到角標爲3的位置
    //保存指針3後面的所有數據到StringBuilder中
    StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
    byte[] buffer = new byte[20];
    int len;
    while((len = raf1.read(buffer)) != -1){
        builder.append(new String(buffer,0,len)) ;
    }
    //調回指針,寫入“xyz”
    raf1.seek(3);
    raf1.write("xyz".getBytes());

    //將StringBuilder中的數據寫入到文件中
    raf1.write(builder.toString().getBytes());
    raf1.close();
}

十二、NIO.2中Path、Paths、Files類的使用

① Java NIO 概述
在這裏插入圖片描述
② Path、Paths和Files核心API
在這裏插入圖片描述
③ Path接口常用方法
在這裏插入圖片描述
④ Files類常用方法
在這裏插入圖片描述
在這裏插入圖片描述
實例一:Path常用方法實例

//Path中的常用方法
    @Test
    public void test2() {
        //實例化Path
        Path path1 = Paths.get("d:\\", "nio\\nio1\\nio2\\hello.txt");
        Path path2 = Paths.get("hello.txt");

//    String toString() : 返回調用 Path 對象的字符串表示形式
        System.out.println(path1);

//    boolean startsWith(String path) : 判斷是否以 path 路徑開始
        System.out.println(path1.startsWith("d:\\nio"));
//    boolean endsWith(String path) : 判斷是否以 path 路徑結束
        System.out.println(path1.endsWith("hello.txt"));
//    boolean isAbsolute() : 判斷是否是絕對路徑
        System.out.println(path1.isAbsolute() + "~");
        System.out.println(path2.isAbsolute() + "~");
//    Path getParent() :返回Path對象包含整個路徑,不包含 Path 對象指定的文件路徑
        System.out.println(path1.getParent());
        System.out.println(path2.getParent());
//    Path getRoot() :返回調用 Path 對象的根路徑
        System.out.println(path1.getRoot());
        System.out.println(path2.getRoot());
//    Path getFileName() : 返回與調用 Path 對象關聯的文件名
        System.out.println(path1.getFileName() + "~");
        System.out.println(path2.getFileName() + "~");
//    int getNameCount() : 返回Path 根目錄後面元素的數量
//    Path getName(int idx) : 返回指定索引位置 idx 的路徑名稱
        for (int i = 0; i < path1.getNameCount(); i++) {
            System.out.println(path1.getName(i) + "*****");
        }

//    Path toAbsolutePath() : 作爲絕對路徑返回調用 Path 對象
        System.out.println(path1.toAbsolutePath());
        System.out.println(path2.toAbsolutePath());
//    Path resolve(Path p) :合併兩個路徑,返回合併後的路徑對應的Path對象
        Path path3 = Paths.get("d:\\", "nio");
        Path path4 = Paths.get("nioo\\hi.txt");
        path3 = path3.resolve(path4);
        System.out.println(path3);

//    File toFile(): 將Path轉化爲File類的對象
        File file = path1.toFile();//Path--->File的轉換
        Path newPath = file.toPath();//File--->Path的轉換
    }

附錄1: FIles工具類的使用

@Test
   public void test1() throws IOException{
      Path path1 = Paths.get("d:\\nio", "hello.txt");
      Path path2 = Paths.get("atguigu.txt");
      
//    Path copy(Path src, Path dest, CopyOption … how) : 文件的複製
      //要想複製成功,要求path1對應的物理上的文件存在。path1對應的文件沒有要求。
//    Files.copy(path1, path2, StandardCopyOption.REPLACE_EXISTING);
      
//    Path createDirectory(Path path, FileAttribute<?> … attr) : 創建一個目錄
      //要想執行成功,要求path對應的物理上的文件目錄不存在。一旦存在,拋出異常。
      Path path3 = Paths.get("d:\\nio\\nio1");
//    Files.createDirectory(path3);
      
//    Path createFile(Path path, FileAttribute<?> … arr) : 創建一個文件
      //要想執行成功,要求path對應的物理上的文件不存在。一旦存在,拋出異常。
      Path path4 = Paths.get("d:\\nio\\hi.txt");
//    Files.createFile(path4);
      
//    void delete(Path path) : 刪除一個文件/目錄,如果不存在,執行報錯
//    Files.delete(path4);
      
//    void deleteIfExists(Path path) : Path對應的文件/目錄如果存在,執行刪除.如果不存在,正常執行結束
      Files.deleteIfExists(path3);
      
//    Path move(Path src, Path dest, CopyOption…how) : 將 src 移動到 dest 位置
      //要想執行成功,src對應的物理上的文件需要存在,dest對應的文件沒有要求。
//    Files.move(path1, path2, StandardCopyOption.ATOMIC_MOVE);
      
//    long size(Path path) : 返回 path 指定文件的大小
      long size = Files.size(path2);
      System.out.println(size);

   }

   @Test
   public void test2() throws IOException{
      Path path1 = Paths.get("d:\\nio", "hello.txt");
      Path path2 = Paths.get("atguigu.txt");
//    boolean exists(Path path, LinkOption … opts) : 判斷文件是否存在
      System.out.println(Files.exists(path2, LinkOption.NOFOLLOW_LINKS));

//    boolean isDirectory(Path path, LinkOption … opts) : 判斷是否是目錄
      //不要求此path對應的物理文件存在。
      System.out.println(Files.isDirectory(path1, LinkOption.NOFOLLOW_LINKS));

//    boolean isRegularFile(Path path, LinkOption … opts) : 判斷是否是文件

//    boolean isHidden(Path path) : 判斷是否是隱藏文件
      //要求此path對應的物理上的文件需要存在。纔可判斷是否隱藏。否則,拋異常。
//    System.out.println(Files.isHidden(path1));

//    boolean isReadable(Path path) : 判斷文件是否可讀
      System.out.println(Files.isReadable(path1));
//    boolean isWritable(Path path) : 判斷文件是否可寫
      System.out.println(Files.isWritable(path1));
//    boolean notExists(Path path, LinkOption … opts) : 判斷文件是否不存在
      System.out.println(Files.notExists(path1, LinkOption.NOFOLLOW_LINKS));
   }

   /**
    * StandardOpenOption.READ:表示對應的Channel是可讀的。
    * StandardOpenOption.WRITE:表示對應的Channel是可寫的。
    * StandardOpenOption.CREATE:如果要寫出的文件不存在,則創建。如果存在,忽略
    * StandardOpenOption.CREATE_NEW:如果要寫出的文件不存在,則創建。如果存在,拋異常
    *
    */
   @Test
   public void test3() throws IOException{
      Path path1 = Paths.get("d:\\nio", "hello.txt");

//    InputStream newInputStream(Path path, OpenOption…how):獲取 InputStream 對象
      InputStream inputStream = Files.newInputStream(path1, StandardOpenOption.READ);

//    OutputStream newOutputStream(Path path, OpenOption…how) : 獲取 OutputStream 對象
      OutputStream outputStream = Files.newOutputStream(path1, StandardOpenOption.WRITE,StandardOpenOption.CREATE);


//    SeekableByteChannel newByteChannel(Path path, OpenOption…how) : 獲取與指定文件的連接,how 指定打開方式。
      SeekableByteChannel channel = Files.newByteChannel(path1, StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);

//    DirectoryStream<Path>  newDirectoryStream(Path path) : 打開 path 指定的目錄
      Path path2 = Paths.get("e:\\teach");
      DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path2);
      Iterator<Path> iterator = directoryStream.iterator();
      while(iterator.hasNext()){
         System.out.println(iterator.next());
      }
   }

附錄2: FileUtils類

1.//拷貝文件 --這裏會覆蓋--而非追加

File src = new File("D:\\workspace\\j2ee\\mycommon\\src\\com\\commons\\io\\abc.txt");  

 File dest = new File("D:\\workspace\\j2ee\\mycommon\\src\\com\\commons\\io\\abcd.txt"); 

FileUtils.copyFile(src, dest);

2.//拷貝文件到某一路徑  

File src = new File("D:\\workspace\\j2ee\\mycommon\\src\\com\\commons\\io\\abcd.txt");  

File dir = new File("D:\\");  

 FileUtils.copyFileToDirectory(src, dir); 

3.//寫字符串到一個文件--此種爲覆蓋的方法  

String string = "Blah blah blah";  

File dest = new File("D:\\workspace\\j2ee\\mycommon\\src\\com\\commons\\io\\abcd.txt");  

FileUtils.writeStringToFile(dest, string, "ISO-8859-1"); 

4. 刪除文件實例

File file = new File( ("D:\\workspace\\j2ee\\mycommon\\src\\com\\commons\\io\\abcd.txt") );  

 FileUtils.forceDelete(file);  

5. 讀取文件每一行數據的功能

File file = new File("D:\\workspace\\j2ee\\mycommon\\src\\com\\commons\\io\\abc.txt");  

       List lines = FileUtils.readLines(file, "UTF-8");  

    for(int i=0;i<lines.size();i++)  {        

System.out.println(lines.get(i));

}```

##IOUtils類
IOUtils主要提供更便捷的操作流的方法
主要方法
toXxx/read- these methods read data from a stream       
write -these methods write data to a stream        
copy -these methods copy all the data from one stream to another
contentEquals- these methods compare the content of two streams
```java
1.比較兩個輸入流的內容是否相等 
 IOUtils.contentEquals(InputStream input1, InputStream input2)

(URLurl = new URL(url);

InputStream is = url.openStream();ur的內容讀出來)

InputStream in = new URL("http://www.apache.org").openStream();  

 InputStream in2 = new URL("http://www.apache.org").openStream(); 

IOUtils.contentEquals(in, in2)

IOUtils.toString將緩衝區的內容以utf-8的編碼方式以字符串的形式輸出 

2.將字節從 InputStream複製到OutputStream中

IOUtils.copy(InputStream input, OutputStream output) 

ByteArrayOutputStream out = **new** ByteArrayOutputStream();  

        IOUtils.copy(in2, out); 

3.返回一個裝有輸入字節行數的Iterator對象,使用特定的字符編碼(如果沒用聲明的話則用默認編碼)

IOUtils.lineIterator(InputStream input, Charset encoding)

InputStream in3 = **new** URL("http://www.apache.org").openStream();  

        try {  

               LineIterator it = IOUtils.lineIterator(in3, "UTF-8");  

               System.out.println(it.hasNext());  

               if (it.hasNext()) {  

                 String line = it.nextLine();  

                 //System.out.println(line);  

               }  

        } finally {  

               IOUtils.closeQuietly(in);  

        }  

4、從輸入流中讀取字節(通常返回輸入流的字節數組的長度) 

IOUtils.read(InputStream input, byte[] buffer) 

 InputStream in4 = new URL("http://www.apache.org").openStream();  

        byte[] buffer = new byte[100000];  

        System.out.println(IOUtils.read(in4, buffer));

5、獲得輸入流的內容放回一個List<String>類型的容器,每一行爲這個容器的一個入口,使用特定的字符集(如果爲空就使用默認的字符集)

 IOUtils.readLines(InputStream input, Charset encoding)

 InputStream in5 = new URL("http://www.apache.org").openStream();  

        List<String> list = IOUtils.readLines(in5, "UTF-8");  

        Iterator<String> iter = list.iterator();  

        while(iter.hasNext()){  
            String s =  iter.next();  
            //System.out.println(s);  
        }

好了,JAVA IO 流就是這麼多的知識了,積少成多,我們首先要理解各自的基礎知識,厚積薄發,慢慢的弄懂其中的原理,終將可簡化開發,實現程序員之夢。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章