I/O輸入輸出流

1. 編碼問題

從一種形式或格式轉(zhuǎn)換為另一種形式的過程也稱為計(jì)算機(jī)編程語言的代碼簡稱編碼。而這個(gè)轉(zhuǎn)換的方式就是編碼方式。
將字符串“例子ABC”分別以gbk、utf-8utf-16be編碼方式轉(zhuǎn)化成字節(jié),如下:

public class Coding {
    public static void printByEncoding(String s, String encoding){
        try {
            byte[] bytes = s.getBytes(encoding);
            System.out.print("encoding " + encoding + " : ");
            for (byte b : bytes) {
                //把字節(jié)(轉(zhuǎn)換成了int)以16進(jìn)制的方式顯示
                System.out.print(Integer.toHexString(b & 0xff) + " ");
            }
            System.out.println();
        }catch (UnsupportedEncodingException e){
            System.out.println("unsupportded encoding: " + encoding);
        }
    }
    public static void main(String[] args) {
        String s = "例子ABC";
        //gbk編碼:中文兩個(gè)字節(jié),英文一個(gè)字節(jié)
        Coding.printByEncoding(s, "gbk");
        //utf-8編碼:中文三個(gè)字節(jié),英文一個(gè)字節(jié)
        Coding.printByEncoding(s, "utf-8");
        // utf-16be編碼,中文兩個(gè)字節(jié),英文兩個(gè)字節(jié)
        Coding.printByEncoding(s, "utf-16be");
    }

輸出結(jié)果為:

encoding gbk : c0 fd d7 d3 41 42 43 
encoding utf-8 : e4 be 8b e5 ad 90 41 42 43 
encoding utf-16be : 4f 8b 5b 50 0 41 0 42 0 43 

當(dāng)你的字節(jié)序列是某種編碼時(shí),這時(shí)候想把字節(jié)序列變成字符串,也需要這種編碼方式,否則會出現(xiàn)亂碼

 try {
            String str1 = new String(s.getBytes("utf-16be"));
            System.out.println(str1);

            String str2 = new String(s.getBytes("utf-16be"), "utf-16be");
            System.out.println(str2);
        }catch (UnsupportedEncodingException e){
            System.out.println("unsupportded encoding: " );
        }

輸出結(jié)果為:

O?[P A B C
例子ABC

文本文件就是字節(jié)序列,它可以是任何編碼的字節(jié)序列。

2. File類

java.io.File類用于表示文件(目錄)。File類只用于表示文件(目錄)的信息(名稱、大小),不能用于文件內(nèi)容的訪問。

File file1 = new File("文件/目錄路徑"); 
File file2 = new File(File parent, String child);
File file3 = new File(String parent, String child) 
方法 描述
boolean exists() 判斷文件/目錄 是否存在
boolean mkdir() 創(chuàng)建目錄
void createNewFile() 創(chuàng)建目錄
delete() 刪除文件/目錄
boolean isDirectory() 是否是一個(gè)目錄,如果不是目錄or目錄不存在返回false
boolean isFile() 是否是一個(gè)文件
String getName() 返回文件/目錄名。
String getAbsolutePath() 返回抽象路徑名的絕對路徑名字符串。
String getParent() / File getParentFile() 獲取父路徑
long lastModified() 返回此抽象路徑名表示的文件最后一次被修改的時(shí)間。
String[] list() 返回由包含在目錄中的文件和目錄的名稱所組成的字符串?dāng)?shù)組
File[] listFiles() 返回一個(gè)抽象路徑名數(shù)組,這些路徑名表示此抽象路徑名所表示目錄中的文件。
...... ......

eg:遍歷目錄

package com.company;

import java.io.File;
import java.util.Stack;

/**
 * FileItem表示 文件和文件在第幾層
 */
public class FileItem {
    public File file;
    public int depth ;

    public FileItem(File file, int depth) {
        this.file = file;
        this.depth = depth;
    }
    //遍歷文件or目錄
    public static void printFiles(String path){
        //用于存放待訪問的節(jié)點(diǎn)
        Stack<FileItem> stack = new Stack<FileItem>();
        //根節(jié)點(diǎn)入棧
        stack.push( new FileItem(new File("F:\\study"), 0) );
        while(!stack.empty() ) {
            FileItem item = stack.pop();
            File file = item.file;
            int depth = item.depth;
            //打出文件名,按層數(shù)縮進(jìn)
            System.out.println(new String(" ".repeat(2*depth) + file.getName()) );
            if(file.exists() && file.isDirectory()){
                //遍歷下一層
                File[] fileList = file.listFiles();
                for(File it: fileList){
                    //下一層入棧
                    stack.push( new FileItem(it, depth+1) );
                }
            }
        }
    }
    public static void main(String[] args) {
      printFiles("F://");

    }

}
 

