Java IO流

IO(Input/Output)流

  • IO流用來處理設(shè)備之間的數(shù)據(jù)傳輸
  • Java對數(shù)據(jù)的操作是通過流的方式
  • Java用于操作流的對象都在IO包中
  • 流按操作數(shù)據(jù)分為兩種:字節(jié)流于字符流
  • 流按流向分為:輸入流和輸出流

字符流由來就是:早期的字節(jié)流 + 編碼表,為了更便于操作文字?jǐn)?shù)據(jù)

IO操作流程.png

IO流常用基類

所屬包:java.io

  • 字節(jié)流的抽象基類(二進(jìn)制)
    • InputStream
    • OutputStream
  • 字符流的抽象基類(文字編碼)
    • Reader
    • Writer
  • 注意:有這四個(gè)類派生出來的子類名稱都是以其父類名字作為子類的后綴记盒,子類的前綴名就是該功能。例如:
    • InputStream派生類:FileInputStream
    • Reader派生類:FileReader
    • OutputStream派生類:FileOutputStream
    • Writer派生類:FileWriter

字節(jié)流(char)

FileWriter

需求:將一些文字存儲(chǔ)到硬盤一個(gè)文件中

/*  FileWriter
 *  要操作文字?jǐn)?shù)據(jù),優(yōu)先考慮字符流
 *  從內(nèi)存寫道硬盤使用輸出流Writer,硬盤的數(shù)據(jù)體現(xiàn)是文件
 */
package FileWriter;

import java.io.FileWriter;
import java.io.IOException;

public class FileWriterDemo {
    private static final String LINE_SEPARATOR = System.getProperty("line.separator");  // 換行符

    public static void main(String[] args) throws IOException {
        // 創(chuàng)建一個(gè)可以往文件中寫入字符數(shù)據(jù)的字符輸出流對象
        /*
         *  既讓是往文件中寫入一個(gè)文字?jǐn)?shù)據(jù)咧擂,那么在創(chuàng)建對象時(shí)宫患,就必須明確該文件(用于存儲(chǔ)數(shù)據(jù)的目的地)
         *  如果文件不存在麦到,則會(huì)自動(dòng)創(chuàng)建
         *  如果文件存在镀梭,則會(huì)被覆蓋
         */
        FileWriter fileWriter = new FileWriter("F:\\demo.txt");

        // 調(diào)用Writer對象中的write(String)方法刀森,寫入數(shù)據(jù),放入臨時(shí)緩沖區(qū)
        fileWriter.write("hello zimo !");
        // 刷新緩沖區(qū)报账,寫入文件中
        fileWriter.flush();
        // 文件末尾追加文字?jǐn)?shù)據(jù)
        fileWriter.append(LINE_SEPARATOR+"hello world !");
        // 關(guān)閉流前,會(huì)自動(dòng)刷新緩沖區(qū)后關(guān)閉
        fileWriter.close();
        // 關(guān)閉后無法操作刷新和寫操作
        fileWriter.write("ccc");    // err

        FileWriter fileWriter1 = new FileWriter("F:\\demo1.txt",true);  // 如果構(gòu)造中加入true,可以對文件進(jìn)行續(xù)寫
        fileWriter1.write("aaaaaaa");
        fileWriter1.write("bbbbbbb");
        fileWriter1.close();        // aaaaaaabbbbbbb
    }
}
FileReader

需求:讀取文件內(nèi)容輸出到控制臺上

/*  FileReader
 *  要操作文字?jǐn)?shù)據(jù)埠偿,優(yōu)先考慮字符流
 *  從文件文件讀到磁盤使用輸出流Reader
 */
package IOTest.FileReader;

import java.io.FileReader;
import java.io.IOException;

public class FileReaderDemo {
    public static void main(String[] args) throws IOException {
        // 創(chuàng)建一個(gè)讀取字符數(shù)據(jù)流的對象,用讀取流關(guān)聯(lián)一個(gè)已存在文件
        FileReader fileReader = new FileReader("f:\\demo.txt");

        // 用Reader中的read方法讀取字符,每次讀取一個(gè)字符
        int ch = 0;
        while ((ch = fileReader.read()) != -1){
            System.out.println((char) ch);
        }
        fileReader.close();

        // 用read(char[])讀取文本文件數(shù)據(jù)
        FileReader fw = new FileReader("f:\\demo.txt");

        char[] buf = new char[1024];    // 1024的整數(shù)倍
        int len = 0;
        while((len = fw.read(buf)) != -1){
            System.out.println(new String(buf, 0, len));
        }
    }
}

IOException異常處理
package IOTest.IOExceptionCatch;

import java.io.FileWriter;
import java.io.IOException;

public class IOExceptionDemo {
    private static final String LINE_SEPARATOR = System.getProperty("line.separator");  // 換行符

    public static void main(String[] args) {
        FileWriter fileWriter = null;
        try {
            fileWriter = new FileWriter("Z:\\demo.txt");
            fileWriter.write("hello zimo !");
            fileWriter.flush();
            fileWriter.append(LINE_SEPARATOR + "hello world !");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileWriter != null) {
                try {
                    fileWriter.close();
                } catch (IOException e) {
                    throw new RuntimeException("關(guān)閉異常透罢!");
                }
            }
        }
    }
}

練習(xí):讀取C盤的文件,寫入到D盤中去

