程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java編程那些事兒92——IO使用注意問題

Java編程那些事兒92——IO使用注意問題

編輯:關於JAVA

11.3.4 注意問題

上面介紹了IO類的基本使用,熟悉了實體流和裝飾流的基本使用,但是在IO類實際使用時,還是會遇到一系列的問題,下面介紹一些可能會經常遇到的問題。

11.3.4.1 類的選擇

對於初次接觸IO技術的初學者來說,IO類體系博大精深,類的數量比較龐大,在實際使用時經常會無所適從,不知道該使用那些類進行編程,下面介紹一下關於IO類選擇的一些技巧。

選擇類的第一步是選擇合適的實體流。

選擇實體流時第一步是按照連接的數據源種類進行選擇,例如讀寫文件應該使用文件流,如FileInputStream/FileOutputStream、FileReader/FileWriter,讀寫字節數組應該使用字節數組流等,如ByteArrayInputStream/ByteArrayOutputStream。

選擇實體流時第二步是選擇合適方向的流。例如進行讀操作時應該使用輸入流,進行寫操作時應該使用輸出流。

選擇實體流時第三步是選擇字節流或字符流。除了讀寫二進制文件,或字節流中沒有對應的流時,一般都優先選擇字符流。

經過以上步驟以後,就可以選擇到合適的實體流了。下面說一下裝飾流的選擇問題。

在選擇IO類時,實體流是必需的,裝飾流是可選的。另外在選擇流時實體流只能選擇一個,而裝飾流可以選擇多個。

選擇裝飾流時第一步是選擇符合要求功能的流。例如需要緩沖流的話選擇BufferedReader/BufferedWriter等,有些時候也可能只是為了使用某個裝飾流內部提供的方法。

選擇裝飾流時第二步是選擇合適方向的流,這個和實體流選擇中的第二步一致。

當選擇了多個裝飾流以後,可以使用流之間的多層嵌套實現要求的功能,流的嵌套之間沒有順序。

11.3.4.2  非依次讀取流數據

由於IO類設計的特點,在實際讀取時,只能依次讀取流中的數據,而且在通常情況下,已經讀取過的數據無法再進行讀取。如果需要重復讀取流中某段數據時,一般的做法是將從流中讀取的數據使用數組存儲起來,然後根據需要讀取數組中的內容即可,但是有些時候,還是有一些特殊的情況的,IO類對於這些都進行了支持。

1、間斷性的讀取流中的數據

對於某些特殊格式的文件,例如字體文件等,在實際讀取數據時不需要順序進行讀取,而只需要根據內容的位置進行讀取。這樣可以使用流中的skip方法實現。例如:

int n = fis.skip(100);

該行代碼的作用是,以流fis當前位置為基礎,當前位置可以是流中的任何位置,向後跳過100個單位(字節流單位為字節,字符流單位是字符),如果再使用read方法繼續讀取,就是讀取跳躍以後新位置的內容,也就相當於跳過了100個單位的內容。

而實際在使用時,實際真正跳過的單位數量作為skip方法的返回值返回。

2、重復讀取流中某段數據

當必須重復讀取流中同一段數據時,如果對應的流支持mark(標記)的話,則可以重復讀取同一段數據。

下面以重復讀取控制台輸入流System.in為例子,來介紹mark的使用,示例代碼如下:

import java.io.*;
/**
* mark使用示例
*/
public class MarkUseDemo {
 public static void main(String[] args) {
  byte[] b = new byte[1024];
  try{
   //讀取數據
   int data = System.in.read();
   //輸出第一個字節的數據
   System.out.println("第一個字節:" + data);
   //判斷該流是否支持mark
   if(System.in.markSupported()){
    //記憶當前位置,可以從當前位置
    //向後最多讀取100個字節
    System.in.mark(100);
    //讀取數據
    int n = System.in.read(b);
    //輸出讀取到的內容
    System.out.print("第一次讀取到的內容:");
    for(int i = 0;i < n;i++){
     System.out.print(b[i] + " ");
    }
    System.out.println();
    //回到標記位置
    System.in.reset();
    //重復讀取標記位置以後的內容
    n = System.in.read(b);
    //輸出讀取到的內容
    System.out.print("第二次讀取到的內容:");
    for(int i = 0;i < n;i++){
     System.out.print(b[i] + " ");
    }
    System.out.println();
   }
  }catch(Exception e){
    e.printStackTrace();
  }
 }
}

在該示例中,首先調用System.in流中的read方法,讀取流中的第一個字節,並把讀取到的數據賦值給data,然後將讀取到的第一個字節的數據輸出出來。

然後調用System.in流中的markSupported判斷該流是否支持mark功能,如果支持的話則markSupported方法將返回true。

如果流System.in支持mark,則標記當前位置,並允許從當前位置開始最多讀取後續100個字節的數據,其實IO類內部的只讀取這些數據,而不真正從流中將這些數據刪除。

後續繼續讀取流中的數據,如果讀取的數據超過100個字節,則mark標記失效,並把讀取到的有效數據輸出到控制台。

如果需要從標記位置重復讀取已經讀取過的數據,則只需要調用流對象中的reset方法重置流的位置,使流可以回到mark的位置,如果繼續讀取的話,則從該位置開始可以向後讀取。這樣就可以從mark的位置開始,再次讀取後續的數據了。

例如在控制台輸入123456789,則該程序的執行結果是:

第一個字節:49

第一次讀取到的內容:50 51 52 53 54 55 56 57 13 10

第二次讀取到的內容:50 51 52 53 54 55 56 57 13 10

其中輸入的第一個字節是1,讀取時該字符的編碼是49,而後續的內容就是流的結構,其中流末尾的13和10是在輸入時,添加的回車和換行字符。

11.3.4.3 中文問題

由於JDK設計時,對於國際化支持比較好,所以JDK在實際實現時支持很多的字符集,這樣在進行特定字符集的處理時就需要特別小心了。

其實在進行中文處理時,只需要注意一個原則就可以了,這個原則就是將中文字符轉換為byte數組時使用的字符集,需要和把byte數組轉換為中文字符串時的字符集保持一致,這樣就不會出現中文問題了。

當然,如果不想手動實現字符串和byte數組的轉換,可以使用DataInputStream和DataOutputStream中的readUTF和writeUTF實現讀寫字符串。

11.4 總結

關於IO類的使用,還需要在實際開發過程中多進行使用,從而更深入的體會IO類設計的初衷,並掌握IO類的使用。

另外,IO類是Java中進行網絡編程的基礎,所以熟悉IO類的使用也是學習網絡編程必須的一個基礎。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved