JavaSE - [10] 高級部分之IO流

IO流

File 類的實例化

? java.io.File類:文件和文件目錄路徑的抽象表示形式余赢,與平臺無關
? File 能新建、刪除哈垢、重命名文件和目錄妻柒,但 File 不能訪問文件內容本身。
如果需要訪問文件內容本身耘分,則需要使用輸入/輸出流举塔。
? 想要在Java程序中表示一個真實存在的文件或目錄绑警,那么必須有一個File對象,但是Java程序中的一個File對象央渣,可能沒有一個真實存在的文件或目錄计盒。
? File對象可以作為參數(shù)傳遞給流的構造器
? public File(String pathname)
以pathname為路徑創(chuàng)建File對象,可以是 絕對路徑或者相對路徑芽丹,如果
pathname是相對路徑北启,則默認的當前路徑在系統(tǒng)屬性user.dir中存儲。
? 絕對路徑:是一個固定的路徑,從盤符開始
? 相對路徑:是相對于某個位置開始
? public File(String parent,String child)
以parent為父路徑拔第,child為子路徑創(chuàng)建File對象咕村。
? public File(File parent,String child)
根據(jù)一個父File對象和子文件路徑創(chuàng)建File對象
? 路徑中的每級目錄之間用一個 路徑分隔符隔開。
? 路徑分隔符和系統(tǒng)有關:
? windows和DOS系統(tǒng)默認使用“\”來表示
? UNIX和URL使用“/”來表示
? Java程序支持跨平臺運行蚊俺,因此路徑分隔符要慎用懈涛。
? 為了解決這個隱患,F(xiàn)ile類提供了一個常量:
public static final String separator泳猬。根據(jù)操作系統(tǒng)批钠,動態(tài)的提供分隔符

File 類的常用方法

File 類的獲取功能
? public String getAbsolutePath():獲取絕對路徑
? public String getPath() :獲取路徑
? public String getName() :獲取名稱
? public String getParent():獲取上層文件目錄路徑。若無得封,返回null
? public long length() :獲取文件長度(即:字節(jié)數(shù))价匠。不能獲取目錄的長度。
? public long lastModified() :獲取最后一次的修改時間呛每,毫秒值
? public String[] list() :獲取指定目錄下的所有文件或者文件目錄的名稱數(shù)組
? public File[] listFiles() :獲取指定目錄下的所有文件或者文件目錄的File數(shù)組
File 類的重命名功能
? public boolean renameTo(File dest):把文件重命名為指定的文件路徑
File 類的判斷功能
? public boolean isDirectory():判斷是否是文件目錄
? public boolean isFile() :判斷是否是文件
? public boolean exists() :判斷是否存在
? public boolean canRead() :判斷是否可讀
? public boolean canWrite() :判斷是否可寫
? public boolean isHidden() :判斷是否隱藏
File 類的創(chuàng)建功能
? public boolean createNewFile() :創(chuàng)建文件踩窖。若文件存在,則不創(chuàng)建晨横,返回false
? public boolean mkdir() :創(chuàng)建文件目錄洋腮。如果此文件目錄存在,就不創(chuàng)建了手形。如果此文件目錄的上層目錄不存在啥供,也不創(chuàng)建。
? public boolean mkdirs() :創(chuàng)建文件目錄库糠。如果上層文件目錄不存在伙狐,一并創(chuàng)建
注意事項:如果你創(chuàng)建文件或者 文件 目錄沒有 寫 盤符路徑 , 那么 瞬欧, 默認在項目路徑下 贷屎。
File 類的刪除功能
? public boolean delete():刪除文件或者文件夾
刪除注意事項:
Java中的刪除不走 回收站。
要刪除一個文件目錄艘虎,請注意該文件目錄內不能包含文件或者文件目錄

public class TestFile {
    public static void main(String[] args) {
        //相對路徑  相對于 項目文件
        File file1 = new File("hello.txt");
        //絕對路徑
        File file2 = new File("C:\\Users\\icanci\\Desktop\\poi\\poi-3.9\\readme.md");

        System.out.println(file1.getAbsolutePath());
        System.out.println(file1.getPath());
        System.out.println(file1.getName());
        System.out.println(file1.getPath());
        System.out.println(file1.length());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:ss:mm");
        System.out.println(sdf.format(file1.lastModified()));

        //獲取文件名字

        //獲取文件對象數(shù)組

        File file3 = new File("D:\\centBrowser");
        String[] list = file3.list();
        System.out.println(Arrays.toString(list));
        File[] files = file3.listFiles();
        System.out.println(Arrays.toString(files));

        boolean renameTo = file1.renameTo(file2);
        System.out.println(renameTo);
        System.out.println(file1);
        System.out.println(file2);
//        System.out.println("----------------");
//        System.out.println(file1.isDirectory());
//        System.out.println(file1.isFile());
//        System.out.println(file1.exists());
//        System.out.println(file1.canWrite());
//        System.out.println(file1.canRead());
//        System.out.println(file1.isHidden());
//        System.out.println("----------------");
//        System.out.println(file2.isDirectory());
//        System.out.println(file2.isFile());
//        System.out.println(file2.exists());
//        System.out.println(file2.canWrite());
//        System.out.println(file2.canRead());
//        System.out.println(file2.isHidden());

        try {
            file1.createNewFile();
            System.out.println("success");
        } catch (IOException e) {
            e.printStackTrace();
        } 
        File file = new File("File");
        System.out.println(file.mkdirs());
        file.delete();
    }
}
File
IO 流概述與流的分類