package IOTest.CopyFile;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyFileDemo {
    public static void main(String[] args) throws IOException {

        // 1.讀取已有的文本文件冠蒋,使用字符讀取流和文件相關(guān)聯(lián)
        FileReader fileReader = new FileReader("C:\\TextDemo.txt");
        // 2.創(chuàng)建一個(gè)目錄羽圃,用于存儲(chǔ)讀取到的數(shù)據(jù)
        FileWriter fileWriter = new FileWriter("D:\\CopyFileDemo.txt");

        // 3.頻繁的讀寫操作
        EveryCopyByByte(fileReader,fileWriter);
        EveryCopyByBuffer(fileReader,fileWriter);

        // 4.關(guān)閉流資源
        if(fileReader != null)
            fileReader.close();
        if(fileWriter != null)
            fileWriter.close();
    }

    // 每次讀取一個(gè)緩沖區(qū)
    private static void EveryCopyByBuffer(FileReader fileReader, FileWriter fileWriter) {
        char[] buff = new char[1024];
        int len = 0;
        try {
            while ((len = fileReader.read(buff)) != -1) {
                fileWriter.write(buff, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 每次讀取一個(gè)字符
    private static void EveryCopyByByte(FileReader fileReader, FileWriter fileWriter) throws IOException {
        int ch = 0;
        while ((ch = fileReader.read()) != -1) {
            fileWriter.write(ch);
        }
    }
}

復(fù)制文本文件圖解.png

字符流的緩沖區(qū)

  • 緩沖區(qū)的出現(xiàn)提高了對數(shù)據(jù)的讀寫效率
  • 對應(yīng)類
    • BufferedWriter
    • BufferedReader
  • 緩沖區(qū)要結(jié)合流才可以使用
  • 在流的基礎(chǔ)上對流的功能進(jìn)行了增強(qiáng)
BufferedWriter
  • newLine():換行符

緩沖區(qū)在緩沖對象時(shí)必須具備緩沖對象(流)

package IOTest.BufferWriter;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class BufferedWriterDemo {
    public static void main(String[] args) throws IOException {
        FileWriter fileWriter = new FileWriter("buf.txt");

        // 為了提高寫入效率,使用字符流的緩沖區(qū)
        // 創(chuàng)建了一個(gè)字符寫入流的緩沖區(qū)對象抖剿,并和指定要被緩沖的對象相關(guān)聯(lián)
        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

        // bufferedWriter.write("aaaaaaaaaa\r\nbbbbbbbb");
        bufferedWriter.write("aaaaaaaaaa");
        bufferedWriter.newLine();   // 緩沖區(qū)的換行符
        bufferedWriter.write("bbbbbbbb");

        // 使用緩沖區(qū)的寫入方法將數(shù)據(jù)寫入到緩沖區(qū)中
        bufferedWriter.flush();
        // 關(guān)閉緩沖區(qū)朽寞,其實(shí)關(guān)閉了緩沖區(qū)的流對象fileWriter,close();
        bufferedWriter.close();
    }
}
BufferedReader
  • readLine():讀取一行
package IOTest.BufferReader;

import java.io.BufferedReader;
import java.io.FileReader;

public class BurreredWriterDemo {
    public static void main(String[] args) {
        FileReader fileReader = new FileReader("buf.txt");
        BufferedReader bufferedReader = new BufferedReader(fileReader);

        String line = null;
        while ((line = bufferedReader.readLine()) != null){
            System.out.println(line);
        }
    }
}

readLine方法原理.png

練習(xí):使用緩沖區(qū)拷貝文本文件

package IOTest.BufferRW;

import java.io.*;

public class BufferCopyFileDemo {
    public static void main(String[] args) throws IOException {
        FileReader fileReader = new FileReader("test.txt");
        BufferedReader bufferedReader = new BufferedReader(fileReader);

        FileWriter fileWriter = new FileWriter("copy_test.txt");
        BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

        /*int ch = 0;
        while ((ch = bufferedReader.read()) != -1){
            bufferedWriter.write(ch);
        }*/

        String line = null;
        while ((line = bufferedReader.readLine())!= null){
            bufferedWriter.write(line);
            bufferedWriter.newLine();
            bufferedWriter.flush();
        }

        bufferedReader.close();
        bufferedWriter.close();
    }
}

練習(xí):自定義讀取緩沖區(qū)

// 模擬BufferedReader
package IOTest.BufferRW;

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
/*
分析:
 *  緩沖區(qū)無非就是封裝了一個(gè)數(shù)組
 *  并對外提供了更多的方法對數(shù)組進(jìn)行訪問
 *  其實(shí)最終操作的就是數(shù)組的角標(biāo)
 
原理:
 *  從源中獲取一批數(shù)據(jù)裝進(jìn)緩沖區(qū)
 *  在緩沖區(qū)中不斷取出一個(gè)個(gè)數(shù)據(jù)
 *  在此次取完后识窿,在從源中繼續(xù)取一批數(shù)據(jù)進(jìn)緩沖區(qū)
 *  當(dāng)源中的數(shù)據(jù)取完,用-1作為結(jié)束標(biāo)記
 */
public class MyBufferedReader /*extends Reader*/ {

    private FileReader fileReader;
    /*private Reader reader;*/
    
    // 定一個(gè)數(shù)組作為緩沖區(qū)
    private char[] buf = new char[1024];

    // 定義一個(gè)指針用于操作這個(gè)數(shù)組中的元素脑融。操作到最后一個(gè)元素喻频,指針歸零
    private int ptr = 0;

    // 定義一個(gè)計(jì)數(shù)器用于記錄緩沖區(qū)中的數(shù)據(jù)個(gè)數(shù)。當(dāng)該數(shù)據(jù)減到0肘迎,就從源中繼續(xù)獲取數(shù)據(jù)到緩沖區(qū)中
    private int count = 0;

    MyBufferedReader(FileReader fileReader){
        this.fileReader =fileReader;
    }
    /*
    MyBufferedReader(Reader reader){
        this.reader =reader;
    }
    */
    public int myRead() throws IOException {
        // 1.從源中獲取一批數(shù)據(jù)到緩沖區(qū)中甥温。需要先判斷計(jì)數(shù)器為0時(shí),才需要從源中獲取數(shù)據(jù)
        if (count == 0){
            count = fileReader.read(buf);
            ptr = 0;
        }
        if (count < 0)
            return -1;
        char ch = buf[ptr++];
        count--;
        return ch;
    }

    public String myReadLine() throws IOException {
        StringBuilder stringBuilder = new StringBuilder();
        int ch = 0;
        while ((ch = myRead()) != -1){
            if (ch == '\r')
                continue;
            if (ch == '\n')
                return stringBuilder.toString();
            // 將從緩沖區(qū)讀取到的字符妓布,存儲(chǔ)到緩存行數(shù)據(jù)的緩沖區(qū)中
            stringBuilder.append((char)ch);
        }
        if (stringBuilder.length()!= 0){
            return stringBuilder.toString();
        }
        return null;
    }
    public void myClose() throws IOException {
        fileReader.close();
    }
    /*
    @Override
    public int read(char[] cbuf, int off, int len) throws IOException{
        return 0;
    }
    @Override
    public void close() throws IOException{
        
    }
    */
}
LineNumberReader:

裝飾類姻蚓,行號讀取追蹤

public static void main(String[] args) throws IOException{
    FileReader fr = new FileReader("demo.txt");
    LineNumberReader lnr = new LineNumberReader(fr);
    
    String line = null;
    // lnr.setLineNumber(100);  // 默認(rèn)從0開始,開始讀取一行就變成1匣沼,可以手動(dòng)設(shè)置100
    while ((line = lnr.readLine()) != null){
        System.out.println(lnr.getLineNumber() + ":" +line);
    }
}

裝飾設(shè)計(jì)模式

對一組對象的功能進(jìn)行增強(qiáng)時(shí)狰挡,就可以使用該模式進(jìn)行問題的解決

class Person{
    void eat(){
        System.out.println("吃飯");
    }
}
// 這個(gè)類是為了增強(qiáng)Person而出現(xiàn)的
class NewPerson{
    private Person p;       // 本質(zhì)還是Person
    NewPerson(Person p){
        this.p = p;
    }
    public void eat(){      // 外觀進(jìn)行了升級 
        System.out.println("開胃酒");
        p.eat();
        System.out.println("飯后甜點(diǎn)");
    }
}
public static void main(String[] args){
    Person p = new Person();
    NewPerson p1 = new NewPerson(p);
    p1.eat();
}
// 繼承同樣可以實(shí)現(xiàn)效果
class NewPersonExtends extends Person{
        public void eat(){
        System.out.println("開胃酒");
        super.eat();
        System.out.println("飯后甜點(diǎn)");
    }
}
繼承和裝飾的區(qū)別:
  • 假設(shè)的基礎(chǔ)體系:
  • Writer:
    • | -- TextWriter:用于操作文本的流對象
    • | -- MediaWriter:用于操作媒體的流對象

想要對操作的動(dòng)作進(jìn)行效率的提高,按照面向?qū)ο笏枷胧吞危梢酝ㄟ^繼承對功能進(jìn)行擴(kuò)展加叁。

  • 效率提高需要加入緩沖技術(shù)
  • Writer:(繼承實(shí)現(xiàn))
    • | -- TextWriter:用于操作文本
      • | -- BufferTextWriter:加入了緩沖技術(shù)的操作文本流對象
    • | -- MediaWriter:用于操作媒體
      • | -- BufferMediaWriter:加入了緩沖技術(shù)的操作媒體流對象

如果體系再次進(jìn)行功能擴(kuò)展,又多了一個(gè)流對象枢贿,是否要產(chǎn)生子類殉农?

  • 是,這時(shí)就會(huì)發(fā)現(xiàn)只為了提高功能局荚,進(jìn)行的繼承超凳,導(dǎo)致繼承體系越來越臃腫,繼承實(shí)現(xiàn)不夠靈活

加入的都是同一種技術(shù) --- 緩沖技術(shù)

前一種是讓緩沖和具體的對象相結(jié)合耀态,可以將緩沖進(jìn)行單獨(dú)的封裝轮傍,哪個(gè)對象需要緩沖就將哪個(gè)對象和緩沖進(jìn)行關(guān)聯(lián)

  • Writer:
    • | -- TextWriter:用于操作文本的流對象
    • | -- MediaWriter:用于操作媒體的流對象
    • | -- BufferWriter:用于提高效率

裝飾比繼承靈活

class Buffer{
    // 一次增強(qiáng)一個(gè)流對象的功能
    Buffer(TextWriter w){}
    Buffer(MediaWriter w){}
}
class BufferWriter extends Writer{
    // 一次增強(qiáng)一個(gè)體系的功能
    Buffer(Writer w){}
}

\color{blue}{特點(diǎn):裝飾類和被裝飾類都必須所屬同一個(gè)接口或者父類}

字符流(byte)

  • 基本操作與字符流類相同
  • 但它不僅僅可以操作字符,還可以操作其他媒體文件
  • 例子:Copy一個(gè)jpg文件
package ByteStream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class ByteStreamDemo {
    public static void main(String[] args) throws IOException {
        writeDemo();
        readDemo();
    }

    private static void readDemo() throws IOException {
        // 1.創(chuàng)建一個(gè)讀取流對象首装,和指定的文件進(jìn)行關(guān)聯(lián)
        FileInputStream fileInputStream = new FileInputStream("byteTest.txt");

        // 2.讀取字符,一次讀取一個(gè)字符
        /*
        int ch = 0;
        while ((ch = fileInputStream.read()) != -1){
            System.out.println((char) ch);
        }

        // 2.讀取字符,一次讀取一個(gè)指定大小的緩沖區(qū)创夜,建議使用這個(gè)
        byte[] buf = new byte[1024];
        int len = 0;
        while ((len = fileInputStream.read(buf)) != -1){
            System.out.println(new String(buf, 0, len));
        }
        */

        // 2.讀取字符,一次讀取一個(gè)剛好的緩沖區(qū)
        // fileInputStream.available()      返回一個(gè)文件的字節(jié)大小,慎用仙逻,如果文件太大驰吓,內(nèi)存會(huì)崩潰
        byte[] buf = new byte[fileInputStream.available()];
        System.out.println(new String(buf));

        // 3.關(guān)閉字節(jié)流對象
        fileInputStream.close();
    }

    private static void writeDemo() throws IOException {
        // 1.創(chuàng)建字節(jié)輸出流對象,用于操作文件
        FileOutputStream fileOutputStream = new FileOutputStream("byteTest.txt");

        // 2.寫數(shù)據(jù)系奉,直接寫入到目標(biāo)文件檬贰,flush沒有意義
        fileOutputStream.write("hello zimo!".getBytes());

        // 緩沖區(qū)需要刷新,字節(jié)流不需要刷新
        // fileOutputStream.flush();

        // 3.關(guān)閉字節(jié)流對象
        fileOutputStream.close();
    }
}

練習(xí):復(fù)制Mp3文件

package CopyByte;

import java.io.*;

public class CopyMp3Demo {
    public static void main(String[] args) throws IOException {
        copyMp3();
        copyMp3Buffer();
    }
    // 緩沖區(qū)緩沖
    private static void copyMp3Buffer() throws IOException {
        FileInputStream fileInputStream = new FileInputStream("C:\\大悲咒.mp3");
        BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
        FileOutputStream fileOutputStream = new FileOutputStream("C:\\大悲咒-副本.mp3");
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);

        int ch = 0;
        while ((ch = bufferedInputStream.read()) != -1){
            bufferedOutputStream.write(ch);
            // bufferedOutputStream.flush();
        }
        bufferedInputStream.close();
        bufferedOutputStream.close();
    }
    // 自定義緩沖區(qū)
    private static void copyMp3() throws IOException {
        FileInputStream fileInputStream = new FileInputStream("C:\\大悲咒.mp3");
        FileOutputStream fileOutputStream = new FileOutputStream("C:\\大悲咒-副本.mp3");

        byte[] buf = new byte[1024];

        int len = 0;
        while ((len = fileInputStream.read(buf)) != -1){
            fileOutputStream.write(buf,0, len);
        }
        fileInputStream.close();
        fileOutputStream.close();
    }
}

不要使用字符流拷貝圖片文件缺亮,可能存在字符解析異常

// 讀取一個(gè)鍵盤錄入的數(shù)據(jù)翁涤,并打印在控制臺上。
    public static void main(String[] args) throws IOException {
        InputStream inputStream = System.in;

        int ch = inputStream.read();    // 阻塞式方法
        System.out.println(ch);

        inputStream.close();    // 標(biāo)準(zhǔn)流對象只有這一個(gè),建議不用關(guān)葵礼,隨著系統(tǒng)消失自動(dòng)關(guān)閉

        InputStream inputStream2 = System.in;
        ch = inputStream.read();    // err:標(biāo)準(zhǔn)輸入流已經(jīng)被關(guān)閉了
    }
  • 標(biāo)準(zhǔn)輸入/輸出設(shè)備流号阿,通常情況下不需要關(guān)閉
public static void main(String[] args) throws IOException {
    StringBuilder sb = new StringBuilder()
    InputStream inputStream = System.in;
    int ch = 0;
    while((ch  = inputStream.read()) != -1){
        if(ch == '\r')continue;
        if(ch == '\n'){
            String tmp = sb.toString();
            if("over".equals(tmp)){
                break;
            }
            System.out.println(tmp.toUpperCase());
            sb.delete(0, sb.length());
        }else
            sb.append((char)ch);
    }
}

轉(zhuǎn)換流

1) 將字節(jié)流轉(zhuǎn)成字符流:InputStreamReader(解碼)

public static void main(String[] args){
    // 字節(jié)流
    InputStream in = System.in;
    // 將字節(jié)轉(zhuǎn)成字符的橋梁,轉(zhuǎn)換流
    InputStreamReader isr = new InputStreamReader(in);
    // 字符流
    BufferedReader buffer = new BufferedReader(isr);
    String line = null;
    while((line - buffer.readLine())!= null){
        if("over".equals(line))break;
        System.out.println(line.toUpperCase());
    }
}

2) 將字符轉(zhuǎn)成字節(jié)流:OutputStreamWriter(編碼)

