java IO


title: java IO
date: 2018-12-16 15:54:20
updated: 2020-03-15 16:11:45
categories: java
tags:
- java


此文檔爲java IO的學習總結

文件輸入與輸出

  • 1.從文件中讀取信息
//從文件中讀取數據信息並打印輸出
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Scanner; //三個包不能少
 
public class Test {
	public static void main(String args[]) throws IOException //這個throws不能少
	{
		Scanner in = new Scanner(Paths.get("d:\\1.txt"));  
		String data = in.nextLine();
		String data2 = in.nextLine();
		System.out.println(data + '\n' + data2);
	}
}

  • 2.寫入數據信息到文件中
//向文件中寫入數據信息
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Scanner; //三個包不能少
 
public class Test {
	public static void main(String args[]) throws IOException //這個throws不能少
	{
		PrintWriter out = new PrintWriter("d:\\2.txt");
		out.println("hahahaha");  //寫入數據信息到指定文件
		out.flush(); //刷新文件
	}
}

Java IO: 管道

由於java語言的stream嚴格區分爲inputstream和outputstream,流數據讀寫之間轉換一般使用臨時文件方式來轉換,但是這種方式使用的效率比較低,因此可以使用管道來實現,java管道支持比較弱,需要多線程來支持,

import org.junit.Test;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
	
/**
 * FileName: TestPipe
 * Author:   braincao
 * Date:     2018/10/4 15:23
 * Description: 兩個線程間用管道實現通信的例子
 * Java IO中的管道爲運行在同一個JVM中的兩個線程提供了通信的能力
 */
	
public class TestPipe {
    @Test
    public void test1() throws IOException{
        PipedOutputStream output = new PipedOutputStream();
        PipedInputStream input = new PipedInputStream(output);
	
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    output.write("hello world".getBytes());
                    output.close(); //通信完切記關閉管道資源
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        });
	
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    int data = input.read();
                    while(data!=-1){
                        System.out.print((char)data + " ");
                        data = input.read();
                    }
                    input.close();//通信完切記關閉管道資源
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
        });
	
        thread1.start();
        thread2.start();
    }
}
	
//out:h e l l o   w o r l d 

java IO

1.File類: 文件或目錄路徑(文件夾)的抽象表示形式。通過File對象可以訪問文件的屬性、創建空文件和目錄

@Test
public void test1() throws IOException, InterruptedException{
    //創建目錄路徑(文件夾)--mkdir():如果父目錄不存在,失敗
    String path2 = "/Users/braincao/git/test";
    File file2 = new File(path2);
    boolean flag = file2.mkdir();
    System.out.println(flag);

    //創建目錄路徑(文件夾)--mkdirs():如果父目錄不存在,一同創建
    String path = "/Users/braincao/git/test/test";
    File file3 = new File(path);
    boolean flag3 = file3.mkdirs();
    System.out.println(flag3);

    //創建文件--createNewFile()
    File file = new File("/Users/braincao/git/2.txt");
    if(!file.exists()){ //如果不存在則創建新文件,存在就不創建
        file.createNewFile();
    }
//        if(file.exists()){
//            file.delete();//如果存在則刪除文件,不存在就不創建
//        }

    //創建臨時文件,程序退出即刪除
    File tmp = File.createTempFile("test", ".temp", new File("/Users/braincao/git"));
    Thread.sleep(2000);//放大延時便於觀看效果
    tmp.deleteOnExit();//文件退出即刪除
    
    //輸出當前系統的根目錄--listRoots()
    File[] roots = File.listRoots(); //當前系統的根目錄
}

@Test
public void test2(){
    //遍歷文件夾中的文件--String[] list()
    File file4 = new File("/Users/braincao/git");
    if(file4.isDirectory()){ //如果是目錄路徑
        String[] lists = file4.list(); //返回的是文件夾中所有東西的路徑字符串,不是File對象
        for(String s: lists){
            System.out.println(s);
        }
        System.out.println("=========");
        File[] files = file4.listFiles();//返回的是文件夾中所有東西的File對象
        for(File f: files){
            System.out.println(f.getName());
        }
        System.out.println("=========");
        //命令設計模式
        //FilenameFilter()--設置過濾模板,顯示想要的文件或路徑
        File[] ff = file4.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return new File(dir, name).isFile() && name.endsWith(".txt"); //返回後綴.txt的文件(非路徑)
            }
        });

        for(File f: ff){
            System.out.println(f.getName());
        }
    }
}

輸出子孫級目錄的絕對路徑名稱—遞歸

static void test3(String path) throws Exception{
        /**
         * @Description: 輸出子孫級目錄的絕對路徑名稱---遞歸
         */
        File file = new File(path);
        if(file.isFile()){
            System.out.println(file.getAbsolutePath());
            return;
        }
	
        File[] ff = file.listFiles();
        for(File f: ff){
            if(f.isFile()){
                System.out.println(f.getAbsolutePath());
            }
            else{
                test3(f.getAbsolutePath());
            }
        }
    }
	
    public static void main(String[] args) throws Exception{
        test3("/Users/braincao/git/test");
    }

2.IO:

1583507875

  • 節點流:節點流處於IO操作的第一線,所有操作必須通過它們進行
  • 字節流

  • 字符流

  • 處理流:處理流可以對其他流進行處理(增強功能,提高效率)