? I/O是Input/Output的縮寫唉侄, I/O技術是非常實用的技術,用于
處理設備之間的數(shù)據(jù)傳輸野建。如讀/寫文件属划,網(wǎng)絡通訊等恬叹。
? Java程序中,對于數(shù)據(jù)的輸入/輸出操作以 “流(stream)” ” 的
方式進行同眯。
? java.io包下提供了各種“流”類和接口绽昼,用以獲取不同種類的
數(shù)據(jù),并通過 標準的方法輸入或輸出數(shù)據(jù)须蜗。


IO

流的分類
?按操作 數(shù)據(jù)單位不同分為:流 字節(jié)流(8 bit) 绪励,字符流(16 bit)
?按數(shù)據(jù)流的 流向不同分為: 輸入流,輸出流
?按流的 角色的不同分為:


分類
  1. Java的IO流共涉及40多個類唠粥,實際上非常規(guī)則,都是從如下4個
    抽象基類派生的停做。
  2. 由這四個類派生出來的子類名稱都是以其父類名作為子類名后綴晤愧。


    輸入輸出流
IO 流的體系結構
IO體系結構
InputStream & Reader

?InputStream 和 Reader 是所有 輸入流的基類。
?InputStream(典型實現(xiàn):FileInputStream)
?int read()
?int read(byte[] b)
?int read(byte[] b, int off, int len)
?Reader(典型實現(xiàn):FileReader)
?int read()
?int read(char [] c)
?int read(char [] c, int off, int len)
?程序中打開的文件 IO 資源不屬于內存里的資源蛉腌,垃圾回收機制無法回收該資
源官份,所以應該件 顯式關閉文件 IO 資源。
?FileInputStream 從文件系統(tǒng)中的某個文件中獲得輸入字節(jié) FileInputStream
用于讀取非文本數(shù)據(jù)之類的原始字節(jié)流烙丛。要讀取字符流舅巷,需要使用FileReader
InputStream
? int read()
從輸入流中讀取數(shù)據(jù)的下一個字節(jié)。返回 0 到 255 范圍內的 int 字節(jié)值河咽。如果因為已經到達流末尾而沒有可用的字節(jié)钠右,則返回值 -1。
? int read(byte[] b)
從此輸入流中將最多 b.length 個字節(jié)的數(shù)據(jù)讀入一個 byte 數(shù)組中忘蟹。如果因為已經到達流末尾而沒有可用的字節(jié)飒房,則返回值 -1。否則以整數(shù)形式返回實際取的字節(jié)數(shù)媚值。
? int read(byte[] b, int off,int len)
將輸入流中最多 len 個數(shù)據(jù)字節(jié)讀入 byte 數(shù)組狠毯。嘗試讀取 len 個字節(jié),但讀取的字節(jié)也可能小于該值褥芒。以整數(shù)形式返回實際讀取的字節(jié)數(shù)嚼松。如果因為流位于文件末尾而沒有可用的字節(jié),則返回值 -1锰扶。
? public void close() throws IOException
關閉此輸入流并釋放與該流關聯(lián)的所有系統(tǒng)資源献酗。

Reader
? int read()
讀取單個字符。作為整數(shù)讀取的字符坷牛,范圍在 0 到 65535 之間 (0x00-0xffff)(2個字節(jié)的Unicode碼)凌摄,如果已到達流的末尾,則返回 -1
? int read(char[] cbuf)
將字符讀入數(shù)組漓帅。如果已到達流的末尾锨亏,則返回 -1痴怨。否則返回本次讀取的字符數(shù)。
? int read(char[] cbuf,int off,int len)
將字符讀入數(shù)組的某一部分器予。存到數(shù)組cbuf中浪藻,從off處開始存儲,最多讀len個字符乾翔。如果已到達流的末尾爱葵,則返回 -1。否則返回本次讀取的字符數(shù)反浓。
? public void close() throws IOException
關閉此輸入流并釋放與該流關聯(lián)的所有系統(tǒng)資源萌丈。

OutputStream & Writer
? OutputStream 和 Writer 也非常相似:
?void write(int b/int c);
?void write(byte[] b/char[] cbuf);
?void write(byte[] b/char[] buff, int off, int len);
?void flush();
?void close(); 需要先刷新,再關閉此流
? 因為字符流直接以字符作為操作單位雷则,所以 Writer 可以用字符串來替換字符數(shù)組辆雾,即以 String 對象作為參數(shù)
?void write(String str);
?void write(String str, int off, int len);
? FileOutputStream 從文件系統(tǒng)中的某個文件中獲得輸出字節(jié)。FileOutputStream用于寫出非文本數(shù)據(jù)之類的原始字節(jié)流月劈。要寫出字符流度迂,需要使用FileWriter