public static void main(String[] args){
    OutputStream out = System.out;
    OutputStreamWriter osw = new OutputStreamWriter(out);
    String line = null;
    osw.write(line.toUpperCase() + "\r\n");
    osw.flush();        // 編碼完刷新一下緩沖區(qū)
    
    BufferedWriter buffer = new BufferedWriter(osw);
    buffer.write(line.toUpperCase());
    buffer.newLine();
    buffer.flush();
}
  • 簡化代碼
public static void main(String[] args){
    BufferedReader buffReader = new BufferedReader(new InputStreamReader(System.in));   // 鍵盤讀入
    BufferedWriter buffWriter = new BufferedWriter(new OutputStreamWriter(System.out)); // 輸出到控制臺
    //BufferedWriter buffWriter = new BufferedWriter(new FileOutputStream("a.txt"));    // 輸出到a.txt
    
    String line = null;
    while((line = buffReader.readLine()) != null){
        if("over".equals(line))break;
        buffWriter.write(line.toUpperCase());
        buffWriter.newLine();
        buffWriter.flush();
    }
}
轉(zhuǎn)換流.png

流的操作基本規(guī)律

  • 四個(gè)明確:

    1. 明確源和目的(匯)

      • 源:InputStream鸳粉、Reader
      • 目的:OutputStream扔涧、Writer
    2. 明確數(shù)據(jù)是否是純文本數(shù)據(jù)

      • 源:

        1. 是純文本:Reader
        2. 不是純文本:InputStream
      • 目的:

        1. 是純文本:Writer
        2. 不是純文本:OutputStream
    3. 明確具體的設(shè)備

      • 源:
        1. 硬盤:File
        2. 鍵盤:System.in
        3. 內(nèi)存:數(shù)組
        4. 網(wǎng)絡(luò):Socket流
      • 目標(biāo):
        1. 硬盤:File
        2. 控制臺:System.out
        3. 內(nèi)存:數(shù)組
        4. 網(wǎng)絡(luò):Socket流
    4. 是否需要額外功能

      1. 是否需要高效(緩沖區(qū)): + buffer
      2. 是否需要轉(zhuǎn)換: + InputStreamReader、OutputStreamWriter
    5. 如果需求中明確指定碼表編碼的動(dòng)作

      • 不能使用FileWriter赁严,因?yàn)閮?nèi)部使用的默認(rèn)本地編碼表
      • 只能使用其父類OutputStreamWriter
      • OutputStreamWriter接收一個(gè)字符輸出流對象扰柠,既然操作文件,那么應(yīng)該使用FileOutputStream
