1. 程式人生 > >Java學習筆記10--位元組流 ;字元流 ;序列流 ;物件的輸入輸出流;Properties(配置檔案類);列印流;編碼

Java學習筆記10--位元組流 ;字元流 ;序列流 ;物件的輸入輸出流;Properties(配置檔案類);列印流;編碼

∆ 位元組流、字元流

∆ SequenceInputStream(序列流)

序列流,對多個流進行合併。
SequenceInputStream 表示其他輸入流的邏輯串聯。它從輸入流的有序集合開始,並從第一個輸入流開始讀取,直到到達檔案末尾,接著從第二個輸入流讀取,依次類推,直到到達包含的最後一個輸入流的檔案末尾為止。

需求:的內容合併

public class Demo1 {

    public static void main(String[] args) throws IOException {
        merge3();
    }

    //把三個檔案合併成一個檔案
public static void merge3() throws IOException{ //找到目標檔案 File file1 = new File("F:\\a.txt"); File file2 = new File("F:\\b.txt"); File file3 = new File("F:\\c.txt"); File file4 = new File("F:\\d.txt"); //建立對應 的輸入輸出流物件 FileOutputStream fileOutputStream = new
FileOutputStream(file4); FileInputStream fileInputStream1 = new FileInputStream(file1); FileInputStream fileInputStream2 = new FileInputStream(file2); FileInputStream fileInputStream3 = new FileInputStream(file3); //建立序列流物件 Vector<FileInputStream> vector = new
Vector<FileInputStream>(); vector.add(fileInputStream1); vector.add(fileInputStream2); vector.add(fileInputStream3); Enumeration<FileInputStream> e = vector.elements(); SequenceInputStream sequenceInputStream = new SequenceInputStream(e); //讀取檔案資料 byte[] buf = new byte[1024]; int length = 0; while((length = sequenceInputStream.read(buf))!=-1){ fileOutputStream.write(buf,0,length); } //關閉資源 sequenceInputStream.close(); fileOutputStream.close(); } // 使用SequenceInputStream合併檔案。 public static void merge2() throws IOException{ //找到目標檔案 File inFile1 = new File("F:\\a.txt"); File inFile2 = new File("F:\\b.txt"); File outFile = new File("F:\\c.txt"); //建立資料的輸入輸出通道 FileOutputStream fileOutputStream = new FileOutputStream(outFile); FileInputStream fileInputStream1 = new FileInputStream(inFile1); FileInputStream fileInputStream2 = new FileInputStream(inFile2); //建立序列流物件 SequenceInputStream inputStream = new SequenceInputStream(fileInputStream1,fileInputStream2); byte[] buf = new byte[1024]; int length = 0 ; while((length = inputStream.read(buf))!=-1){ fileOutputStream.write(buf,0,length); } //關閉資源 inputStream.close(); fileOutputStream.close(); } //需求:把a.txt與b.txt 檔案的內容合併。 public static void merge1() throws IOException{ //找到目標檔案 File inFile1 = new File("F:\\a.txt"); File inFile2 = new File("F:\\b.txt"); File outFile = new File("F:\\c.txt"); //建立資料的輸入輸出通道 FileOutputStream fileOutputStream = new FileOutputStream(outFile); FileInputStream fileInputStream1 = new FileInputStream(inFile1); FileInputStream fileInputStream2 = new FileInputStream(inFile2); //把輸入流儲存到集合中,然後再從集合中讀取 ArrayList<FileInputStream> list = new ArrayList<FileInputStream>(); list.add(fileInputStream1); list.add(fileInputStream2); //準備一個緩衝陣列 byte[] buf = new byte[1024]; int length = 0 ; for(int i = 0 ; i< list.size() ; i++){ FileInputStream fileInputStream = list.get(i); while((length = fileInputStream.read(buf))!=-1){ fileOutputStream.write(buf,0,length); } //關閉資源 fileInputStream.close(); } fileOutputStream.close(); } }

舉例Demo: 需求: 把一首mp3先切割成n份,然後再把這些檔案合併起來。

public class Demo2 {
    public static void main(String[] args) throws IOException {
//      cutFile();
        mergeFlile();
    }
    //合併
    public static void mergeFlile() throws IOException{
        //找到目標檔案
        File dir = new File("F:\\music");
        //通過目標資料夾找到所有的MP3檔案,然後把所有的MP3檔案新增到vector中。
        Vector<FileInputStream> vector = new Vector<FileInputStream>();
        File[] files = dir.listFiles();
        for(File file : files){
            if(file.getName().endsWith(".mp3")){
                vector.add(new FileInputStream(file));
            }
        }
        //通過Vector獲取迭代器
        Enumeration<FileInputStream> e = vector.elements();
        //建立序列流
        SequenceInputStream inputStream = new SequenceInputStream(e);
        //建立檔案的輸出通道
        FileOutputStream fileOutputStream = new FileOutputStream("F:\\合併.mp3");
        //建立緩衝陣列讀取檔案
        byte[] buf = new byte[1024];
        int length = 0 ; 
        while((length =  inputStream.read(buf))!=-1){
            fileOutputStream.write(buf,0,length);
        }
        //關閉資源
        fileOutputStream.close();
        inputStream.close();    
    }
    //切割MP3
    public static void cutFile() throws IOException{
        File file = new File("F:\\美女\\1.mp3");
        //目標資料夾
        File dir = new File("F:\\music");
        //建立資料的輸入通道
        FileInputStream fileInputStream = new FileInputStream(file);
        //建立緩衝陣列讀取
        byte[] buf = new byte[1024*1024];
        int length = 0;
        for(int i = 0 ;  (length = fileInputStream.read(buf))!=-1 ; i++){
            FileOutputStream fileOutputStream = new FileOutputStream(new File(dir,"part"+i+".mp3"));
            fileOutputStream.write(buf,0,length);
            fileOutputStream.close();
        }
        //關閉資源
        fileInputStream.close();
    }
}

∆ 物件的輸入輸出流

當建立物件時,程式執行時它就會存在,但是程式停止時,物件也就消失了.但是如果希望物件在程式不執行的情況下仍能存在並儲存其資訊,將會非常有用,物件將被重建並且擁有與程式上次執行時擁有的資訊相同。可以使用物件的序列化。

物件的序列化: 將記憶體中的物件直接寫入到檔案裝置中
物件的反序列化: 將檔案裝置中持久化的資料轉換為記憶體物件

基本的序列化由兩個方法產生:一個方法用於序列化物件並將它們寫入一個流,另一個方法用於讀取流並反序列化物件。

ObjectOutput
writeObject(Object obj) 
          將物件寫入底層儲存或流。

ObjectInput
readObject() 
          讀取並返回物件。

ObjectOutputStream的使用步驟:

物件輸入輸出流要注意的細節:

  • 如果物件需要被寫出到檔案上,那麼物件所屬的類必須要實現Serializable介面。 Serializable介面沒有任何的方法,是一個標識介面而已。
  • 物件的反序列化建立物件的時候並不會呼叫到構造方法的、
  • serialVersionUID 是用於記錄class檔案的版本資訊的,serialVersionUID這個數字是通過一個類的類名、成員、包名、工程名算出的一個數字。
  • 使用ObjectInputStream反序列化的時候,ObjeectInputStream會先讀取檔案中的serialVersionUID,然後與本地的class檔案的serialVersionUID進行對比,如果這兩個id不一致,那麼反序列化就失敗了。
  • 如果序列化與反序列化的時候可能會修改類的成員,那麼最好一開始就給這個類指定一個serialVersionUID,如果一類已經指定的serialVersionUID,然後在序列化與反序列化的時候,jvm都不會再自己算這個 class的serialVersionUID了。
  • 如果一個物件某個資料不想被序列化到硬碟上,可以使用關鍵字transient修飾。
  • 如果一個類維護了另外一個類的引用,那麼另外一個類也需要實現Serializable介面。
    程式碼舉例:
class Address implements Serializable{

    String country; 

    String city;

    public Address(String country,String city){
        this.country = country;
        this.city = city;
    }

}

class User implements Serializable{

    private static final long serialVersionUID = 1L;

    String userName ;

    String password;

    transient int age;  // transient 透明

    Address address ;
    public User(String userName , String passwrod) {
        this.userName = userName;
        this.password = passwrod;
    }
    public User(String userName , String passwrod,int age,Address address) {
        this.userName = userName;
        this.password = passwrod;
        this.age = age;
        this.address = address;
    }

    @Override
    public String toString() {
        return "使用者名稱:"+this.userName+ " 密碼:"+ this.password+" 年齡:"+this.age+" 地址:"+this.address.city;
    }
}

public class Demo3 {

    public static void main(String[] args) throws IOException, Exception {
        writeObj();
//      readObj();
    }

    //把檔案中的物件資訊讀取出來-------->物件的反序列化
    public static void readObj() throws  IOException, ClassNotFoundException{
        //找到目標檔案
        File file = new File("F:\\obj.txt");
        //建立資料的輸入通道
        FileInputStream fileInputStream = new FileInputStream(file);
        //建立物件的輸入流物件
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        //讀取物件資訊
        User user = (User) objectInputStream.readObject(); //建立物件肯定要依賴物件所屬 的class檔案。
        System.out.println("物件的資訊:"+ user);
    }
    //定義方法把物件的資訊寫到硬碟上------>物件的序列化。
    public static void writeObj() throws IOException{
        //把user物件的資訊持久化儲存。
        Address address = new Address("中國","廣州");
        User user = new User("admin","123",15,address);
        //找到目標檔案
        File file = new File("F:\\obj.txt");
        //建立資料輸出流物件
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        //建立物件的輸出流物件
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        //把物件寫出
        objectOutputStream.writeObject(user);
        //關閉資源
        objectOutputStream.close();
    }
}

∆ Properties(配置檔案類)

主要用於生產配置檔案與讀取配置檔案的資訊。

可以和流相關聯的集合物件Properties.

Map
|--Hashtable
|--Properties

Properties:該集合不需要泛型,因為該集合中的鍵值對都是String型別。
1,存入鍵值對:setProperty(key,value);
2,獲取指定鍵對應的值:value getProperty(key);
3,獲取集合中所有鍵元素:
Enumeration propertyNames();

Properties要注意的細節:

  • 如果配置檔案的資訊一旦使用了中文,那麼在使用store方法生成配置檔案的時候只能使用字元流解決,如果使用位元組流生成配置檔案的話,預設使用的是iso8859-1碼錶進行編碼儲存,這時候會出現亂碼。
  • 如果Properties中的內容發生了變化,一定要重新使用Properties生成配置檔案,否則配置檔案資訊不會發生變化。
public class Demo4 {
    public static void main(String[] args) throws IOException {
        creatProperties();

//      readProperties();
    }
    //讀取配置檔案的資訊 
    public static void readProperties() throws IOException{
        //建立Properties物件
        Properties properties = new Properties();
        //載入配置檔案資訊到Properties中
        properties.load(new FileReader("F:\\persons.properties"));
        //遍歷
        Set<Entry<Object, Object>> entrys = properties.entrySet();
        for(Entry<Object, Object> entry  :entrys){
            System.out.println("鍵:"+ entry.getKey() +" 值:"+ entry.getValue());
        }
        //修改狗娃的密碼
        //把修改後的Properties再生成一個配置檔案
        properties.setProperty("狗娃", "007");
        properties.store(new FileWriter("F:\\persons.properties"), "hehe");
    }

    //儲存配置檔案檔案的資訊。
    public static void creatProperties() throws IOException{
        //建立Properties
        Properties properties = new Properties();
        properties.setProperty("狗娃", "123");
        properties.setProperty("狗剩","234");
        properties.setProperty("鐵蛋","345");
        // 遍歷Properties
        /*Set<Entry<Object, Object>> entrys = properties.entrySet();
        for(Entry<Object, Object> entry  :entrys){
            System.out.println("鍵:"+ entry.getKey() +" 值:"+ entry.getValue());
        }*/
        //使用Properties生產配置檔案。
        //properties.store(new FileOutputStream("F:\\persons.properties"), "haha"); //第一個引數是一個輸出流物件,第二引數是使用一個字串描述這個配置檔案的資訊。
        properties.store(new FileWriter("F:\\persons.properties"), "hehe");
    }
}

程式碼舉例: 使用properties實現本軟體只能 執行三次,超過了三次之後就提示購買正版,退jvm.

public class Demo5 {
    public static void main(String[] args) throws IOException {
        File file = new File("F:\\count.properties");
        if(!file.exists()){
            //如果配置檔案不存在,則建立該配置檔案
            file.createNewFile();
        }
        //建立Properties物件。
        Properties properties = new Properties();
        //把配置檔案的資訊載入到properties中
        properties.load(new FileInputStream(file));
        FileOutputStream fileOutputStream = new FileOutputStream(file);

        int count = 0; //定義該變數是用於儲存軟體的執行次數的。
        //讀取配置檔案的執行次數
        String value = properties.getProperty("count");
        if(value!=null){
            count = Integer.parseInt(value);
        }   
        //判斷使用的次數是否已經達到了三次,
        if(count==3){
            System.out.println("你已經超出了試用次數,請購買正版軟體!!");
            System.exit(0);
        }
        count++;
        System.out.println("你已經使用了本軟體第"+count+"次");
        properties.setProperty("count",count+"");
        //使用Properties生成一個配置檔案
        properties.store(fileOutputStream,"runtime");       
    }
}

∆ 列印流(printStream)

列印流(printStream) 列印流可以列印任意型別的資料,而且列印資料之前都會先把資料轉換成字串再進行列印。

PrintStream:
是一個位元組列印流,System.out對應的型別就是PrintStream。

它的建構函式可以接收三種資料型別的值。

  1. 字串路徑。
  2. File物件。
  3. OutputStream。
public static void main(String[] args) throws IOException {
        PrintStream ps = System.out;

        // 普通write方法需要呼叫flush或者close方法才會在控制檯顯示
        // ps.write(100);
        // ps.close();

        // 不換行列印
        ps.print(100);
        ps.print('a');
        ps.print(100.5);
        ps.print("世界");
        ps.print(new Object());
        System.out.println("--------------");
        // 換行
        ps.println(100);
        ps.println('a');
        ps.println(100.5);
        ps.println("世界");
        ps.println(new Object());

        // 重定向列印流
        PrintStream ps2 = new PrintStream(new File("c:\\a.txt"));
        System.setOut(ps2);
        // 換行
        ps2.println(100);
            ps2.println('a');
        ps2.println(100.5);
        ps2.println("世界");
        ps2.println(new Object());

        // printf(); 格式化
        ps2.printf("%d,%f,%c,%s", 100, 3.14, '中', "世界你好!!!");
        ps2.printf("%4s和%8s 打價格戰", "京東", "蘇寧");
    }   }

程式碼舉例:

class Animal{
    String name;
    String color;
    public Animal(String name,String color){
        this.name = name;
        this.color = color;
    }
    @Override
    public String toString() {
        return "名字:"+this.name+ " 顏色:"+ this.color;
    }
}
public class Demo6 {
    public static void main(String[] args) throws IOException {
        /*FileOutputStream fileOutputStream = new FileOutputStream("F:\\a.txt");
        fileOutputStream.write("97".getBytes());
        fileOutputStream.close();*/
        //列印流可以列印任何型別的資料,而且列印資料之前都會先把資料轉換成字串再進行列印。
        File file = new  File("F:\\a.txt");
        //建立一個列印流
        PrintStream printStream = new PrintStream(file);
        /*
        printStream.println(97);
        printStream.println(3.14);
        printStream.println('a');
        printStream.println(true);
        Animal a = new Animal("老鼠", "黑色");
        printStream.println(a);
        //預設標準的輸出流就是向控制檯輸出的,
        System.setOut(printStream); //重新設定了標準的輸出流物件
        System.out.println("哈哈,猜猜我在哪裡!!");
        */

        //收集異常的日誌資訊。
        File logFile = new File("F:\\2015年1月8日.log");
        PrintStream logPrintStream = new PrintStream( new FileOutputStream(logFile,true) );
        try{
            int c = 4/0;
            System.out.println("c="+c);
            int[] arr = null;
            System.out.println(arr.length);
        }catch(Exception e){
            e.printStackTrace(logPrintStream);
        }       
    }
}

∆ 編碼

∆ 轉換流:

輸入位元組流的轉換流:InputStreamReader 是位元組流通向字元流的橋
InputStreamReader

輸出位元組流的轉換流:
OutputStreamWriter 可以把輸出位元組流轉換成輸出字元流 。

轉換流的作用:

1. 如果目前所 獲取到的是一個位元組流需要轉換字元流使用,這時候就可以使用轉換流。  位元組流----> 字元流
2. 使用轉換流可以指定編碼表進行讀寫檔案。
public class Demo8 {
    public static void main(String[] args) throws IOException {
//      readTest();
//      writeTest();'

//      writeTest2();
        readTest2();
    }
    //使用輸入位元組流的轉換流指定碼錶進行讀取檔案資料
    public static void readTest2() throws IOException{
        File file = new File("F:\\a.txt");
        FileInputStream fileInputStream = new FileInputStream(file);
        //建立位元組流的轉換流並且指定碼錶進行讀取
        InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"utf-8");
        char[] buf = new char[1024];
        int length = 0;
        while((length = inputStreamReader.read(buf))!=-1){
            System.out.println(new String(buf,0,length));
        }   
    }
    //使用輸出位元組流的轉換流指定碼錶寫出資料
    public static void writeTest2() throws IOException{
        File file = new File("F:\\a.txt");
        //建立資料的輸出通道
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        //把輸出位元組流轉換成字元流並且指定編碼表。
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "utf-8");
        outputStreamWriter.write("新中國好啊");
        //關閉資源
        outputStreamWriter.close();
    }
    public static void writeTest() throws IOException{
        File file = new File("F:\\a.txt");
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        //把輸出位元組流轉換成輸出字元流。
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
        outputStreamWriter.write("大家好");
        outputStreamWriter.close();
    }

    public static void readTest() throws IOException{
        InputStream in = System.in; //獲取了標準的輸入流。
//      System.out.println("讀到 的字元:"+ (char)in.read());  //read()一次只能讀取一個位元組。
        //需要把位元組流轉換成字元流。
        InputStreamReader inputStreamReader = new InputStreamReader(in);
        //使用字元流的緩衝類
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        String line = null;
        while((line = bufferedReader.readLine())!=null){
            System.out.println("內容:"+ line);
        }
    }
}