OutputStream
? void write(int b)
將指定的字節(jié)寫入此輸出流。write 的常規(guī)協(xié)定是:向輸出流寫入一個字節(jié)猜揪。要寫入的字節(jié)是參數(shù) b 的八個低位惭墓。b 的 24 個高位將被忽略。 即寫入0~255范圍的而姐。
? void write(byte[] b)
將 b.length 個字節(jié)從指定的 byte 數(shù)組寫入此輸出流腊凶。write(b) 的常規(guī)協(xié)定是:應該與調用 write(b, 0, b.length) 的效果完全相同。
? void write(byte[] b,int off,int len)
將指定 byte 數(shù)組中從偏移量 off 開始的 len 個字節(jié)寫入此輸出流拴念。
? public void flush()throws IOException
刷新此輸出流并強制寫出所有緩沖的輸出字節(jié)吭狡,調用此方法指示應將這些字節(jié)立即寫入它們預期的目標。
? public void close() throws IOException
關閉此輸出流并釋放與該流關聯(lián)的所有系統(tǒng)資源丈莺。

Writer
? void write(int c)
寫入單個字符划煮。要寫入的字符包含在給定整數(shù)值的 16 個低位中,16 高位被忽略缔俄。 即寫入0 到 65535 之間的Unicode碼弛秋。
? void write(char[] cbuf)
寫入字符數(shù)組。
? void write(char[] cbuf,int off,int len)
寫入字符數(shù)組的某一部分俐载。從off開始蟹略,寫入len個字符
? void write(String str)
寫入字符串。
? void write(String str,int off,int len)
寫入字符串的某一部分遏佣。
? void flush()
刷新該流的緩沖挖炬,則立即將它們寫入預期目標。
? public void close() throws IOException
關閉此輸出流并釋放與該流關聯(lián)的所有系統(tǒng)資源状婶。