public static void main(String[] args){
    OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"),"UTF-8");
    // FileWriter fw = new FileWriter("a.txt"); // 等同于 OutputStreamWriter("a.txt")默認(rèn)構(gòu)造函數(shù)
    /**
     * FileWriter:實(shí)際上就是默認(rèn)本機(jī)編碼表疼约,默認(rèn)編碼表操作文件的便捷類
     * 需要明確指定的編碼卤档,不能使用FileWriter類
     */
    osw.write("你好");
    osw.close();
}

什么時(shí)候使用轉(zhuǎn)換流?

  1. 源或目的對應(yīng)設(shè)備是字節(jié)流程剥,但操作的是文本數(shù)據(jù)劝枣,可以作為轉(zhuǎn)換橋梁,提高對文本操作的便捷
  2. 一旦操作文本涉及到具體指定的編碼表時(shí)织鲸,必須使用轉(zhuǎn)換流

File類

  • 用來將文件或者文件夾封裝成對象
  • 方便對文件與文件夾的屬性信息進(jìn)行操作
  • File對象可以作為參數(shù)傳遞給流的構(gòu)造函數(shù)
  • File類中的常用方法
public static void main(String[] args){
    // 將一個(gè)已存在或者不存在的文件或者目錄封裝成file對象 
    File file = new File("c:\\a.txt");
    File file1 = new File("c:\\", "a.txt");
    File file2 = new File("c:\\");
    File file3 = new File(file2, "a.txt");
    File file4 = new File("c:" + System.getProperty + "abc" + File.separator + "a.txt");
}
  • 常用方法分類:
    1. 獲忍蛱凇:
      • 獲取文件名稱:String getName()
      • 獲取文件路徑:String getPath() | String getAbsolutePath()
      • 獲取文件大小:Long length()
      • 獲取文件修改時(shí)間:Long lastModified()
      • 獲取文件父目錄:String getParent()如果是相對路徑搂擦,則獲取不到父目錄
    2. 創(chuàng)建與刪除:
      • 創(chuàng)建文件:boolean createNewFile() 如果文本不存在則創(chuàng)建稳诚,如果存在不創(chuàng)建
      • 創(chuàng)建文件夾:boolean mkdir() | boolean mkdirs()
      • 刪除文件:boolean delete() 直接刪除 boolean deleteOnExit() 結(jié)束后刪除
    3. 判斷:
      • 是否存在:boolean exists()
      • 是否文件:boolean isFile()
      • 是否目錄:boolean isDirectory()
    4. 其他:
      • 重命名/剪切:boolean renameTo(File f1)
      • 列出根目錄下文件:static File listRoots()
      • 可用磁盤空間:long getFreeSpace()
      • 總磁盤容量:long getTotalSpace()
      • 已用磁盤空間:long getUsableSpace()
      • 獲取目錄名稱:String[] list() 包含隱藏文件(如果對象是文件或者是系統(tǒng)級,會(huì)拋出異常)
      • 獲取目錄對象:File[] listFiles()