3. RandomAccessFile

RandomAccessFile是Java提供的對文件內(nèi)容的訪問,既可以讀文件,也可以寫文件。
RandomAccessFile支持隨機(jī)訪問文件,即可以訪問文件的任意位置。

  • (1) java文件模型
    在硬盤上的文件是bye bye bye存儲的,是數(shù)據(jù)的集合。
  • (2) 打開文件
    打開文件時(shí),可以選擇兩種模式:“rw"(讀寫),"r"(只讀)。
RandomAccessFile raf = new RandomAccessFile(file, "rw");

由于RandomAccessFile支持隨機(jī)訪問文件,需要一個(gè)文件指針來指定位置。打開文件時(shí)指針在開題pointer = 0;

  • (3) 寫方法
raf.write(int) //只寫一個(gè)字節(jié),同時(shí)指針指向下一個(gè)位置。
  • (4) 讀方法
int b = raf.read(); //讀一個(gè)字節(jié)
  • (5) 文件讀寫完成后一定要關(guān)閉。

4. 字節(jié)流

4.1 InputStream和OutputStream

InputStream 和 OutputStream為各種輸入輸出字節(jié)流的基類,所有字節(jié)流都繼承這兩個(gè)基類。而且InputStream 和 OutputStream為抽象類,不進(jìn)行具體的實(shí)現(xiàn)。
InputStream抽象了應(yīng)用程序讀取數(shù)據(jù)的方式。
OutputStream抽象了應(yīng)用程序?qū)懗鰯?shù)據(jù)的方式。

  • 輸入流常用方法
方法名 描述
int read() throws IOException 讀取一個(gè)字節(jié)無符號填充到int低八位,-1是EOF
int read( byte[] buf ) throws IOException 讀取數(shù)據(jù)填充到字節(jié)數(shù)組buf
int read(byte[] buf, int start, int size) throws IOException /讀取數(shù)據(jù)填充到字節(jié)數(shù)組buf
void close() throws IOException 關(guān)閉輸入流
  • 輸出流基本方法
方法名 描述
void write(int b) throws IOException 寫出一個(gè)byte到流,b的低八位
void write( byte[] buf ) throws IOException 將buf字節(jié)數(shù)組都寫入到流
void write(byte[] buf, int start, int size) throws IOException 將buf字節(jié)數(shù)組都寫入到流
void close() throws IOException 關(guān)閉輸出流

4.2 FileInputStream和FileOutputStream

FileInputStream具體實(shí)現(xiàn)了在文件上讀取數(shù)據(jù)。
FileOutputStream具體實(shí)現(xiàn)了將byte數(shù)據(jù)寫入文件.

  • 讀取文件
 /**
     * 通過int讀取指定文件內(nèi)容,按照16進(jìn)制輸出到控制臺
     */
      public  static void printHexByInt(String filename) throws IOException{
        //把文件作為字節(jié)流進(jìn)行讀操作
        FileInputStream in = new FileInputStream(filename); 
        int b;
        while ( (b=in.read()) != -1 ){
            System.out.print(Integer.toHexString(b) + " ");
        }
        in.close();

    }
    /**
     * 通過byte讀取指定文件內(nèi)容,按照16進(jìn)制輸出到控制臺
     */
    public  static void printHexByBytes(String filename) throws IOException{
        //把文件作為字節(jié)流進(jìn)行讀操作
        FileInputStream in = new FileInputStream(filename);
        byte[] buf = new byte[1024]; //隨便大小都可,大一點(diǎn)可能更快
        //從in中批量讀取字節(jié), 最多讀取 buf.length個(gè),返回讀到的數(shù)據(jù)的個(gè)數(shù)
        //int bytes = in.read(buf);
        int bytes = 0;
        while ( (  bytes = in.read(buf) ) != -1){

            for(int i = 0; i < bytes; i++){
                System.out.print( Integer.toHexString(buf[i] &0x00ff)+ " ");
            }
        }

    }
  • 寫入文件
 //如果該文件不存在,則直接創(chuàng)建;如果存在,刪除后創(chuàng)建
        FileOutputStream out = new FileOutputStream("out.dat");
        //如果該文件不存在,則直接創(chuàng)建;如果存在,在后面繼續(xù)寫
        FileOutputStream out2 = new FileOutputStream("out2.dat",true);

        out.write('A'); //寫出了‘A’的低八位

        //write只能寫八位,那么寫一個(gè)int需要4次每次8位
        int a = 10;
        out.write(a >>> 24);
        out.write(a >>> 16);
        out.write(a >>> 8 );
        out.write(a );

        //寫入byte數(shù)組
        byte [] gbk = "中國".getBytes("gbk");
        out.write(gbk);
        
        out.close();
  • 拷貝一個(gè)文件
 try {
           InputStream in = new FileInputStream("a.txt");
           OutputStream out = new FileOutputStream("b.txt");

           byte[] buf = new byte[1024];
           int bytes;
           while( (bytes = in.read(buf)) != -1){
               out.write(buf);
               out.flush();
           }
           in.close();
           out.close();
       }catch (FileNotFoundException e1){
           e1.printStackTrace();
       }catch (IOException e2){
           e2.printStackTrace();
       }