FileReader 讀入數(shù)據(jù)的基本操作
public class TestIO {
    public static void main(String[] args) {

        //1.實例化File類的對象.指明要操作得文件
        File file = new File("hello.txt");
        //2.提供具體的流
        FileReader fr = null;
        try {
            fr = new FileReader(file);
            //數(shù)據(jù)的讀入
//            int data = fr.read();
//            while (data != -1) {
//                System.out.print((char)data);
//                data = fr.read();
//            }

            int data;
            while ((data = fr.read())!=-1){
                System.out.print((char) data);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
FileReader 中使用 read(char[] cbuf)讀入數(shù)據(jù)
public class TestIO {
    public static void main(String[] args) {
        //1. File類的實例化
        File file = new File("hello.txt");
        //2.FileReader流的實例化
        FileReader fr = null;
        try {
            fr = null;
            fr = new FileReader(file);
            //3.讀取的操作
            char[] buff = new char[5];
            int len;
            //read(char[] buff)
            while ((len = fr.read(buff)) != -1) {
                for (int i = 0; i < len ; i++) {
                    System.out.print(buff[i]);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.資源的關閉
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}
FileWriter 寫出數(shù)據(jù)的操作
public class TestIO {
    public static void main(String[] args) {
        //1. 提供File對象
        File file1 = new File("text.txt");
        FileWriter fw = null;
        try {
            //2.提供FileWriter對象
            fw = null;
            fw = new FileWriter(file1);

            //3.寫出的操作
            fw.write("hahahahahahah hahah");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.資源關閉
            try {
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

注意:文件不存在 自己創(chuàng)建 如果存在 先刪除 再創(chuàng)建 然后輸入內容

new FileWriter(file1,false);//不追加
new FileWriter(file1,true);//追加
字符流不能處理圖片文件的測試
public class TestIO {
    public static void main(String[] args) {
        //圖片的復制
        //創(chuàng)建對象
        File file1 = new File("logo.jpg");
        File file2 = new File("copy.jpg");

        //創(chuàng)建輸入輸出流
        FileReader fr = null;
        FileWriter fw = null;

        try {
            fr = new FileReader(file1);
            fw = new FileWriter(file2);

            //讀取和寫
            char[] buff = new char[10];
            int len;
            while ((len= fr.read(buff))!=-1){
                fw.write(buff,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //關閉資源
            try {
                fw.close();
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
失敗
使用 FileInputStream 不能讀取文本文件的測試
public class FileInputTest {
    public static void main(String[] args) {
        //1. 獲取文件對象
        File file = new File("hello.txt");

        //2.創(chuàng)建輸入流對象

        FileInputStream fis = null;;
        try {
            fis = new FileInputStream(file);
            //讀取數(shù)據(jù)
            byte[] buffer = new byte[10];
            int len;
            while ((len=fis.read(buffer))!=-1){
                String str = new String(buffer,0,len);
                System.out.print(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //關閉資源
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

注意:
文本使用字節(jié)流
非文本使用字符流

使用 FileInputStream 和 FileOutputStream 讀寫非文本文件
public class FileInputTest {
    public static void main(String[] args) {
        //1.實現(xiàn)對文件的復制

        File file1 = new File("logo.jpg");
        File file2 = new File("logo1.jpg");

        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream  =null;
        try {
            fileInputStream = new FileInputStream(file1);
            fileOutputStream = new FileOutputStream(file2);

            //讀取寫入文件
            byte[] buffer = new byte[20];
            int len;
            while ((len = fileInputStream.read(buffer))!=-1){
                fileOutputStream.write(buffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

        }

    }
}
使用 FileInputStream 和 FileOutputStream 復制文件的方法測試
public class FileInputTest {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();

        String srcPath = "H:\\java主流框架\\主流框架\\階段3 7.微服務電商【黑馬樂優(yōu)商城】\\01 - SpringBoot\\1.mp4";
        String destPath = "E:\\IdeaHome\\maven\\jichu\\1.mp4";
        copyFile(srcPath, destPath);

        long end = System.currentTimeMillis();
        System.out.println("時間:" + (end - start));
    }

    public static void copyFile(String source, String dest) {
        //1.實現(xiàn)對文件的復制
        //時間:805 
        File file1 = new File(source);
        File file2 = new File(dest);

        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            fileInputStream = new FileInputStream(file1);
            fileOutputStream = new FileOutputStream(file2);

            //讀取寫入文件
            byte[] buffer = new byte[1024<<2];
            int len;
            while ((len = fileInputStream.read(buffer)) != -1) {
                fileOutputStream.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            try {
                fileInputStream.close();
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}
緩沖流(字節(jié)型)實現(xiàn)非文本文件的復制
public class FileInputTest {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();

        String srcPath = "H:\\java主流框架\\主流框架\\階段3 7.微服務電商【黑馬樂優(yōu)商城】\\01 - SpringBoot\\1.mp4";
        String destPath = "E:\\IdeaHome\\maven\\jichu\\1.mp4";
//        copyFile(srcPath, destPath);
        copyFileBuffer(srcPath, destPath);
        long end = System.currentTimeMillis();
        System.out.println("時間:" + (end - start));
    }

    public static void copyFileBuffer(String srcPath, String destPath) {
        //1.實現(xiàn)對文件的復制
        //時間:563 但是如果是關閉的流的順序存了,就會異常
        File file1 = new File(srcPath);
        File file2 = new File(destPath);

        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            fileInputStream = new FileInputStream(file1);
            fileOutputStream = new FileOutputStream(file2);
            bis = new BufferedInputStream(fileInputStream);
            bos = new BufferedOutputStream(fileOutputStream);
            //讀取寫入文件
            byte[] buffer = new byte[1024 << 2];
            int len;
            while ((len = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            try {
                bis.close();
                bos.close();
                fileInputStream.close();
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}
緩沖流與節(jié)點流讀寫速度對比

使用字節(jié):時間:805
使用緩沖:時間:563

緩沖流(字符型)實現(xiàn)文本文件的復制
public class CharBufferTest {
    public static void main(String[] args) {
        //使用 bufferReader bufferWriter
        long start = System.currentTimeMillis();
        File srcFile = new File("demo.txt");
        File targetFile = new File("demo1.txt");
        copyFile(srcFile,targetFile);
        long end = System.currentTimeMillis();
        System.out.println("時間:" + (end - start));
    }

    /**
     * 時間:2ms
     * @param src
     * @param target
     */
    public static void copyFile(File src, File target){
        //1.創(chuàng)建流
        BufferedReader reader = null;
        BufferedWriter writer = null;
        FileReader reader1 = null;
        FileWriter writer2 = null;
        try {
            reader1 = new FileReader(src);
            writer2 = new FileWriter(target);

            reader = new BufferedReader(reader1);
            writer = new BufferedWriter(writer2);

            //讀寫操作
//            char[] buffer = new char[1024];
//            int len;
//            while ((len = reader.read(buffer))!=-1){
//                writer.write(buffer,0,len);
//            }
            //方式2 一行一行讀取 時間:1ms
            String data;
            while ((data = reader.readLine())!=null){
                writer.write(data);
                writer.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //關閉資源
            try {
                reader.close();
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
原理
轉換流概述與 InputStreamReader 的使用

轉換流提供了在字節(jié)流和字符流之間的轉換
Java API提供了兩個轉換流:
? InputStreamReader :將InputStream 轉換為Reader
? OutputStreamWriter :將Writer 轉換為OutputStream
? 字節(jié)流中的數(shù)據(jù)都是字符時意敛,轉成字符流操作更高效。
? 很多時候我們使用轉換流來處理文件亂碼問題草姻。實現(xiàn)編碼和解碼的功能。
InputStreamReader
? 實現(xiàn)將字節(jié)的輸入流按指定字符集轉換為字符的輸入流敞曹。
? 需要和InputStream“套接”综膀。
? 構造器
? public InputStreamReader(InputStream in)
? public InputSreamReader(InputStream in,String charsetName)
如:Reader isr = new InputStreamReader(System.in,”gbk”);
OutputStreamWriter
? 實現(xiàn)將字符的輸出流按指定字符集轉換為字節(jié)的輸出流。
? 需要和OutputStream“套接”剧劝。
? 構造器
? public OutputStreamWriter(OutputStream out)
? public OutputSreamWriter(OutputStream out,String charsetName)


原理圖
轉換流實現(xiàn)文件的讀入和寫出
public static void testMyInput() throws Exception {
    FileInputStream fis = new FileInputStream("demo.txt");
    FileOutputStream fos = new FileOutputStream("demo2.txt");
    InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
    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();
}
多種字符編碼集的說明

? 編碼表的由來
計算機只能識別二進制數(shù)據(jù)担平,早期由來是電信號。為了方便應用計算機锭部,讓它可以識別各個國家的文字暂论。就將各個國家的文字用數(shù)字來表示,并一一對應拌禾,形成一張表取胎。這就是編碼表。
? 常見的編碼表
? ASCII:美國標準信息交換碼湃窍。
? 用一個字節(jié)的7位可以表示闻蛀。
? ISO8859-1:拉丁碼表。歐洲碼表
? 用一個字節(jié)的8位表示您市。
? GB2312:中國的中文編碼表觉痛。最多兩個字節(jié)編碼所有字符
? GBK:中國的中文編碼表升級,融合了更多的中文文字符號茵休。最多兩個字節(jié)編碼
? Unicode:國際標準碼薪棒,融合了目前人類使用的所有字符。為每個字符分配唯一的字符碼榕莺。所有的文字都用兩個字節(jié)來表示俐芯。
? UTF-8:變長的編碼方式,可用1-4個字節(jié)來表示一個字符钉鸯。
? 在 在Unicode 出現(xiàn)之前吧史,所有的字符集都是和具體編碼方案綁定在一起的(即字符集≈ 編碼方式),都是直接將字符和最終字節(jié)流綁定死了唠雕。
? GBK等雙字節(jié)編碼方式贸营,用最高位是1或0表示兩個字節(jié)和一個字節(jié)吨述。

? Unicode不完美,這里就有三個問題莽使,一個是芳肌,我們已經知道亿笤,英文字母只用一個字節(jié)表示就夠了净薛,第二個問題是如何才能區(qū)別Unicode和ASCII痴腌?計算機怎么知道兩個字節(jié)表示一個符號士聪,而不是分別表示兩個符號呢剥悟?第三個区岗,如果和GBK等雙字節(jié)編碼方式一樣慈缔,用最高位是1或0表示兩個字節(jié)和一個字節(jié)胀糜,就少了很多值無法用于表示字符教藻,不夠表示所有字符。Unicode在很長一段時間內無法推廣,直到互聯(lián)網(wǎng)的出現(xiàn)讥电。
? 面向傳輸?shù)谋姸?UTF(UCS Transfer Format)標準出現(xiàn)了,顧名思義横媚,UTF-8就是每次8個位傳輸數(shù)據(jù)灯蝴,而UTF-16就是每次16個位。這是為傳輸而設計的編碼耕肩,并使編碼無國界猿诸,這樣就可以顯示全世界上所有文化的字符了梳虽。
? Unicode只是定義了一個龐大的是复、全球通用的字符集,并為每個字符規(guī)定了唯一確定的編號逗余,具體存儲成什么樣的字節(jié)流录粱,取決于字符編碼方案。推薦的Unicode編碼是UTF-8和UTF-16青抛。

?編碼: 字符串?字節(jié)數(shù)組
?解碼: 字節(jié)數(shù)組?字符串
? 轉換流的編碼應用
? 可以將字符按指定編碼格式存儲
? 可以對文本數(shù)據(jù)按指定編碼格式來解讀
? 指定編碼表的動作由構造器完成

標準的輸入适室、輸出流

? System.in和System.out分別代表了系統(tǒng)標準的輸入和輸出設備
? 默認輸入設備是:鍵盤捣辆,輸出設備是:顯示器
? System.in的類型是InputStream
? System.out的類型是PrintStream旧巾,其是OutputStream的子類
FilterOutputStream 的子類
? 重定向:通過System類的setIn菠齿,setOut方法對默認設備進行改變绳匀。
? public static void setIn(InputStream in)
? public static void setOut(PrintStream out)

打印流的使用

?實現(xiàn)將 基本數(shù)據(jù)類型的數(shù)據(jù)格式轉化為 字符串輸出
?打印流:PrintStream和PrintWriter
? 提供了一系列重載的print()和println()方法疾棵,用于多種數(shù)據(jù)類型的輸出
? PrintStream和PrintWriter的輸出不會拋出IOException異常
? PrintStream和PrintWriter有自動flush功能
? PrintStream 打印的所有字符都使用平臺的默認字符編碼轉換為字節(jié)。在需要寫入字符而不是寫入字節(jié)的情況下开仰,應該使用 PrintWriter 類恩溅。
? System.out返回的是PrintStream的實例

數(shù)據(jù)流的使用

?為了方便地操作Java語言的基本數(shù)據(jù)類型和String的數(shù)據(jù)脚乡,可以使用數(shù)據(jù)流奶稠。
?數(shù)據(jù)流有兩個類:(用于讀取和寫出基本數(shù)據(jù)類型锌订、String類的數(shù)據(jù))
? DataInputStream 和 DataOutputStream
? 在 分別“套接”在 InputStream 和 和 OutputStream 子類的流 上
? DataInputStream 中的方法
boolean readBoolean()
byte readByte()
char readChar()
float readFloat()
double readDouble()
short readShort()
long readLong()
int readInt()
String readUTF()
void readFully(byte[] b)
? DataOutputStream 中的方法
? 將上述的方法的read改為相應的write即可涩搓。

對象序列化機制的理解

? ObjectInputStream 和OjbectOutputSteam
? 用于存儲和讀取 基本數(shù)據(jù)類型數(shù)據(jù)或 對象的處理流昧甘。它的強大之處就是可以把Java中的對象寫入到數(shù)據(jù)源中充边,也能把對象從數(shù)據(jù)源中還原回來浇冰。
? 序列化:用ObjectOutputStream類 保存基本類型數(shù)據(jù)或對象的機制
? 反序列化:用ObjectInputStream類 讀取基本類型數(shù)據(jù)或對象的機制
? ObjectOutputStream和ObjectInputStream不能序列化static和transient修
飾的成員變量

? 對象序列化機制允許把內存中的Java對象轉換成平臺無關的二進制流,從
而允許把這種二進制流持久地保存在磁盤上坡倔,或通過網(wǎng)絡將這種二進制流傳
輸?shù)搅硪粋€網(wǎng)絡節(jié)點投蝉。//當其它程序獲取了這種二進制流瘩缆,就可以恢復成原
來的Java對象
?序列化的好處在于可將任何實現(xiàn)了Serializable接口的對象轉化為 字節(jié)數(shù)據(jù)庸娱,使其在保存和傳輸時可被還原
?序列化是 RMI(Remote Method Invoke – 遠程方法調用)過程的參數(shù)和返
回值都必須實現(xiàn)的機制熟尉,而 RMI 是 JavaEE 的基礎臣樱。因此序列化機制是
JavaEE 平臺的基礎
?如果需要讓某個對象支持序列化機制,則必須讓對象所屬的類及其屬性是可序列化的踩蔚,為了讓某個類是可序列化的馅闽,該類必須實現(xiàn)如下兩個接口之一局骤。否則峦甩,會拋出NotSerializableException異常
?Serializable
?Externalizable

序列化的要求

?凡是實現(xiàn)Serializable接口的類都有一個表示序列化版本標識符的靜態(tài)變量:
?private static final long serialVersionUID;
?serialVersionUID用來表明類的不同版本間的兼容性凯傲。 簡言之冰单,其目的是以序列化對象
進行版本控制,有關各版本反序列化時是否兼容浴栽。
?如果類沒有顯示定義這個靜態(tài)常量,它的值是Java運行時環(huán)境根據(jù)類的內部細節(jié)自
動生成的甩挫。若類的實例變量做了修改,serialVersionUID 可能發(fā)生變化间护。故建議汁尺,顯式聲明痴突。
? 簡單來說辽装,Java的序列化機制是通過在運行時判斷類的serialVersionUID來驗證版本一致性的殉挽。在進行反序列化時,JVM會把傳來的字節(jié)流中的
serialVersionUID與本地相應實體類的serialVersionUID進行比較一死,如果相同
就認為是一致的摘符,可以進行反序列化逛裤,否則就會出現(xiàn)序列化版本不一致的異
常带族。(InvalidCastException)

若某個類實現(xiàn)了 Serializable 接口,該類的對象就是可序列化的:
創(chuàng)建一個 ObjectOutputStream
調用 ObjectOutputStream 對象的 writeObject( 對象) 方法輸出可 序列化對象
? 注意寫出一次择克,操作flush() 一次
?反序列化
?個 創(chuàng)建一個 ObjectInputStream
?用 調用 readObject() 方法讀取流中的對象
? 強調:如果某個類的屬性不是基本數(shù)據(jù)類型或 String 類型肚邢,而是另一個
引用類型骡湖,那么這個引用類型必須是可序列化的响蕴,否則擁有該類型的
Field 的類也不能序列化

談談你對java.io.Serializable 接口的理解浦夷,我們知道它用于序列化,是空方法接口誓禁,還有其它認識嗎摹恰?

? 實現(xiàn)了Serializable 接口的對象俗慈,可將它們轉換成一系列字節(jié)闺阱,并可在以后完全恢復回原來的樣子酣溃。 這一過程亦可通過網(wǎng)絡進行赊豌。這意味著序列化機
制能自動補償操作系統(tǒng)間的差異碘饼。在 換句話說艾恼,可以先在Windows 機器上創(chuàng)建一個對象舆声,對其序列化纳寂,然后通過網(wǎng)絡發(fā)給一臺Unix 機器毙芜,然后在那里
準確無誤地重新“裝配”腋粥。不必關心數(shù)據(jù)在不同機器上如何表示,也不必
關心字節(jié)的順序或者其他任何細節(jié)展辞。
? 由于大部分作為參數(shù)的類如String 罗珍、Integer 等都實現(xiàn)了
java.io.Serializable 的接口覆旱,也可以利用多態(tài)的性質藕坯,作為參數(shù)使接口更
靈活炼彪。

自定義類可序列化的其它要求
public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    private String username;
    private String password;
    private String email;
    private int age;

    public User(String username, String password, String email, int age) {
        this.username = username;
        this.password = password;
        this.email = email;
        this.age = age;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                '}';
    }
}
public class ObjectOutputStreamTest {
    public static void main(String[] args) {
        obj();
        objReturn();
    }

    public static void objReturn() {
        ObjectInputStream in = null;
        try {
            in = new ObjectInputStream(new FileInputStream("data1.bin"));
            User user = (User)in.readObject();
            System.out.println(user);
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
        }
    }

    public static void obj(){
        try {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("data1.bin"));
            oos.writeObject(new User("haxi","qweq","icanci@163.com",18));
            oos.flush();
            oos.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }
}
RandomAccessFile 實現(xiàn)數(shù)據(jù)的讀寫操作

?RandomAccessFile 聲明在java.io包下朋腋,但直接繼承于java.lang.Object類旭咽。并且它實現(xiàn)了DataInput、DataOutput這兩個接口,也就意味著這個類既可以讀也可以寫勾缭。
?RandomAccessFile 類支持 “隨機訪問” 的方式俩由,程序可以直接跳到文件的任意地方來 讀、寫文件
?支持只訪問文件的部分內容
?可以向已存在的文件后追加內容
?RandomAccessFile 對象包含一個記錄指針碘梢,用以標示當前讀寫處的置煞躬。
RandomAccessFile 類對象可以自由移動記錄指針:
?long getFilePointer():獲取文件記錄指針的當前位置
?void seek(long pos):將文件記錄指針定位到 pos 位置
? 構造器
?public RandomAccessFile(File file, String mode)
?public RandomAccessFile(String name, String mode)
?創(chuàng)建 RandomAccessFile 類實例需要指定一個 mode 參數(shù)在扰,該參數(shù)指定 RandomAccessFile 的訪問模式:
?r: 以只讀方式打開
?rw :打開以便讀取和寫入
?rwd: 打開以便讀取和 寫入健田;同步文件內容的更新
?rws: 打開以便讀取和 寫入总放; 同步文件內容和元數(shù)據(jù) 的 更新
? 如果模式為只讀r甥啄。則不會創(chuàng)建文件炬搭,而是會去讀取一個已經存在的文件蜈漓,
如果讀取的文件不存在則會出現(xiàn)異常。 如果模式為rw讀寫宫盔。如果文件不存在則會去創(chuàng)建文件融虽,如果存在則不會創(chuàng)建。

可以用RandomAccessFile這個類灼芭,來實現(xiàn)一個多線程斷點下載的功能有额,
用過下載工具的朋友們都知道,下載前都會建立兩個臨時文件彼绷,一個是與
被下載文件大小相同的空文件,另一個是記錄文件指針的位置文件腻菇,每次
暫停的時候丘薛,都會保存上一次的指針希坚,然后斷點下載的時候聊疲,會繼續(xù)從上
一次的地方下載贡珊,從而實現(xiàn)斷點下載或上傳的功能

RandomAccessFile 實現(xiàn)數(shù)據(jù)的插入

思路:
1.記錄從哪兒開始的位置 seek();
2.然后把后面的數(shù)據(jù)存儲到 StringBuffer中
3.然后調回指針 到插入位置
4.然后把需要插入的元素插入
5.然后再把StringBuffer 中的元素尾部插入
6.完成

NIO 介紹及 NIO 中 Path蒜鸡、Paths忘朝、Files 的介紹

? Java NIO (New IO悦昵,Non-Blocking IO)是從Java 1.4版本開始引入的一套新
的IO API棋凳,可以替代標準的Java IO API。NIO與原來的IO有同樣的作用和目
的莫湘,但是使用的方式完全不同,NIO支持面向緩沖區(qū)的(IO是面向流的)、基于
通道的IO操作。NIO將以更加高效的方式進行文件的讀寫操作耕渴。
? Java API中提供了兩套NIO屁桑,一套是針對標準輸入輸出NIO盆偿,另一套就是網(wǎng)
絡編程NIO。
?|-----java.nio.channels.Channel
?|-----FileChannel:處理本地文件
?|-----SocketChannel:TCP網(wǎng)絡編程的客戶端的Channel
?|-----ServerSocketChannel:TCP網(wǎng)絡編程的服務器端的Channel
?|-----DatagramChannel:UDP網(wǎng)絡編程中發(fā)送端和接收端的Channel

隨著 JDK 7 的發(fā)布涵亏,Java對NIO進行了極大的擴展,增強了對
文件處理和文件系統(tǒng)特性的支持,以至于我們稱他們?yōu)?NIO.2冰垄。因為 NIO 提供的一些功能蝴罪,NIO已經成為文件處理中越來越重要的部分。

Path 缘琅、Paths 和Files 核心API
? 早期的Java只提供了一個File類來訪問文件系統(tǒng)居暖,但File類的功能比較有限最住,所提供的方法性能也不高。而且,大多數(shù)方法在出錯時僅返回失敗,并不會提供異常信息逢勾。
? NIO. 2為了彌補這種不足句占,引入了Path接口,代表一個平臺無關的平臺路徑塌碌,描述了目錄結構中文件的位置。Path可以看成是File類的升級版本俊扳,實際引用的資源也可以不存在畜隶。
? 在以前IO操作都是這樣寫的:
import java.io.File;
File file = new File("index.html");
? 但在Java7 中,我們可以這樣寫:
import java.nio.file.Path;
import java.nio.file.Paths;
Path path = Paths.get("index.html");

? 同時峡捡,NIO.2在java.nio.file包下還提供了Files械拍、Paths工具類,F(xiàn)iles包含
了大量靜態(tài)的工具方法來操作文件绑谣;Paths則包含了兩個返回Path的靜態(tài)
工廠方法。
? Paths 類提供的靜態(tài) get() 方法用來獲取 Path 對象:
?static Path get(String first, String … more) : 用于將多個字符串串連成路徑
?static Path get(URI uri): 返回指定uri對應的Path路徑

? Path 常用方法:
? String toString() : 返回調用 Path 對象的字符串表示形式
? boolean startsWith(String path) : 判斷是否以 path 路徑開始
? boolean endsWith(String path) : 判斷是否以 path 路徑結束
? boolean isAbsolute() : 判斷是否是絕對路徑
? Path getParent() :返回Path對象包含整個路徑,不包含 Path 對象指定的文件路徑
? Path getRoot() :返回調用 Path 對象的根路徑
? Path getFileName() : 返回與調用 Path 對象關聯(lián)的文件名
? int getNameCount() : 返回Path 根目錄后面元素的數(shù)量
? Path getName(int idx) : 返回指定索引位置 idx 的路徑名稱
? Path toAbsolutePath() : 作為絕對路徑返回調用 Path 對象
? Path resolve(Path p) :合并兩個路徑,返回合并后的路徑對應的Path對象
? File toFile(): 將Path轉化為File類的對象

? java.nio.file.Files 用于操作文件或目錄的工具類纱扭。
? Files 常用方法:
? Path copy(Path src, Path dest, CopyOption … how) : 文件的復制
? Path createDirectory(Path path, FileAttribute<?> … attr) : 創(chuàng)建一個目錄
? Path createFile(Path path, FileAttribute<?> … arr) : 創(chuàng)建一個文件
? void delete(Path path) : 刪除一個文件/目錄岳锁,如果不存在,執(zhí)行報錯
? void deleteIfExists(Path path) : Path對應的文件/目錄如果存在蹦魔,執(zhí)行刪除
? Path move(Path src, Path dest, CopyOption…h(huán)ow) : 將 src 移動到 dest 位置
? long size(Path path) : 返回 path 指定文件的大小

? Files 常用方法:用于判斷
? boolean exists(Path path, LinkOption … opts) : 判斷文件是否存在
? boolean isDirectory(Path path, LinkOption … opts) : 判斷是否是目錄
? boolean isRegularFile(Path path, LinkOption … opts) : 判斷是否是文件
? boolean isHidden(Path path) : 判斷是否是隱藏文件
? boolean isReadable(Path path) : 判斷文件是否可讀
? boolean isWritable(Path path) : 判斷文件是否可寫
? boolean notExists(Path path, LinkOption … opts) : 判斷文件是否不存在
? Files 常用方法:用于操作內容
? SeekableByteChannel newByteChannel(Path path, OpenOption…h(huán)ow) : 獲取與指定文件的連
接激率,how 指定打開方式。
? DirectoryStream<Path> newDirectoryStream(Path path) : 打開 path 指定的目錄
? InputStream newInputStream(Path path, OpenOption…h(huán)ow):獲取 InputStream 對象
? OutputStream newOutputStream(Path path, OpenOption…h(huán)ow) : 獲取 OutputStream 對象

使用第三方 jar 包實現(xiàn)數(shù)據(jù)讀寫

commons-io-2.5.jar

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末勿决,一起剝皮案震驚了整個濱河市乒躺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌低缩,老刑警劉巖嘉冒,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異咆繁,居然都是意外死亡讳推,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進店門玩般,熙熙樓的掌柜王于貴愁眉苦臉地迎上來银觅,“玉大人,你說我怎么就攤上這事壤短∩枘猓” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵久脯,是天一觀的道長。 經常有香客問我镰吆,道長帘撰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任万皿,我火速辦了婚禮摧找,結果婚禮上核行,老公的妹妹穿的比我還像新娘。我一直安慰自己蹬耘,他們只是感情好芝雪,可當我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著综苔,像睡著了一般惩系。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上如筛,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天堡牡,我揣著相機與錄音,去河邊找鬼杨刨。 笑死晤柄,一個胖子當著我的面吹牛妖胀,可吹牛的內容都是我干的芥颈。 我是一名探鬼主播赚抡,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼闯估,長吁一口氣:“原來是場噩夢啊……” “哼刚夺!你這毒婦竟也來了侠姑?” 一聲冷哼從身側響起莽红,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤鬼店,失蹤者是張志新(化名)和其女友劉穎罗捎,沒想到半個月后捉偏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體讹躯,經...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡萝究,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年栽连,在試婚紗的時候發(fā)現(xiàn)自己被綠了下面。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡玷氏,死狀恐怖,靈堂內的尸體忽然破棺而出诗宣,到底是詐尸還是另有隱情篮灼,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布换薄,位于F島的核電站玉雾,受9級特大地震影響,放射性物質發(fā)生泄漏轻要。R本人自食惡果不足惜复旬,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一稀蟋、第九天 我趴在偏房一處隱蔽的房頂上張望搬泥。 院中可真熱鬧缴淋,春花似錦封锉、人聲如沸误趴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽浩淘。三九已至咳焚,卻和暖如春洽损,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背革半。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工碑定, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人又官。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓延刘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親六敬。 傳聞我的和親對象是個殘疾皇子碘赖,可洞房花燭夜當晚...
    茶點故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內容