// 文件名過濾器:獲取路徑下所有.java文件
public class FilterByJava implements FilenameFilter{
    @Override
    public boolean accept(File dir, String name){
        return name.endsWith(".java");
    }
}
// 文件過濾器:過濾隱藏文件
public class FilterByHidden implements FilenameFilter{
    @Override
    public boolean accept(File pathname){
        return !pathname.isHidden();
    }
}
//測試
public static void main(String[] args){
    File dir = new File("D:\\");
    String[] names = dir.list(new FilterByJava());
    for(String name : names){
        System.out.println(name);
    }
    File[] names = dir.list(new FilterByHidden());
    for(String name : names){
        System.out.println(name);
    }
}
文件過濾器解析.png

深度遍歷文件夾(遞歸方式)

import java.io.File;

public class test {
    public static void main(String[] args){
        File file = new File("F:\\JavaTest");
        int level = 0;
        listAll(file ,level);
    }

    public static void listAll(File file, int level) {
        System.out.println(getSpace(level) + file.getName());
        level++;
        File[] files = file.listFiles();
        for (File file1 : files){
            if (file1.isDirectory()){
                listAll(file1, level);
            }else {
                System.out.println(getSpace(level) + file1.getName());
            }
        }
    }

    private static String getSpace(int level) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("|--");
        for (int i = 0; i < level; i++){
//            stringBuilder.append("\t");
            stringBuilder.insert(0, "|\t");
        }
        return stringBuilder.toString();
    }
}

遞歸:自身直接或間接調(diào)用自身瀑踢。

一個(gè)功能在被重復(fù)使用扳还,并且每次使用時(shí),參與運(yùn)算的結(jié)果和上一次有關(guān)橱夭,可以用遞歸來解決問題

注意:遞歸一定要明確條件氨距,否則容易棧溢出,注意遞歸的次數(shù)

// 刪除一個(gè)有內(nèi)容的目錄
public static void main(String[] args){
    File file = new File("E:\\demo");
    removeDir(file);
}

public void removeDir(File file){
    File[] files = file.listFiles();
    for(File f : files){
        if(f.isDirectory()){
            removeDir(f);
        }else{
            f.delete();
        }
    }
    file.delete();
}
  • Map

    | ---- Hashtable

          | ---- Properties:
    

    Properties集合:

    • 特點(diǎn):
      1. 該集合中的鍵和值都是字符串類型
      2. 集合中的數(shù)據(jù)可以保存到流中棘劣,或者從流中獲取
      3. 通常該集合用于操作以鍵值對形式存在的配置文件
public static void main(String[] args) throws IOException {
    Properties prop = new Properties();
    // 存儲(chǔ)元素
    prop.setProperty("zhangsan","30");
    prop.setProperty("lisi","31");
    prop.setProperty("wangwu","29");
    prop.setProperty("zhaoliu","33");

    // 持久化存儲(chǔ)--->> 使用流將文件存儲(chǔ)到文件中
    FileOutputStream fos = new FileOutputStream("info.txt");
    
    // 將集合數(shù)據(jù)存儲(chǔ)到文件中去
    prop.store(fos, "name : age");
    fos.close();
    
    // 加載文件中的數(shù)據(jù)(鍵值對)到集合中
    // 使用讀取流
    FileInputStream fis = new FileInputStream("info.txt");
    prop.load(fis);
    prop.list(System.out);
}

