Java總結IO篇之其餘IO流對象

零、前言:

本篇涉及到的流:
1.PrintWriter:字符打印輸出流
2.PrintStream:字節打印輸出流
3.SequenceInputStream :合併多個字節輸入流
4.RandomAccessFile:隨機操做文件
5.ObjectOutputStream與ObjectInputStream :對象的序列化流
6.DataInputStream與DataOutputStream :基本數據類型操做流
7.ByteArrayInputStream與ByteArrayOutputStream:字節數組操做流java

1、PrintWriter:字符打印輸出流

9414344-686ec8fb18d88cc4.png
PrintWriter.png
1.構造方法
File file 文件
File file, String csn 文件,字符集 
String fileName 文件名 
String fileName, String csn 文件名,字符集
OutputStream out 字節輸出流
OutputStream out, boolean autoFlush 字節輸出流,是否自動刷新緩衝區
Writer out 字符輸出流
Writer out, boolean autoFlush 字符輸出流,是否自動刷新緩衝區

不管是文件也好,字符串也好,字節輸出流,字符輸出流也好,總之一句話:
給我一個輸出流,還你一個PrintWritergit

使用:鍵盤錄入,控制檯輸出大寫
public class PrintStreamTest {
    public static void main(String[] args) throws IOException {
        BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));
        //使用控制檯輸出流建立一個自動刷新緩衝區的PrintWriter對象
        PrintWriter pw = new PrintWriter(System.out,true);
        String line = null;
        while ((line = bfr.readLine()) != null) {
        //pw.write(line.toUpperCase());//不帶換行
        //pw.flush();
            pw.println(line.toUpperCase());//自帶換行,自帶刷新
        }
        bfr.close();
        pw.close();
    }
}
使用:鍵盤錄入,輸出大寫到文件

想要將鍵盤錄入保存到文件中,只要將控制檯輸出流換成文件輸出流便可
其餘部分同上github

String path = "I:\\Java\\Base\\Thinking\\src\\IOTest\\PrintWriter.txt";
PrintWriter pw = new PrintWriter(new FileWriter(path), true);
9414344-55fc8b26ee60fa99.png
PrintWriter輸出到文件.png

2、PrintStream:字節打印輸出流
9414344-0f6d1afbf553fd0d.png
PrintStream.png
File file 文件
File file, String csn 文件,字符集
String fileName 文件名
String fileName, String csn 文件名,字符集
OutputStream out 字節輸出流
OutputStream out, boolean autoFlush  字節輸出流,是否自動刷新緩衝區
OutputStream out, boolean autoFlush, String encoding 字節輸出流,是否自動刷新緩衝區,字符集

不管是文件也好,字符串也好,字節輸出流,總之一句話:
給我一個字節輸出流,還你一個PrintStream編程