4.3 DataInputStream和DataOutputStream

對"流"功能的擴(kuò)展,可以更加方便地讀取int、long、字符等類型數(shù)據(jù)。

  • DataInputStream: readByte()/readInt() / readDouble() / readUTF()...
  • DataOutputStream:writeByte()/writeInt() / writeDouble() / writeUTF()...

4.2 字節(jié)緩沖流BufferedInputStream和BufferedOutputStream

為IO提供了帶緩沖區(qū)的操作,一般打開文件進(jìn)行寫入或讀取操作時(shí),都會加上緩沖,這種流模式提高了IO的性能。
從應(yīng)用程序中把輸入放入文件,相當(dāng)于將一缸水倒入到另一缸水中:

  • FileOutputStream --> write()方法相當(dāng)于一滴一滴地把水轉(zhuǎn)移過去
  • DataOutputStream->writeXxx()方法會方便點(diǎn),相當(dāng)于一瓢一瓢地將水轉(zhuǎn)移過去。
  • BufferedOutputStream-->write方法更方便,相當(dāng)于一瓢一瓢先放入桶中,再從桶中倒入缸中。
    拷貝文件:
 try {
           BufferedInputStream is  = new BufferedInputStream(new FileInputStream("a.txt"));
           BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream("b.txt"));
           int c;
           while( (c=is.read())!= -1){
               os.write(c);
               os.flush(); //刷新緩存區(qū)
           }
           is.close();
           os.close();
       }catch (FileNotFoundException e1){
           e1.printStackTrace();
       }catch (IOException e2){
           e2.printStackTrace();
       }  

5. 字符流Reader/Writer

5.1 文本文件

  • java的文本(char)是16位無符號整數(shù),是字符的unicode編碼(雙字節(jié)編碼)。
  • 文件是 byte byte byte...的數(shù)據(jù)序列。
  • 文本文件是文本(char)序列按照某種編碼方案(utf-8,utf-16be,gbk) 序列號為byte 的存儲結(jié)構(gòu)。

字符的處理,一次處理一個(gè)字符。但是字符的底層任然是基本的字節(jié)序列 。

5.2 InputStreamReader和OutputStreamWriter

InputStreamReader 完成byte流解析為char流,按照編碼解析。
OutputStreamWriter 提供char流到byte流,按照編碼處理。

 try {
           FileInputStream is = new FileInputStream("a.txt");
           InputStreamReader isr = new InputStreamReader(is,"gbk");//默認(rèn)為gbk
           //第一種方法
           int c;
           while( (c = isr.read()) != -1){
               System.out.println( (char)c);
           }
           //第二種方法
           char[] buffer = new char[1024];
           int n;
           while( (n = isr.read(buffer)) !=-1 ){
               String s  = new String(buffer, 0, n);
               System.out.println( s );

           }
           is.close(); 
           isr.close();

       }catch (FileNotFoundException e1){
           e1.printStackTrace();
       }catch (IOException e2){
           e2.printStackTrace();
       }

5.3 BufferedReader / BufferedWriter

  • BufferedReader : readLine 一次第一行
  • BufferedWriter/PrintWriter:寫一行

6.對象的序列化和反序列化

對象序列化,就是將Object轉(zhuǎn)換成byte序列,反之叫對象的反序列化 。

  • 序列化流(ObjectOutputStream),是過濾流。--- writeObject
  • 反序列化流(ObjectInputStream) --- readObject

對象必須實(shí)現(xiàn)序列化接口Serializable,才能序列化,否則將會出現(xiàn)異常。

  • 序列化:
public class Student implements Serializable {
    private String stuno;
    private  String stuname;
    private  int stuage;

    public Student(String stuno, String stuname, int stuage) {
        this.stuno = stuno;
        this.stuname = stuname;
        this.stuage = stuage;
    }
  • 將Object寫入文件
        ObjectOutputStream oos =  new ObjectOutputStream(new FileOutputStream(file));
        Student stu = new Student("10000","loserwang",20);
        oos.writeObject(stu);
        oos.flush();
        oos.close();
  • 從文件中讀取Object
 String file = "obj.txt";
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
        Student s = (Student) ois.readObject();
        System.out.println(s);

添加transient 該元素不會被JVM默認(rèn)序列化

private transient int name;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。