模擬Properties.load方法

public static void myLoad() throws IOException{
    Properties prop = new Properties();
    BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
    
    String line = null;
    while((line = bufr.readLine()) != null){
        if(line.startsWith("#")) continue;
        String[] arr = line.split("=");
        prop.setProperty(arr[0], arr[1]);
    }
    prop.list(System.out);
    bufr.close();
}

修改Properties中的某一個(gè)鍵對應(yīng)的值

// 對已有的配置文件中的信息進(jìn)行修改
/**
 *  讀取這個(gè)文件
 *  將這個(gè)文件中的鍵值數(shù)據(jù)存儲(chǔ)到集合中
 *  通過集合對數(shù)據(jù)進(jìn)行修改
 *  再通過流將修改后的數(shù)據(jù)存儲(chǔ)到文件中
 */
public static void test() throws IOException{
    // 讀取這個(gè)文件
    File file = new File("info.txt");
    if(!file.exists()){
        // 文件不存在
        file.createNewFile();
    }
    FileReader fr = new FileReader("info.txt");
    
    // 創(chuàng)建集合存儲(chǔ)信息
    Properties prop = new Properties();
    // 將流中的信息存儲(chǔ)到集合中
    prop.load();
    
    // 修改
    prop.setProperty("wangwu", "16");
    FileWriter fw = new FileWriter(file);
    prop.store(fw, "");
    
    prop.list(System.out);
    fw.close();
    fr.close();
}

練習(xí):免費(fèi)試用程序5次俏让,之后請注冊再使用

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

public static void getAppCount() throws IOException{
    // 將配置文件封裝成File對象
    File countFile = new File("count.properties");
    if(!countFile.exists()){
        countFile.createNewFile();
    }
    FileInputStream fis = new FileInputStream(countFile);
    Properties prop = new Properties();
    prop.load(fis);
    
    // 從集合中獲取鍵的次數(shù)
    String value = prop.getProperty("time");
    int count = 0;
    if(value != null){
        count = Integer.parseInt(value);
        if(count >= 5){
            throw new RuntimeException("使用次數(shù)已到,請注冊茬暇,給錢首昔!");
        }
    }
    count++;
    prop.setProperty("time", count + "");
    FileOutputStream fos = new FileOutputStream(countFile);
    prop.store(fos, "");
    fos.close();
    fis.close();
}

打印流

  • PrintWriter與PrintStream
    • 可以直接操作輸入流和文件

PrintStream構(gòu)造函數(shù),接收三種類型的值:

  1. 字符串路徑
  2. File對象
  3. 字節(jié)輸出流

PrintWriter構(gòu)造函數(shù)糙俗,接收三種類型的值:

  1. 字符串路徑
  2. File對象
  3. 字節(jié)輸出流
  4. 字符輸出流
public static void main(String[] args){
    PrintStream out = new PrintStream("print.txt");
    out.write(97);          // a 
    out.write(609);         // a 只寫最低8位 0000-0000 0000-0000 0000-0010 0110-0001
    out.print(97);          // 97 將原有字符保持原樣沙廉,然后將數(shù)據(jù)打印到目的地
    out.close();
    ----------------------------------------------------------------------------------------------------
    // 字符打印流
    BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
    PrintWriter out = new PrintWriter(System.out);
    // PrintWriter out = new PrintWriter(System.out, true); 自動(dòng)刷新緩沖區(qū),無需調(diào)用flush
    String line = null;
    while((line = bufr.readLine()) != null){
        if("exit".equals(line)) break;
        out.println(line);
        out.flush();
    }
    out.close();
    bufr.close();
}

序列流

  • SequenceInputStream
    • 多個(gè)流進(jìn)行合并
// 將三個(gè)文件中內(nèi)容放到一個(gè)文件中去
public static void main(String[] args) throws IOException{
    /*
    Vector<FileInputStream> v = new Vector<FileInputStream>();
    v.add(new FileInputStream("1.txt"));
    v.add(new FileInputStream("2.txt"));
    v.add(new FileInputStream("3.txt"));
    Enumeration<FileInputStream> en = v.elements();
    */
    
    ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
    for(int i = 1; i <= 3; i++){
        al.add(new FileInputStream(i + ".txt"));
    }
    final Iterator<FileInputStream> it = al.iterator();
    /*
    Enumeration<FileInputStream> en = new Enumeration<FileInputStream>(){
        @Override
        public boolean hasMoreElements(){
            return it.hasNext();
        }
        @Override
        public FileInputStream nextElement(){
            return it.next();
        }
    };
    */
    Enumeration<FileInputStream> en = Collections.enumeration(al);
    SequenceInputStream sis = new SequenceInputStream(en);
    
    FileOutputStream fos = new FileOutputStream("4.txt");
    
    byte[] buf = new byte[1024];
    
    int len = 0;
    while((len = sis.read(buf)) != -1){
        fos.write(buf, 0, len);
    }
    fos.close();
    sis.close();
}

文件切割

public static void main(String[] args){
    private static final int ONE_M = 1024 * 1024;
    File file = new File("C:\\0.bmp");
    // 用讀取流關(guān)聯(lián)源文件
    FileInputStream fis = new FileInputStream(file);
    // 定義一個(gè)1M緩沖區(qū)
    byte[] buf = new byte[ONE_M];
    // 創(chuàng)建目的
    FileOutputStream fos = null;
    
    int len = 0;
    int i = 1;
    /**
     *  記錄切割文件的數(shù)據(jù):名稱臼节、碎片個(gè)數(shù),方便合并
     */
    Properties prop = new Properties();
    
    File dir = new File("D:\\partfile");
    if(!dir.exists())
        dir.mkdirs();
    while((len = fis.read(buf))!= -1){
        fos = new FileOutputStream(new File(dir, (i++) + ".part"));
        fos.write(buf, 0, len);
        fos.close();
    }
    // 將切割文件的信息保存到prop集合中
    prop.setProperty("filename", file.getName());
    prop.setProperty("partnum", count + "");
    fos = new FileOutputStream(new File(dir, count + ".properties"));
    // 將prop集合中數(shù)據(jù)存儲(chǔ)到文件中
    prop.store(fos,"save file info");
    fos.close();
    fis.close();
}