public class PrintWriterTest {
    public static void main(String[] args) {
        try {
            int a = Integer.parseInt("a");
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
    }
}
java.lang.NumberFormatException: For input string: "a"
    at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.base/java.lang.Integer.parseInt(Integer.java:652)
    at java.base/java.lang.Integer.parseInt(Integer.java:770)
    at top.toly.IO.io.其餘流.PrintWriterTest.main(PrintWriterTest.java:12)

全部異常繼承自:Throwable 類
其中有個不起眼的方法printStackTrace(),通常放着也沒人管
但它有的重載的方法void printStackTrace​(PrintStream s) 能夠自定義輸出流數組

public class PrintStreamTest {
    public static void main(String[] args) throws FileNotFoundException {
        try {
            int a = Integer.parseInt("a");
        } catch (NumberFormatException e) {
            e.printStackTrace();//默認是輸出到控制檯:即System.out流
            //將信息打印到F:\log.txt文件中
            e.printStackTrace(new PrintStream("F:\\log.txt"));
        }
    }
}
9414344-a142ad18dcf5159c.png
輸出錯誤日誌到文件.png

也能夠加入異常的時間微信

//將信息打印到F:\log.txt文件中
PrintStream ps = new PrintStream("F:\\log.txt");
ps.println(new SimpleDateFormat(" G yyyy/MM/dd 星期--EE a hh:mm:ss ").format(new Date().getTime()));
e.printStackTrace(ps);//默認是輸出到控制檯:即System.out流

3、SequenceInputStream :合併多個字節輸入流

InputStream s1, InputStream s2  兩個字節流對象,先讀s1,再s2
(Enumeration<? extends InputStream> e)
1.將兩個文件的數據合併到一個文件
public class SISTest {
    public static void main(String[] args) throws Exception {
        FileInputStream fis1 = new FileInputStream("I:\\Java\\Base\\Thinking\\src\\IOTest\\FileInputStream.txt");
        FileInputStream fis2 = new FileInputStream("I:\\Java\\Base\\Thinking\\src\\IOTest\\TxtInfo.ini");
        //使用Vector獲取Enumeration對象
        Vector<InputStream> vec = new Vector<>();
        vec.add(fis1);
        vec.add(fis2);
        SequenceInputStream sis = new SequenceInputStream(vec.elements());//合併輸入流
        //建立輸出流
        FileOutputStream fos = new FileOutputStream("I:\\Java\\Base\\Thinking\\src\\IOTest\\SequenceInputStream.txt");

        int len = 0;
        byte[] buf = new byte[1024];
        while ((len = sis.read(buf)) != -1) {
            fos.write(buf, 0, len);
        }
        sis.close();
        fos.close();
    }
}
9414344-f026dd93b232e58e.png
SequenceInputStream.png
2.文件切分

當一個文件過大時,能夠分割成多個小塊
好比將一個1GB的電影分割成10份,每份100+M,因爲字節不完整,致使沒法播放
因此別人也不知道是什麼電影 想看時用合併流合併一下,就能正常播放了。
能夠搞個切合播放器,關閉播放器將電影切割,須要打開時碎片合併,而後就神不知鬼不覺。dom

目標文件Activity.md --7.34 KB (7,521 字節),按3KB大小切ide

public class SplitFile {
    public static void main(String[] args) throws Exception {
        String pathS = "I:\\Java\\Base\\Thinking\\src\\IOTest\\Activity.md";
        File fileS = new File(pathS);
        FileInputStream fis = new FileInputStream(pathS);
        //獲取待切分文件名,以它做文文件夾,放入切分後的
        File parent = new File(fileS.getParentFile().getAbsolutePath()
                + File.separator + fileS.getName().split("\\.")[0]);
        parent.mkdir();
        int count = 0;
        int len = 0;
        byte[] buf = new byte[1024 * 3];//每份3kb,最後一份小於或等於3kb
        while ((len = fis.read(buf)) != -1) {
            File fileT = new File(parent, (count++) + ".temp");
            FileOutputStream fos = new FileOutputStream(fileT);
            fos.write(buf, 0, len);
            fos.close();
        }
        fis.close();
    }
}
9414344-e5482ada779833a8.png
切割文件.png

合併網站

public class SISTest {
    public static void main(String[] args) throws Exception {
        FileInputStream fis1 = new FileInputStream("I:\\Java\\Base\\Thinking\\src\\IOTest\\Activity\\0.temp");
        FileInputStream fis2 = new FileInputStream("I:\\Java\\Base\\Thinking\\src\\IOTest\\Activity\\1.temp");
        FileInputStream fis3 = new FileInputStream("I:\\Java\\Base\\Thinking\\src\\IOTest\\Activity\\2.temp");
        //使用Vector獲取Enumeration對象
        ArrayList<InputStream> list = new ArrayList<>();
        list.add(fis1);
        list.add(fis2);
        list.add(fis3);
        //基於ArrayList合併流:需自定義Enumeration
        final Iterator<InputStream> it = list.iterator();
        Enumeration<InputStream> en = new Enumeration<>() {
            @Override
            public boolean hasMoreElements() {
                return it.hasNext();
            }
            @Override
            public InputStream nextElement() {
                return it.next();
            }
        };
        SequenceInputStream sis = new SequenceInputStream(en);//合併輸入流
        //建立輸出流
        FileOutputStream fos = new FileOutputStream("I:\\Java\\Base\\Thinking\\src\\IOTest\\Activity\\Activity.md");
        int len = 0;
        byte[] buf = new byte[1024];
        while ((len = sis.read(buf)) != -1) {
            fos.write(buf, 0, len);
        }
        sis.close();
        fos.close();
    }
}

4、對象的序列化流

使用ObjectOutputStream將對象序列化成爲數據輸出-->將對象持久存儲
使用ObjectInputStream進行讀取序列化的數據-->恢復先前對象
只能序列化堆中的對象,static修飾的成員變量不能被序列化
transient修飾的成員變量,即便在堆內存中也不會被序列化this

一、ObjectOutputStream :對象的序列化輸出流
private static void writeObject() throws IOException {
     String path = "I:\\Java\\Base\\Thinking\\src\\IOTest\\ObjectOutputStream.txt";
     ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
     //Person須要序列化implements Serializable:不然ERROR----NotSerializableException
     Person toly = new Person("捷特", 24);
     oos.writeObject(toly);
     oos.close();
 }
public class Person implements Serializable {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    //get()、set()、toSring()省略
}
9414344-5259f75af72fada1.png
將對象序列化到文件中.png
二、ObjectInputStream :對象的序列化輸入流

至關於給個文件給你,你直接讀出來一個對象,建立,賦值什麼的都已經搞定了
對於十分複雜的對象序列化仍是很方便的,但因爲是IO,相對比較耗時

private static void readObject() throws IOException, ClassNotFoundException {
    String path = "I:\\Java\\Base\\Thinking\\src\\IOTest\\ObjectOutputStream.txt";
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
    Person toly = (Person) ois.readObject();
    System.out.println(toly);//Person{name='捷特', age=24}

5、RandomAccessFile:隨機操做文件

1.該類不是算是IO體系中子類。而是直接繼承自Object。
2.可是它是IO包中成員。由於它具有讀和寫功能,內部封裝字節輸入流和輸出流。
3.內部封裝數組,經過指針對數組的元素進行操做,getFilePointer獲取指針位置,經過seek改變指針的位置
4.只能操做磁盤文件,

構造方法:
File file, String mode     rw :讀寫模式   r : 只讀 
String name, String mode

1.文件寫入
public class RAF_Test {
    public static void main(String[] args) throws IOException {
        String path = "I:\\\\Java\\\\Base\\\\Thinking\\\\src\\\\IOTest\\RandomAccessFile.txt";

        RandomAccessFile raf = new RandomAccessFile(path, "rw");
        raf.write("張風捷特烈".getBytes());
        raf.write(38);
        raf.write(527654);
        raf.close();
    }
}
9414344-75b8a4c0e2c9862a.png
RandomAccessFile.png

可見38和527654兩個int值以&字符展示出來,utf-8碼錶第38爲是&這情有可原,527654怎麼也來插一腳
衆所周知,一個int佔4個字節,一個字節是8位,也就是一個int佔32位,轉換成二進制即下面:

3366
0000 0000 0000 1000 0000 1101 0010 0110
38
0000 0000 0000 0000 0000 0000 0010 0110
RandomAccessFile寫入時int只寫入低8位(由於字符寫入,一次只能寫一個字節即8位),即0010 0110

解決方法:將一個int分爲4次來讀,每次讀一個字節(8位),寫入文件

raf.writeInt(527654);//RandomAccessFile內部已經封裝
9414344-afe86dee1a25e8b0.png
RandomAccessFile2.png
2.讀取
RandomAccessFile rafR = new RandomAccessFile(path, "r");
        byte[] buf = new byte[9];//一個utf-8漢字佔三個字節,這裏一次讀三個漢字
        rafR.read(buf);
        System.out.println(new String(buf));//張風捷
        //這裏用8,由於兩個漢字3*2=6字節,加上2個&&一共8個字節。
        byte[] buf2 = new byte[8];
        rafR.read(buf2);
        System.out.println(new String(buf2));//特烈&&
        //讀取int值:若是上面不是8,而是9,那麼527654的字節就不完整,會報錯
        System.out.println(rafR.readInt());//527654
9414344-2dd923cb081cf0dc.png
字節顯示.png
3.seek調節指針讀取
RandomAccessFile rafR = new RandomAccessFile(path, "r");
rafR.seek(3);//將讀取的指針移到第4個字節
byte[] buf = new byte[3];
rafR.read(buf);
System.out.println(new String(buf));//風
4.seek調節指針寫出
String path = "I:\\\\Java\\\\Base\\\\Thinking\\\\src\\\\IOTest\\RandomAccessFile.txt";
RandomAccessFile rafRW = new RandomAccessFile(path, "rw");
rafRW.write("張風捷特".getBytes());
rafRW.write(38);
rafRW.write(527654);
rafRW.writeInt(527654);
rafRW.seek(40);
rafRW.write("巫纓".getBytes());
rafRW.close();
9414344-a67dca988fd99ca3.png
移動指針寫數據.png

6、DataInputStream與DataOutputStream:基本數據類型操做流

9414344-9613d8c9f37ac5a2.png
DataXXStream.png

1.寫出操做
private static void write() throws IOException {
    DataOutputStream dos = new DataOutputStream(new FileOutputStream(path));
    dos.writeBoolean(true);//1字節
    dos.writeInt(3366);//4字節
    dos.writeFloat(3.14f);//4字節
    dos.close();
}
9414344-4c57b7154e06b811.png
DataOutputStream.png
2.讀取操做
DataInputStream dis = new DataInputStream(new FileInputStream(path));
//注意按添加的順序讀取
System.out.println(dis.readBoolean());//true
System.out.println(dis.readInt());//3366
System.out.println(dis.readFloat());//3.14

七:ByteArrayInputStream與ByteArrayOutputStream:字節數組操做流

ByteArrayInputStream :在構造的時候,須要數據源:一個字節數組,緩衝區會隨數據自動增加。
ByteArrayOutputStream: 在構造的時候,該對象中已經內部封裝了可變長度的字節數組,是數據目的地。

public class BAIS_BAOS_Test {
    public static void main(String[] args) throws IOException {
        ByteArrayInputStream bais = new ByteArrayInputStream("張風捷特烈".getBytes());
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        System.out.println(baos.size());//0
        int by = 0;
        while ((by = bais.read()) != -1) {
            baos.write(by);
        }
        System.out.println(baos.size());//15 = 3 * 5
        //寫到控制檯
        baos.writeTo(System.out);//張風捷特烈
        //寫到文件
        String path = "I:\\Java\\Base\\Thinking\\src\\IOTest\\ByteArrayOutputStream.txt";
        baos.writeTo(new FileOutputStream(path));
    }
}

其餘幾個操做相似,順便提一下

IO 流類型 操做數據
ByteArrayInputStream 輸入流I 字節流 字節數組
ByteArrayOutputStream 輸出流O 字節流 字節數組
CharArrayReader 輸出流I 字符流 字符數組
CharArrayWriter 輸出流O 字符流 字符數組
StringReader 輸出流I 字符流 字符串
StringWriter 輸出流O 字符流 字符串

後記:捷文規範

1.本文成長記錄及勘誤表
項目源碼 日期 備註
V0.1--無 2018-10-12 Java總結IO篇之其餘IO流對象
V0.2--無 - -
2.更多關於我
筆名 QQ 微信 愛好
張風捷特烈 1981462002 zdl1994328 語言
個人github 個人簡書 個人CSDN 我的網站
3.聲明

1----本文由張風捷特烈原創,轉載請註明 2----歡迎廣大編程愛好者共同交流 3----我的能力有限,若有不正之處歡迎你們批評指證,一定虛心改正 4----看到這裏,我在此感謝你的喜歡與支持

相關文章
相關標籤/搜索