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,管道来了!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值