文件合并

public static void main(String[] args){
    File dir = new File("D:\\partfile");
    // 獲取指定目錄下文件配置信息
    File[] files = dir.listFile(new SuffixFilter(".properties"));
    if(files.length != 1){
        throw new RuntimeException(dir + ",該目錄下沒有properties擴(kuò)展名文件或者不唯一");
    }
    // 記錄配置文件對象
    File configFile = files[0];
    
    // 獲取該文件中信息
    Properties prop = new Properties();
    FileInputStream fis = new FileInputStream(configFile);
    prop.load(fis);
    
    String filename = prop.getProperty("filename");
    int count = Integer.parseInt(prop.getProperty("partnum"));
    
    // 獲取該目錄下所有的碎片文件
    File[] partFiles = dir.listFiles(new SuffixFilter(".part"));
    if(partFiles.length != (count - 1)){
        throw new RuntimeException("碎片文件不符合,無法合并网缝,應(yīng)該是"+count);
    }
    
    // 將碎片文件和流對象關(guān)聯(lián)巨税,并存儲(chǔ)到集合中
    ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
    for(int i = 1; i <= partFiles.length ; i++){
        al.add(new FileInputStream(new File(dir, x + ".part")));
    }
    
    // 將多個(gè)流合并成一個(gè)序列流
    Enumeration<FileInputStream> en = Collections.enumeration(al);
    SequenceInputStream sis = new SequenceInputStream(en);
    FileOutputStream fos = new FileOutputStream(new File(dir, filename));
    
    // 讀寫過程
    byte[] buf = new byte[1024];
    int len = 0;
    while((len = sis.read(buf)) != -1){
        fos.write(buf, 0, len);
    }
    fos.close();
    sis.close()
}
// 文件過濾器
public class SuffixFilter implements FilenameFilter{
    private String suffix;
    public SuffixFilter(String suffix){
        super();
        this.suffix = suffix;
    }
    @Override
    public boolean accept(File dir, String name){
        return name.endsWith(suffix);
    }
}

操作對象

  • ObjectInputStream與ObjectOutputStream
    • 被操作的對象需要實(shí)現(xiàn)Serializable(標(biāo)記接口)
public static void main(String[] args) throws IOException{
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.object"));
    // 對象序列化,被序列化對象必須實(shí)現(xiàn)Serializable接口
    oos.writeObject(new Person("zimo", 18));    // 不實(shí)現(xiàn)Serializable標(biāo)記接口粉臊,無法寫入
    oos.close();
    
    -------------------------------------------------------------------------------------------------
    // 對ObjectOutputStream寫入的基本數(shù)據(jù)和對象進(jìn)行反序列化
    ObjectInputStream ois = new ObjectInputStream(new FileOutputStream("obj.object"));
    Person p = (Person)ois.readObject();    // 以來與Person的class文件 throw ClassNotFountException
    System.out.println(p.getName() + ":" + p.getAge());
}
public class Person implements Serializable{
    private static final long serialVersionUID = 9527L;
    private String name;
    private int age;
    public Person(String name, int age){
        super();
        this.name = name;
        this.age = age;
    }
    public String getName(){
        return name;
    }
    public int getAge(){
        return age;
    }
}

Serializable接口

序列化運(yùn)行時(shí)使用一個(gè)serialVersionUID草添,用于反序列化時(shí)驗(yàn)證發(fā)送者和接收者是否為該對象加載的序列化兼容的類

Person{
    private transient String name;
    private static int age;
}
transient:非靜態(tài)數(shù)據(jù)不想被序列化可以使用這個(gè)關(guān)鍵字修飾

其他類

  • RandomAccessFile
    • 隨機(jī)訪問文件,自身具備讀寫的方法
    • 通過skipBytes(int x), seek(int x)來達(dá)到隨機(jī)訪問
  • 管道流
    • PipedInputStream和PipedOutputStream
      • 輸入輸出可以直接進(jìn)行連接扼仲,通過結(jié)合線程使用
// 使用RandomAccessFile對象寫入一些人員信息远寸,比如姓名和年齡
public static void writeFile() throws IOException{
    RandomAccessFile raf = new RandomAccessFile("ranacc.txt","rw");
    raf.write("zhangsan".getBytes());
    raf.write(97);
    raf.writeInt(609);
    //raf.write(609);       // 丟棄高位 剩下97
    raf.close();
    -------------------------------------------------------------------------------------------------------
    RandomAccessFile raf = new RandomAccessFile("ranacc.txt", "r");
    // 通過seek設(shè)置指針的位置,可以進(jìn)行隨機(jī)讀取
    raf.seek(0*8);
    byte[] buf = new byte[4];
    raf.read(buf);
    String name = new String(buf);
    int age = raf.readInt();
    System.out.println(name + age);
    raf.close();
}
public class PipedStream{
    public static void main(String[] args) throws IOException{
        PipedInputStream input = new PipedInputStream();
        PipedOutputStream output = new PipedOutputStream();    
        // 連接管道
        input.connect(output);
        
        new Thread(new Input(input)).start();
        new Thread(new Output(output)).start();
    }
}
class Input implements Runnable{
    private PipedInputStream in;
    Input(PipedInputStream in){
        this.in = in;
    }
    public void run(){
        try{
            byte[] buf = new byte[1024];
            int len = in.read(buf);
            String s = new String(buf, 0, len);
            System.out.println("s="+s);
            in.close();
        }catch(Exception e){
            
        }
    }
}
class Output implements Runnable{
    private PipedOutputStream out;
    Output(PipedOutputStream out){
        this.out = out;
    }
    public void run(){
        try{
            out.write("管道來了".getBytes());
        }catch(Exception e){
            
        }
    }
}
  • 操作基本數(shù)據(jù)類型
    • DataInputStream與DataOutputStream
  • 操作字節(jié)數(shù)組
    • ByteArrayInputStream與ByteArrayOutputStream
    • 關(guān)閉ByteArray(I/O)Stream無效屠凶,關(guān)閉后仍可以使用驰后,不拋出IO異常,只讀取內(nèi)存數(shù)據(jù)矗愧,不占用資源
  • 操作字符數(shù)組
    • CharArrayReader與CharArrayWrite
  • 操作字符串
    • StringReader與StringWrite