字節流:二進制流,可以處理一切文件,包括純文本、doc、音頻、視頻等等

輸入流:InputStream--read(byte[] b)、read(byte[] b, int off, int len)、close()
	   FileInputStream()
輸出流:OutputStream--write(byte[] b)、write(byte[] b, int off, int len)、flush()、close()
	   FileOutputStream()

字符流:文本流,只能處理純文本

輸入流:Reader--read(char[] cbuf)、read(char[] cbuf, int off, int len)、close()
	   FileReader()
輸出流:Writer--write(char[] cbuf)、write(String[] str, int off, int len)、write(char[] cbuf, int off, int len)、flush()、close()
	   FileWriter()
		   

2.1字節流

讀取文件input、寫入文件output的demo

@Test
public void input(){
    /**
     * @Description: 讀取文件
     * 	1.建立聯繫:File對象
        2.選擇流:字節輸入流:InputStream FileInputStream
        3.操作:數組大小byte[] b = new byte[1024]、read、write
        4.釋放資源
     */

    //1.建立聯繫
    File file = new File("/Users/braincao/git/1.txt");
    //2.選擇流,這裏有異常需要try catch
    InputStream input = null; //提升作用域便於後面釋放資源
    try {
        input = new FileInputStream(file);
        //3.操作:不斷讀取
        byte[] b = new byte[10]; //每次最多讀取10字節的緩衝數組
        int len = 0;//每次讀取的真實字節長度
        //循環讀取
        while(-1 != (len=input.read(b))){
            //輸出,需要將字節數組轉成String
            String str = new String(b, 0, len);
            System.out.println(str);
        }

    } catch (IOException e) {
        e.printStackTrace();
    }finally{
        if(input!=null){
            try {
                input.close(); //釋放資源
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

@Test
public void output(){
    /**
     * @Description: 寫出文件
     *  1.建立聯繫:File對象
        2.選擇流:字節輸出流:OutputStream FileOutputStream
        3.操作:write、flush、close
        4.釋放資源
     */

    //1.建立聯繫
    File file = new File("/Users/braincao/git/2.txt");
    //2.選擇流
    OutputStream output = null;//提升作用域便於後面釋放資源
    try {
        output = new FileOutputStream(file, true);//true是追加寫入,false是覆蓋寫入
        String str = "hello world!\n";
        //將String轉成byte數組
        byte[] b = str.getBytes();
        try {
            output.write(b, 0, b.length); //3.操作:寫入文件
            output.flush(); //強制刷新出去。如果沒有強制刷新,IO管道滿了或者需要等到釋放資源時,纔會flush推出寫入。因此要養成手動flush的習慣
        } catch (IOException e) {
            e.printStackTrace();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }finally{
        if(output!=null){
            try {
                output.close(); //釋放資源
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

#####拷貝文件、拷貝文件夾

拷貝文件:實現文件拷貝。結合了輸入流input和輸出流output,邊讀取邊寫入

拷貝文件夾

1.遞歸查找子孫級文件/文件夾

2.文件:IO流複製;文件夾:創建並遞歸下一級

@Test
public static void copy(String pathSrc, String pathDest) throws IOException {
    /**
     * @Description: 實現文件拷貝。結合了輸入流input和輸出流output,邊讀取邊寫入
     *  1.建立聯繫:File對象
        2.選擇流:字節輸入流:InputStream FileInputStream
                字節輸出流:OutputStream FileOutputStream
        3.操作:數組大小byte[]+read
                write
                flush+close
        4.釋放資源
     */

    //1.建立聯繫
    File fileSrc = new File(pathSrc);
    File fileDest = new File(pathDest);
    //2.選擇流
    InputStream input = null;
    OutputStream output = null; //提升作用域便於後面釋放資源
    try {
        input = new FileInputStream(fileSrc);
        output = new FileOutputStream(fileDest);
        byte[] b = new byte[1024]; //讀取與寫入緩衝數組
        int len = 0;
        while(-1 != (len=input.read(b))){ //讀取
            try {
                output.write(b, 0, len); //寫入
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        output.flush();//強制刷新出去
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }finally{
        try {
            if(input!=null){
                input.close();
            }
            if(output!=null){
                output.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

@Test
public static void copyFileDir(String pathSrc, String pathDest){
    /**
     * @Description: 文件夾拷貝,遞歸實現
     *  1.遞歸查找子孫級文件/文件夾
     *  2.文件:IO流複製;文件夾:創建並遞歸下一級
     */
    //1.建立聯繫
    File fileSrc = new File(pathSrc);
    File fileDest = new File(pathDest + File.separator + fileSrc.getName());

    if(fileSrc.isFile()){//如果是文件,IOcopy
        System.out.println("====file");
        try {
            if(!fileDest.exists()){
                copy(fileSrc.getAbsolutePath(), fileDest.getAbsolutePath());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    else if(fileSrc.isDirectory()){ //如果是文件夾路徑,創建路徑並遞歸遍歷
        System.out.println("====fileDir");
        if(!fileDest.exists()){
            fileDest.mkdir(); //創建文件夾路徑
            System.out.println("chuangjianchenggong ");
        }
        File[] ff = fileSrc.listFiles();
        for(File f: ff){
            copyFileDir(f.getAbsolutePath(), fileDest.getAbsolutePath());
        }
    }
}
public static void main(String[] args) throws Exception{
    //文件拷貝: IO流
    //copy("/Users/braincao/git/1.txt", "/Users/braincao/git/2.txt");

    /*文件夾拷貝: 文件->IO流複製;文件夾->創建路徑並遞歸
     *最終是把/Users/braincao/git/test文件夾拷貝到了/Users/braincao/git/test2/test中
     */
    copyFileDir("/Users/braincao/git/test", "/Users/braincao/git/test2");
}

2.2 字符流

只能處理純文本,全部爲可見字符。

讀取:Reader FileReader

寫入:Writer FileWriter

@Test
public void charInputStream() throws IOException {
    /**
     * @Description: 字符流。從文本讀取
     * 	1.建立聯繫:File對象
        2.選擇流:字符輸入流:Reader FileReader
        3.操作:數組大小char[] b = new byte[1024]、read、close
        4.釋放資源
     */

    //1.建立聯繫
    File src = new File("/Users/braincao/git/1.txt");
    Reader r = null;
    //2.選擇流
    try {
        r = new FileReader(src);
        //3.操作
        char[] cbuf = new char[10];
        int len = 0;
        while(-1 != (len=r.read(cbuf))){
            String ss = new String(cbuf, 0, cbuf.length);
            System.out.println(ss);
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    finally {
        if(r!=null){
            r.close();
        }
    }
}

@Test
public void charOutputStream() throws IOException {
    /**
     * @Description: 字符流。寫入文本到文件
     * 	1.建立聯繫:File對象
        2.選擇流:字符輸入流:Writer FileWriter
        3.操作:write、flush、close
        4.釋放資源
     */
    //1.建立聯繫
    File dest = new File("/Users/braincao/git/2.txt");
    //2.選擇流
    Writer w = null;
    try {
        w = new FileWriter(dest, true);//true追加;false覆蓋
        //3.操作
        String data = "asdadasdasdqweasd";
        w.write(data);
        w.append("\nsada");
        w.flush();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    finally {
        if(w!=null){
            w.close();
        }
    }
}

3.處理流:在節點流之上,處理流可以對其他流進行處理(增強功能,提高效率)

1583507907

爲什麼要有緩衝流?

比如說,家裏蓋房子,有一堆磚頭要搬在工地100米外,單字節的讀取就好比你一個人每次搬一塊磚頭,從堆磚頭的地方搬到工地,這樣可定很費時間,然後好的方法就是多叫幾個小夥伴幫你一起搬磚頭,這樣因爲人多了,每次可以搬十塊磚頭,但效率還是很低,這就好比我們的字節/字符數組讀寫操作;然而聰明的人類會用小推車,每次先搬磚頭搬到小車上,再利用小推車運到工地上去,這樣你或者你的小夥伴們再從小推車上取磚頭是不是方便多了呀!這樣效率就會大大提高,緩衝流就好比我們的小推車;給磚頭暫時提供一個可存放的空間;

針對字節的處理流:字節緩衝流

  • BufferedInputStream–直接把緩衝流加在字節流上就行,其他與字節流完全一樣
  • BufferedOutputStream–建議今後都加上緩衝流,提高性能

針對字符流的處理流:字符緩衝流

  • BufferedReader 新增readLine()
  • BufferedWriter 新增newLine()

字節緩衝流demo:

@Test
public static void copy(String pathSrc, String pathDest) throws IOException {
    /**
     * @Description: 字節緩衝流--拷貝文件demo
     * 緩衝流直接加在字節流上
     */

    //1.建立聯繫
    File fileSrc = new File(pathSrc);
    File fileDest = new File(pathDest);
    //2.選擇流
    InputStream input = null;
    OutputStream output = null; //提升作用域便於後面釋放資源
    try {
        input = new BufferedInputStream(new FileInputStream(fileSrc));//緩衝流直接加在字節流上
        output = new BufferedOutputStream(new FileOutputStream(fileDest));
        byte[] b = new byte[1024]; //讀取與寫入緩衝數組
        int len = 0;
        while(-1 != (len=input.read(b))){ //讀取
            try {
                output.write(b, 0, len); //寫入
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        output.flush();//強制刷新出去
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }finally{
        try {
            if(input!=null){
                input.close();
            }
            if(output!=null){
                output.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

字符緩衝流demo:

在字符流上加緩衝流。有新增方法readline()、newLine()

@Test
public static void bufferedCharCopy(String pathSrc, String pathDest) throws IOException {
    /**
     * @Description: 字符流,拷貝文本文件。在字符流上加緩衝流。有新增方法readline()、newLine()
     */
    //1.建立聯繫
    File src = new File(pathSrc);
    File dest = new File(pathDest);
    //2.選擇流
    Reader r = null;
    Writer w = null;
    try {
        r = new BufferedReader(new FileReader(src)); //在字符流上加了緩衝流。有新增方法readLine()
        w = new BufferedWriter(new FileWriter(dest)); //在字符流上加了緩衝流。有新增方法newLine()
//            //3.1 讀取寫入操作
//            char[] cbuf = new char[10];
//            int len = 0;
//            while(-1 != (len=r.read(cbuf))){
//                w.write(cbuf, 0, cbuf.length);
//            }
        //3.2. 讀取寫入操作--用緩衝流的新增方法readLine()、newLine()
        String line = null;
        while(null != (line=((BufferedReader) r).readLine()) ){ //這裏用緩衝流的新增方法,不能使用多態
            w.write(line);
            ((BufferedWriter) w).newLine();
        }
        w.flush();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    finally {
        if(r!=null){
            r.close();
        }
        if(w!=null){
            w.close();
        }
    }
}
public static void main(String[] args) throws IOException {
    bufferedCharCopy("/Users/braincao/git/1.txt", "/Users/braincao/git/2.txt");
}

轉換流:將字符流轉爲字節流,將字節流轉爲字符流—>處理亂碼(編碼集、解碼集)

字符 --編碼集–> 二進制
字符 <–解碼集-- 二進制

出現亂碼原因:

  • 1.編解碼字符集不統一
  • 2.字節缺少,長度缺失(一箇中文字符需要兩個字節,少一個字節就亂碼)

編解碼例子:

@Test
public void test1() throws UnsupportedEncodingException {
    /**
     * @Description: 編解碼例子,idea平臺默認utf-8編解碼
     */
    String str = "中國"; //utf-8解碼(將二進制解碼成了"中國")
    byte[] b1 = str.getBytes(); //utf-8編碼(將字符串"中國"編碼成了utf-8)
    byte[] b2 = str.getBytes("gbk"); //gbk編碼(將字符串"中國"編碼成了gbk)

    System.out.println(new String(b1,"utf-8")); //解碼
    System.out.println(new String(b1,"gbk")); //解碼

    System.out.println(new String(b2,"utf-8")); //解碼
    System.out.println(new String(b2,"gbk")); //解碼

    /*out:
        中國
        涓浗
        �й�
        中國
     */
}

轉換流:

//輸入流(字節流-->字符流):InputStreamReader 解碼 
//輸出流:OutputStreamWriter(字節流-->字符流) 編碼

    @Test
public static void bufferedCharCharsetCopy(String pathSrc, String pathDest) throws IOException {
    /**
     * @Description: 當出現亂碼問題時,使用轉換流(字節流<--->字符流)
     *  輸入流:InputStreamReader 解碼
        輸出流:OutputStreamWriter 編碼
     * 本例中:目的是:使用字符流進行文件拷貝
     *  源文件(已知是gbk編碼的二進制文件),我們想用字符流(直接用會出現亂碼)
        因此先用字節流,再用轉換流將字節流轉成字符流(解決編碼問題的字符流)
        同時最後還是加上一層緩衝字符流
     */
    //
    File src = new File(pathSrc);
    File dest = new File(pathDest);

    //BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(src), "utf-8")); //指定解碼集,error亂碼,源文件是gbk因此解碼必須是gbk

    //BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(src), "gbk")); //指定解碼集,ok
    //BufferedWriter w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dest), "gbk")); //指定編碼集,ok

    //BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(src), "gbk")); //指定解碼集,ok
    //BufferedWriter w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dest), "utf-8")); //指定編碼集,ok

    BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(src), "gbk")); //指定解碼集,ok
    BufferedWriter w = new BufferedWriter(new FileWriter(dest)); //不指定編碼集,直接用字符流就行,也ok

    String line = null;
    while (null != (line = r.readLine())) {
        System.out.println(line); //輸出解碼後的文本
        w.write(line);
        w.newLine();
    }
    w.flush();
    w.close();
    r.close();
}

public static void main(String[] args) throws IOException {
    bufferedCharCharsetCopy("/Users/braincao/git/1.txt", "/Users/braincao/git/2.txt");
}

其他流:

  • 字節數組流:將傳入的File對象換成了byte[]數組,其他一樣

    輸入流:ByteArrayInputStream bArray = new ByteArrayInputStream(byte [] a);

    輸出流:ByteArrayOutputStream bOut = new ByteArrayOutputStream();
    byte[] dest = bOut.toByteArray() //這點不太一樣,要用這種方式傳給接受數組dest

  • 基礎數據類型處理流:基本類型+String,保留數據+類型

    輸入流:DataInputStream readXxx()

    輸出流:DataOutputStream writeXxx()

  • 引用類型(對象)處理流:保留數據+類型,就是序列化、反序列化。通俗講就是把對象序列化保存到文件中,再從文件中反序列化拿出對象

    反序列化(輸入流): ObjectInputStream readObject()

    序列化(輸出流): ObjectOutputStream writeObject()

    注意:

    先序列化後反序列化,反序列化順序必須與序列化順序一致

    不是所有對象都可以序列化,對象所在類要實現java.io.Serializable接口(空接口讓JVM識別)

    每個對象有很多屬性,不是所有屬性都需要序列化,只序列化目標屬性即可。transient

序列化反序列化Demo:

import java.io.*;
/**
 * @FileName: EmployeeDemo
 * @Author: braincao
 * @Date: 2018-10-07 11:35:10
 * @Description: 序列化反序列化demo
 */
	
class Employee implements java.io.Serializable{
    private String name;
    private transient int id; //transient標識,不讓屬性序列化
	
    public Employee(String name, int id) {
        this.name = name;
        this.id = id;
    }
	
    public Employee() {
    }
	
    public String getName() {
        return name;
    }
	
    public void setName(String name) {
        this.name = name;
    }
	
    public int getId() {
        return id;
    }
	
    public void setId(int id) {
        this.id = id;
    }
	
    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", id=" + id +
                '}';
    }
}
	
public class EmployeeDemo{
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Employee e = new Employee("張三", 2017111110);
        //序列化
        File outfile = new File("/Users/braincao/git/2.txt");
        ObjectOutputStream os = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(outfile)));
        os.writeObject(e);
        os.close();
	
        //反序列化
        File infile = new File("/Users/braincao/git/2.txt");
        ObjectInputStream is = new ObjectInputStream(new BufferedInputStream(new FileInputStream(infile)));
        Object obj = is.readObject();
        if(obj instanceof Employee){
            Employee tmp = (Employee)obj;
            System.out.println(tmp.getName());
            System.out.println(tmp.getId()); //transient修飾的屬性不可見
        }
        is.close();
        //out:張三 0
    }
}

打印流:

System.out.println(“hello world”);中的out定義public final static PrintStream out = null;,可見out就是PrintStream打印流

demo1:

import java.io.*;
public class PrintDemo {
    public static void main(String[] args) throws IOException {
        /**
         * @Description: 打印流PrintStream(OutputStream out)demo
         */
        //1.創建源
        String ss = "鋤禾日當午,汗滴禾下土";
        //2.選擇流
        PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File("/Users/braincao/git/2.txt"))));
        //3.操作
        ps.write(ss.getBytes());
        //4.釋放資源
        ps.close();
    }
}	

demo2:

import java.io.*;
import java.util.Scanner;
public class PrintDemo {
    public static void test1() throws IOException {
        /**
         * @Description: 打印流PrintStream(OutputStream out)demo
         * 輸出到文件
         */
        //1.創建源
        String ss = "鋤禾日當午,汗滴禾下土";
        //2.選擇流
        PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File("/Users/braincao/git/2.txt"))));
        //3.操作
        ps.write(ss.getBytes());
        //4.釋放資源
        ps.close();
    }
	
    public static void test2() throws FileNotFoundException {
        /**
         * @Description:三個常量
         * System.in  --輸入流InputStream,默認是從鍵盤輸入
         * System.out  --輸出流OutputStream,默認是控制檯輸出
         * System.err(與System.out一樣,就是輸出顏色不同)
         */
        //輸出流
        System.out.println("asd");
        System.err.println("asd");
	
        //輸入流1
        InputStream is = System.in; //輸入流,鍵盤輸入
        Scanner sc = new Scanner(is); //獲取鍵盤輸入的輸入流
        System.out.println(sc.nextLine());
	
        //輸入流2
        BufferedInputStream fs = new BufferedInputStream(new FileInputStream(new File("/Users/braincao/git/2.txt")));
        Scanner sc2 = new Scanner(fs); //獲取文件輸入的輸入流
        System.out.println(sc2.nextLine());
    }
	
    public static void test3() throws FileNotFoundException {
        /**
         * @Description:將System.in、System.out重定向,不再使用默認的鍵盤輸入、控制檯輸出
         * 重新分配“標準”輸入/出流:System類方法:setIn(InputStream in)、setOut(PrintStream out)、setErr(PrintStream err)
         */
        PrintStream ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(new File("/Users/braincao/git/2.txt"))), true);//autoFlush設爲true,如果不加一定要手動flush
        System.setOut(ps); //重定向輸出流
        System.out.println("哈哈1234"); //直接寫入到文件
        ps.flush();
        ps.close();
	
        /**
         * @Description:重定向後又想重新設爲控制檯
         * FileDescriptor.in 鍵盤輸入
         * FileDescriptor.out 控制檯輸出
         */
        ps = new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)),true);
        System.setOut(ps); //重定向輸出流
        System.out.println("哈哈1234");
    }
	
    public static void main(String[] args) throws IOException {
        //test1();
        //test2();
        test3();
    }
}

裝飾設計模式

IO流用到的就是裝飾設計模式,包裝後增強功能

/**
 * @FileName: Decrator
 * @Author: braincao
 * @Date: 2018/10/7 16:29
 * @Description: 裝飾設計模式Demo---擴音器例子。IO流用到的就是裝飾設計模式,包裝後增強功能
 */
class Voice{
    private int voice = 10; //初始音量爲10
	
    public Voice() {
    }
	
    public void say(){
        System.out.println(voice); //播放聲音,音量爲10
    }
	
    public int getVoice() {
        return voice;
    }
	
    public void setVoice(int voice) {
        this.voice = voice;
    }
}
	
class Amplify{
    private Voice voice;
	
    public Amplify(Voice voice) {
        this.voice = voice;
    }
	
    public void say(){
        System.out.println(voice.getVoice()*100); //放大音量,現在爲1000
    }
	
    public Voice getVoice() {
        return voice;
    }
	
    public void setVoice(Voice voice) {
        this.voice = voice;
    }
}
	
public class Decrator {
    public static void main(String[] args){
        Voice v = new Voice();
        v.say(); //音量爲10
	
        Amplify am = new Amplify(v);
        am.say(); //音量爲1000
    }
}

文件分割與合併Demo1

import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Properties;
import java.io.*;
	
/**
 * @Description: 文件分割與合併的demo
 */
public class TestDemo {
    public static void main(String[] args) throws IOException {
        File fileSplit = new File("/Users/braincao/git/test/xiezhu_pub.rar"); //要分割的文件,分割後存放的目錄也在同級目錄中
        File fileMerge = new File("/Users/braincao/git/test"); //存放分割文件的目錄,合併後的文件也存在此目錄中
//        split(fileSplit);
        merge(fileMerge);
    }
    //文件分割
    public static void split(File file) throws IOException {
        FileInputStream fis = new FileInputStream(file);
        FileOutputStream fos = null;
        byte[] buf = new byte[1024*1024]; //每個分割文件的大小
	
        int len = 0;
        int count = 1;
        while(-1 != (len=fis.read(buf))){
            fos = new FileOutputStream(new File(file.getParent(), count+".part"));
            count++;
            fos.write(buf, 0, len);
            fos.flush();
        }
        fis.close();
	
        //輸出寫入配置文件
        Properties prop = new Properties();
        fos = new FileOutputStream(new File(file.getAbsoluteFile() + ".properties" ));
        prop.setProperty("fileName", file.getName());
        prop.setProperty("partCount", (count-1)+"");
        prop.store(fos,"save file info");
	
        fos.close();
    }
	
    //文件合併
    public static void merge(File file) throws IOException{
        //1.拿到properties中的相關信息
        File[] propFiles = file.listFiles(new SuffixFilter(".properties"));
        if(propFiles.length!=1){
            throw new RuntimeException(file+"該目錄下沒有properties擴展名的文件或者不唯一");
        }
        Properties pp = new Properties();
        FileInputStream propInput = new FileInputStream(propFiles[0]);
        pp.load(propInput);
        String fileName = pp.getProperty("fileName");
        int partNum = Integer.parseInt(pp.getProperty("partCount"));
	
        //2.遍歷目錄中.part文件,用SequenceInputStream輸入流組合
        ArrayList<FileInputStream> fis = new ArrayList<>();
        File[] files = file.listFiles(new SuffixFilter(".part"));
        for(int i=0; i<files.length; ++i){
            fis.add(new FileInputStream(files[i]));
        }
        Enumeration<FileInputStream> efis = Collections.enumeration(fis);
        SequenceInputStream sis = new SequenceInputStream(efis);
	
        //3.輸入流:SequenceInputStream;輸出流:FileOutputStream--->拷貝寫入
        FileOutputStream fos = new FileOutputStream(new File(file.getAbsolutePath(), "Merge_" + fileName));
        byte[] b = new byte[1024*1024];
        int len = 0;
        while(-1 != (len=sis.read(b))){
            fos.write(b, 0, len);
            fos.flush();
        }
	
        fos.close();
        sis.close();
    }
}
	
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);
    }
}

文件分割與合併Demo2(這個包含很多知識點,建議詳看)

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
	
/**
 * @FileName: RandomAccessFileDemo
 * @Author: braincao
 * @Date: 2018/10/7 16:52
 * @Description: 文件分割與合併Demo
 * 文件分割思路:
 * 1.確定每一塊的大小  blockSize
 * 2.已知文件總大小length和blockSize,計算確定分割的塊數  n=Math.ceil(length/blockSize) //Math.ceil(double a)返回大於等於a的最小整數(返回double類型)
 * 3.確定最後一塊的大小 length - (n-1)*blockSize
 */
	
public class SplitFileDemo {
    private String filePath; //源文件路徑
    private String fileName; //源文件名
    private long length; //源文件名
    private String destPath; //分割後文件存放目錄
    private long blockSize; //每塊的大小
    private List<String> blockPath; //每塊的名稱
    private int n; //分割的塊數
	
    public SplitFileDemo(String filePath, String destPath){
        this(filePath, destPath, 10);
    }
    public SplitFileDemo(String filePath, String destPath, long blockSize){
        blockPath = new ArrayList<>();
        this.filePath = filePath;
        this.destPath = destPath;
        this.blockSize = blockSize;
        init(); //初始化各項參數
    }
	
    private void init(){
        /**
         * @Description: 初始化操作:修正每塊大小、計算塊數、確定文件名
         */
        File src = null;
        //健壯性
        if(null==filePath || !(src=new File(filePath)).exists() || !(src.isFile()) ){
            return;
        }
	
        //文件名
        this.fileName = src.getName();
        //修正每塊大小、計算塊數
        this.length = src.length(); //文件實際大小
	
        if(this.blockSize > length){//修正每塊大小
            this.blockSize = length;
        }
	
        //確定塊數
        n = (int)Math.ceil(length*1.0/this.blockSize); //Math.ceil(double a)返回大於等於a的最小整數,返回double類型
        initPathName(destPath);
    }
	
    private void initPathName(String destPath){//確定文件名
        for(int i=0; i<n; ++i){
            blockPath.add(destPath + "/" + fileName + ".part" + i);
        }
    }
	
    //文件分割
    public void split(){
        /**
         * @Description: 上面都是爲文件分割做準備,現在開始分割
         * @Param: [destPath] 分割文件存放的目錄
         * 文件分割:
         * 第幾塊、起始位置、實際大小
         */
        long beginPos = 0; //起始點
        long actualBlockSize = blockSize; //實際大小
        for(int i=0; i<n; ++i){
            if(i==n-1){
                actualBlockSize = this.length-beginPos;
            }
            splitDetail(i, beginPos, actualBlockSize);
            beginPos += actualBlockSize;
        }
    }
	
    private void splitDetail(int blockNum, long beginPos, long actualBlockSize){
        /**
         * @Description:文件分割的具體操作,其實就是文件拷貝過程
         * 輸入流:RandomAccessFile
         * 輸出流: FileOutputStream
         * @Param: [blockNum, beginPos, actualBlockSize] 第幾塊、起始點、實際每塊大小(主要針對最後一塊)
         */
        //1.創建源
        File src = new File(this.filePath);
        File dest = new File(this.blockPath.get(blockNum));
        //2.選擇流
        RandomAccessFile rnd = null;//參數"r"只讀
        BufferedOutputStream fo = null;
        try {
            rnd = new RandomAccessFile(src, "r");
            fo = new BufferedOutputStream(new FileOutputStream(dest));
            //3.操作
            rnd.seek(beginPos); //從beginPos位置開始讀取文件
            byte[] b = new byte[1024]; //定義緩衝區
            int len = 0;//實際讀取長度
            //目標:從文件beginPos位置讀取actualBlockSize大小的東西,每次實際讀取len大小
            while(-1 != (len=rnd.read(b))){
                if(len<actualBlockSize){
                    fo.write(b, 0, len); //寫入文件
                    fo.flush();
                    actualBlockSize -= len;
                }
                else{//最後一塊了
                    fo.write(b, 0, (int)actualBlockSize); //寫入文件
                    fo.flush();
                    break;
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            try {
                if(rnd!=null){
                    rnd.close();
                }
                if(fo!=null){
                    fo.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
	
    //文件合併--法1
    public void mergeFile(String destPath) {
        /**
         * @Description:文件合併的具體操作,其實就是文件拷貝過程
         * 輸入流:FileInputStream
         * 輸出流: FileOutputStream
         * @Param: [destPath] 合併後文件的存放目錄
         */
        File dest = new File(destPath);
        BufferedOutputStream fo = null;
        try {
            fo = new BufferedOutputStream(new FileOutputStream(dest,true));
            for (int i = 0; i < blockPath.size(); ++i) {
                //1.創建源
                File src = new File(this.blockPath.get(i));
                //2.選擇流
                BufferedInputStream fs = null;//參數"r"只讀
	
                fs = new BufferedInputStream(new FileInputStream(src));
	
                //3.操作
                byte[] b = new byte[1024]; //定義緩衝區
                int len = 0;//實際讀取長度
                while (-1 != (len = fs.read(b))) {
                    fo.write(b, 0, len); //寫入文件
                    fo.flush();
                }
	
                fs.close();
            }
        }catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try{
                if (fo != null) {
                    fo.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
	
    //文件合併--法2--SequenceInputStream:將很多流組合成一個流的InputStream
    public void merge2(String destPath){
        /**
         * @Description: SequenceInputStream(Enumeration<? extends InputStream> e)
         * Enumeration:vector
         * @Param:
         * @return: void
         */
        //1.創建源
        File dest = new File(destPath);
        //2.選擇流
        SequenceInputStream sis = null;  //輸入流
        BufferedOutputStream fo = null; //輸出流
        //創建一個容器用於後面組合流
        Vector<InputStream> vi = new Vector<>();
        try {
            for (int i = 0; i < blockPath.size(); ++i){
                vi.add(new BufferedInputStream(new FileInputStream(new File(this.blockPath.get(i)))));
            }
            sis = new SequenceInputStream(vi.elements()); //SequenceInputStream組合流;vi.elements()返回此向量的枚舉
            fo = new BufferedOutputStream(new FileOutputStream(dest,true));
            //3.操作
            byte[] b = new byte[1024]; //定義緩衝區
            int len = 0;//實際讀取長度
            while (-1 != (len = sis.read(b))) {
                fo.write(b, 0, len); //寫入文件
                fo.flush();
            }
        }catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try{
                if (fo != null) {
                    fo.close();
                }
                if (sis != null) {
                    sis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
	
    public static void main(String[] args){
        String fileSrc = "/Users/braincao/git/1.txt"; //要分割的文件
        String destPath = "/Users/braincao/git"; //分割後文件存放目錄
        String destMergePath = "/Users/braincao/git/test.txt"; //合併後文件的路徑
        SplitFileDemo file = new SplitFileDemo(fileSrc, destPath, 20);
        file.split(); //文件分割
//        file.mergeFile(destMergePath); //文件合併--法1
        file.merge2(destMergePath); //文件合併--法2
    }
}

File類的一個例子

獲取git目錄下後綴名爲.txt的文件

	public static void test1(){
	        File file = new File("/Users/braincao/git");
	        FilenameFilter filter = new FilenameFilter() {
	            @Override
	            public boolean accept(File dir, String name) {
	                return name.endsWith(".txt"); //文件名的後綴要以.txt
	            }
	        };
	        String[] ff = file.list(filter);
	        for(String f: ff){
	            System.out.println(f);
	        }
	    }

日期Date、Calendar相關Demo

打印指定日期的月曆:

import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.Scanner;
	
/**
 * @Description: 鍵盤輸入一個日期,打印該日期所在月份的月曆
 */
public class TestDemo{
    public static void main(String[] args) throws ParseException {
        //1.獲取輸入字符串的日期
        System.out.println("請輸入想要查看的日期:(2018-11-09)");
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        Date d = java.sql.Date.valueOf(s);
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);
        int thisDay = cal.get(Calendar.DAY_OF_MONTH); //指定的日期
        int days_of_month = cal.getActualMaximum(Calendar.DAY_OF_MONTH); //這個月有多少天。getActualMaximum-->返回指定Calendar日曆字段可能擁有的最大值。
        cal.set(Calendar.DAY_OF_MONTH, 1);
        int week_of_firstDay_of_month = cal.get(Calendar.DAY_OF_WEEK); //這個月1號是周幾
	
        //2.打印指定日期的月份
        System.out.println("日\t一\t二\t三\t四\t五\t六");//1週日 2週一 3週二 4週三 5週四 6週六 7週日
        //2.1 打印1號之前的空格
        String suffixHead = "";
        for(int i=1; i<=week_of_firstDay_of_month-1; ++i){
            suffixHead = suffixHead+"\t";
        }
        System.out.print(suffixHead);
        int cnt = week_of_firstDay_of_month; //打印月曆時換行的計數器
        //2.2 打印本月月份,並將指定的當天日期後加"*"
        for(int cntDay=1; cntDay<=days_of_month; ++cntDay){
            if(cntDay==thisDay){
                System.out.print(cntDay + "*\t");
            }
            else{
                System.out.print(cntDay + "\t");
            }
            //判斷是否換行
            if(cnt%7 == 0){
                System.out.println();
                cnt = 1;
            }
            else{
                cnt++;
            }
        }
    }
}

out:

請輸入想要查看的日期:(2018-11-09)
2018-10-09
日	一	二	三	四	五	六
	1	2	3	4	5	6	
7	8	9*	10	11	12	13	
14	15	16	17	18	19	20	
21	22	23	24	25	26	27	
28	29	30	31
	

枚舉Demo

什麼情況用枚舉:值比較少且固定時

import java.text.ParseException;
	
/**
 * @Description: 枚舉使用Demo
 */
	
enum Gendar{ //枚舉,}
	
class Person{
    private String name;
    private int age;
    private Gendar sex; //使用枚舉
	
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                '}';
    }
	
    public Person(String name, int age, Gendar sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
	
    public Person() {
    }
	
	
    public String getName() {
        return name;
    }
	
    public void setName(String name) {
        this.name = name;
    }
	
    public int getAge() {
        return age;
    }
	
    public void setAge(int age) {
        this.age = age;
    }
	
    public Gendar getSex() {
        return sex;
    }
	
    public void setSex(Gendar sex) {
        this.sex = sex;
    }
}
	
public class TestDemo{
    public static void main(String[] args) throws ParseException {
        Person p = new Person();
        p.setName("張三");
        p.setAge(25);
        p.setSex(Gendar.); //用枚舉進行設置。好處:如果是String類型的sex,會遇到亂七八糟的String,這樣給判斷String帶來很多麻煩,用枚舉更好
        System.out.println(p.toString());
	
        //枚舉與switch結合使用
        Gendar sex = Gendar.;
        switch (sex){
            case:
                System.out.println("這是男孩");
                break;
            case:
                System.out.println("這是女孩");
                break;
        }
    }
}

Math.random()與Random r = new Random(long seed)

public static void main(String[] args){
    System.out.println(Math.random()*10);
    System.out.println("-------------");

    Random r = new Random(10); //new Random(long seed)seed是生成隨機數的種子,seed不變生成的隨機數也不變,seed變了隨機數也就變了
    for(int i=0; i<5; ++i){//重複運行發現生成的隨機數都相同,僞隨機數
        System.out.println(r.nextInt());
    }
    System.out.println("-------------");

    Random r1 = new Random(System.currentTimeMillis()); //new Random(long seed)seed是生成隨機數的種子,seed不變生成的隨機數也不變,seed變了隨機數也就變了
    for(int i=0; i<5; ++i){//重複運行發現生成的隨機數都不同,因爲種子變了
        System.out.println(r1.nextInt());
    }
}

out:

1.7647342360229157
-------------
-1157793070
1913984760
1107254586
1773446580
254270492
-------------
958951514
-1748165986
967614401
9816424
-782039092

管道流

PipedInputStream和PipedOutputStream:輸入輸出可以直接進行連接,通過結合線程使用。

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
	
/**
 * @Description: 管道流結合多線程使用
 */
public class TestDemo{
    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(); //Input是一個線程
        new Thread(new Output(output)).start(); //Output是一個線程
    }
}
	
class Input implements Runnable{
    private PipedInputStream in;
    public 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 (IOException e){
            e.printStackTrace();
        }
    }
}
	
class Output implements Runnable{
    private PipedOutputStream out;
    public Output(PipedOutputStream out){
        this.out = out;
    }
    public void run(){
        try{
            out.write( "hi,管道來了!".getBytes());
            out.flush();
            out.close();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}
	
//out: s=hi,管道來了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章