public static void main(String[] args) throws IOException{
    DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
    dos.writeUTF("你好");     // 代表UTF-8修改版  帶標(biāo)頭 8個(gè)字節(jié)
    dos.close();
    
    DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
    String str = dis.readUTF();
    System.out.println(str);
    dis.close();
    ----------------------------------------------------------------------------------------------
    ByteArrayInputStream bis = new ByteArrayInputStream("abcdefg".getBytes());
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    
    int ch = 0;
    while((ch = bis.read()) != -1){
        bos.write(ch);
    }
    // 無需關(guān)流
}

編碼表

編碼表的由來

  • 計(jì)算機(jī)只能識別二進(jìn)制數(shù)據(jù)灶芝,早期由來是電信號
  • 為了方便應(yīng)用計(jì)算機(jī),讓它可以識別各個(gè)國家的文字
  • 就將各個(gè)國家的文字用數(shù)字來表示唉韭,并一一對應(yīng)夜涕,形成一張表
  • 這就是編碼表

常見的編碼表

  • ASCII:美國標(biāo)準(zhǔn)信息交換碼
    • 用一個(gè)字節(jié)的7位可以表示
  • ISO8859-1:拉丁碼表。歐洲碼表
    • 用一個(gè)字節(jié)的8位表示
  • GB2312:中國的中文編碼表
  • GBK:中國的中文編碼表升級属愤,融合了更多的中文文字符號
  • Unicode:國際標(biāo)準(zhǔn)碼女器,融合了多種文字
    • 所有文字都用兩個(gè)字節(jié)來表示,Java語言使用的就是Unicode
  • UTF-8:最多用三個(gè)字節(jié)來表示一個(gè)字符
  • ...
// 簡單的編碼解碼
/**
 *  字符串 --->> 字節(jié)數(shù)組:編碼   看的懂 --> 看不懂
 *  字節(jié)數(shù)組 --->> 字符串:解碼   看不懂 --> 看得懂
 */

public static void main(String[] args){
    String str = "你好";
    // 編碼
    byte[] buf = str.getBytes();
    // byte[] buf = str.getBytes("utf-8");      // -28 -67 -96 -27 -91 -67
    
    for(byte b : buf){
        System.out.println(b);  // GBK: -60  -29  -70  -61
    }
    
    // 解碼
    String s1 = new String(buf);
    // String s1 = new String(buf, "utf-8");
    System.out.println("s1 = " + s1);
}
編碼錯(cuò)誤補(bǔ)救.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末住诸,一起剝皮案震驚了整個(gè)濱河市驾胆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌只壳,老刑警劉巖俏拱,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異吼句,居然都是意外死亡锅必,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進(jìn)店門惕艳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來搞隐,“玉大人,你說我怎么就攤上這事远搪×痈伲” “怎么了?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵谁鳍,是天一觀的道長癞季。 經(jīng)常有香客問我劫瞳,道長,這世上最難降的妖魔是什么绷柒? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任志于,我火速辦了婚禮,結(jié)果婚禮上废睦,老公的妹妹穿的比我還像新娘伺绽。我一直安慰自己,他們只是感情好嗜湃,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布奈应。 她就那樣靜靜地躺著,像睡著了一般购披。 火紅的嫁衣襯著肌膚如雪杖挣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天今瀑,我揣著相機(jī)與錄音程梦,去河邊找鬼。 笑死橘荠,一個(gè)胖子當(dāng)著我的面吹牛屿附,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播哥童,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼挺份,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了贮懈?” 一聲冷哼從身側(cè)響起匀泊,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎朵你,沒想到半個(gè)月后各聘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡抡医,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年躲因,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片忌傻。...
    茶點(diǎn)故事閱讀 38,716評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡大脉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出水孩,到底是詐尸還是另有隱情镰矿,我是刑警寧澤,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布俘种,位于F島的核電站秤标,受9級特大地震影響绝淡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜抛杨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一够委、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧怖现,春花似錦、人聲如沸玉罐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吊输。三九已至饶号,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間季蚂,已是汗流浹背茫船。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留扭屁,地道東北人算谈。 一個(gè)月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像料滥,于是被迫代替她去往敵國和親然眼。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 本篇文章主要圍繞字符編碼展開葵腹,為了能夠更好地講述這一主題高每,我將從字節(jié)流操作中文數(shù)據(jù)開始。 字節(jié)流操作中文數(shù)據(jù) 假設(shè)...
  • 本文對 Java 中的 IO 流的概念和操作進(jìn)行了梳理總結(jié)践宴,并給出了對中文亂碼問題的解決方法鲸匿。 1. 什么是流 J...
    Skye_kh閱讀 767評論 0 2
  • java IO流學(xué)習(xí)總結(jié) 近期學(xué)習(xí)了Java的IO流,嘗試著總結(jié)一下阻肩。 java.io 包下的IO流很多: 其中带欢,...
    java萌新小白閱讀 586評論 0 0
  • 源:鍵盤錄入。 目的:控制臺磺浙。 需求:想把鍵盤錄入的數(shù)據(jù)存儲(chǔ)到一個(gè)文件中洪囤。源:鍵盤。目的:文件撕氧。 需求:想要將一個(gè)...
    一畝三分甜閱讀 100評論 0 1
  • 導(dǎo)語: 打開簡書瘤缩,看到自己的文章被瀏覽了五十多次的時(shí)候真的很開心,然后發(fā)現(xiàn)有幾個(gè)喜歡一個(gè)粉絲的時(shí)候伦泥,真的是非常開心...
    我是小徐同學(xué)閱讀 805評論 5 17