IO流

IO

1.概念

输入:硬盘--->内存 (读)

输出:内存---->硬盘 (写)

有的流是按照字节的方式读取数据,一次读取一个字节Byte,这种流是万能的,什么类型的数据文件都可以读取,包括:文本、图片、声音、视频

有的流是按照字符的方式读取数据,一次读取一个字符,这种流是为了方便读取普通文本文件而存在,只能读取“TXT”,连word都不行

? 类名以Stream结尾是字节流、以Reader/Writer结尾是字符流

java.io.InputStream
java.io.OutputStream
java.io.Reader
java.io.Writer
    //全为抽象类
  • 所有流都实现了java.io.Closeable接口,都是可以关闭的,都有close()方法,流使用完必须要关闭,以免浪费资源,finally中的close分开抓捕异常,以免其中一个异常导致另一个无法关闭,并且遵循先开后关原则

  • 所有输出流都实现了java.io.Flushable接口,都是可刷新的,都有flush()方法,输出流在最终输出后一定要刷新,将管道清空(把其中剩余未输出的数据强行输出),否则可能导致数据丢失

2.分类

  • 文件专属:

    FileInputStream
    FileOutputStream
    FileReader
    FileWriter
    
  • 转换流:字节流转换成字符流

    InputStreamReader
    OutputStreamReader
    
  • 缓冲流

    BufferedReader
    BufferedWriter
    BufferedInputStream
    BufferedOutputStream
    
  • 数据流专属

    DataInputStream
    DataOutputStream
    
  • 标准输出流

    PrintWriter
    PrintStream
    
  • 对象专属流

    ObjectInputStream
    ObjectOutputStream
    

3.FileInputStream

public static void main(String[] args) {
        FileInputStream fis =null;//外面声明,在finally中才能调用
        try {
            fis=new FileInputStream("C:\\Users\\Monster y\\Desktop\\movie.txt");
            while(true){
                int readData= fis.read();//返回字符的ASCII值
                if(readData==-1)break;
                System.out.println(readData);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (fis!=null){//关闭输入流
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
  byte[] bytes=new byte[4];
while(true){
               int readCount=fis.read(bytes);
                System.out.println(readCount);
                for (int a:bytes) {
                    System.out.println(a);
                }
                if (readCount==-1)break;
            }
//当文件中是:abcdef
//第一次读:abcd readCount=4
//第二次读:ef   readCount=2	ef会替换掉ab	
//第三次读:readCount=-1

其他方法

  • int available()返回流当中剩余的没有督导的字节数量
  • long skip(long n) 跳过n个字节不读

4.FileOutputStream

public class Demo03 {
    public static void main(String[] args) {
        FileOutputStream fos =null;//外面声明,在finally中才能调用
        try {
            fos=new FileOutputStream("C:\\Users\\Monster y\\Desktop\\456.txt",true);
            //若文件不存在会自己新建文件
            //这里加true表示原文件非空时,在后面追加,没有true则在清空后写入,但一次程序的多次写入不会清空
            byte[] bytes={97,98,99,100};
            fos.write(bytes);//写出数组
            fos.flush();//写完后刷新
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos!=null){//关闭输入流
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

5.FileReader和FileWriter

用法和上面类似,注意数组换成char类型!!!

6.BufferedReader

带有缓冲区的字符输入流,使用这个流时不需要自定义char[]数组/byte[]数组,自带缓冲

public class Demo04 {
 public static void main(String[] args) throws IOException {
    FileReader reader= new FileReader("C:\\Users\\Monster y\\Desktop\\456.txt");
    BufferedReader bufferedReader=new BufferedReader(reader);//包装流
    String s=null;
    if (((s=bufferedReader.readLine())!=null))
        System.out.println(s);
    bufferedReader.close();//关闭外层流
 }
}

若当一个流的构造方法需要传进来一个流的时候,传进来的叫节点流,负责外部包装的流叫包装流/处理流

对于包装流,关闭外层流后节点流默认关闭

7.InputStringReader

FileInputStream fileInputStream=new FileInputStream("路径");//字节流
InputStreamReader inputStreamReader=new InputStreamReader(fileInputStream);
//字节流--->字符流
BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
//这里是字符输入缓冲流,只能传入字符流
bufferedReader.close();//关闭最外层

8.数据流专属

DataOutputStream写的文件只能用DataInputStream去读,并且读的时候需要提前知道写入的顺序。读的顺序与写的顺序一致才能正常取出数据

这两个都是包装流

public class Demo05 {
    public static void main(String[] args) {
        FileInputStream fileInputStream=null;
        FileOutputStream fileOutputStream=null;
        DataInputStream dataInputStream=null;
        DataOutputStream dataOutputStream=null;
        try {
            fileInputStream=new FileInputStream("C:\\Users\\Monster y\\Desktop\\456.txt");
            fileOutputStream=new FileOutputStream("C:\\Users\\Monster y\\Desktop\\456.txt");
            dataInputStream=new DataInputStream(fileInputStream);
            dataOutputStream=new DataOutputStream(fileOutputStream);
           //写~~~~~~~
            dataOutputStream.writeByte(12);
            dataOutputStream.writeChar(‘a‘);
            dataOutputStream.writeLong(1234l);
		   //读~~~~~~~
            byte b=dataInputStream.readByte();
            char c=dataInputStream.readChar();
            long l=dataInputStream.readLong();
            System.out.println(b);
            System.out.println(c);
            System.out.println(l);

            dataOutputStream.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (dataInputStream!=null)try {
                dataInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (dataOutputStream!=null) {
                try {
                    dataOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

9.标准输出流

PrintStream :标准字节输出流,默认输出到控制台该流不需要手动关闭

System.out.println("hello");
//等价于
PrintStream ps=System.out;
ps.println("hello");
PrintStream ps=new PrintStream(new FileOutputStream("路径") );
System.setOut(ps);
//标准输出流不再指向控制台,而是指向给出的路径标准输出流不再指向控制台,而是指向给出的路径

10.File类

File类不能完成文件的读和写,File对象代表:目录和文件路径名的抽象表示形式

public class TestFile01 {
    public static void main(String[] args) {
        File file = new File("E:\\模电三\\1\\a\\b\\d");//创建File对象
        if (!(file.exists())){//判断file是否存在
            try {
                file.createNewFile();//以文件形式创建出来
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        file.mkdir();//以目录(文件夹)
        file.mkdirs();//创建多重目录  路径为E:\1\a\b\d,文件夹1、a、b、d都不存在,可一次性创建

    }
}
  • 获取父路径

    File file1=new File("E:\\模电三\\1\\a\\b\\d");
    String parentPath=file1.getParent();//获取父路径     
    //E:\模电三\1\a\b
    File parentFile=file1.getParentFile();
    System.out.println(parentFile.getAbsoluteFile());//获取绝对路径 E:\模电三\1\a\b
    
  • 常用方法

    String getName();//获取文件名
    olean isDirectory();//判断是否为目录
    olean isFile();//判断是否为文件
    ng lastModified();//最后修改时间,返回自1970以来的毫秒数
    ng length();//获取文件的大小
    le[] listFiles();//获取当前目录下所有子文件
    

11.序列化与反序列化

序列化:Serialize java对象存储到文件中

反序列化:DeSerialize 硬盘上的数据恢复到内存中,恢复成java对象

java.io.NotSerializableException :java对象不支持序列化异常

参与序列化和反序列化的对象必须实现Serializable接口,此接口为标志接口,没有任何方法,主要用来给JVM识别,JVM会自动为其生成一个序列化版本号。参与序列化的集合和集合中的元素也都要实现此接口。

public class Demo06 {
    public static void main(String[] args)  {
        ObjectOutputStream oos= null;
        ObjectInputStream ois=null;
        Object o = new User(15);
        try {
            oos = new ObjectOutputStream(new FileOutputStream("E:\\模电三\\1\\a\\b\\d\\c"));
            ois=new ObjectInputStream(new FileInputStream("E:\\模电三\\1\\a\\b\\d\\c"));
            oos.writeObject(o);//序列化(写)
            Object oo=ois.readObject();//反序列化(读)
            System.out.println(oo.toString());
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                oos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }
}
class User implements Serializable {
    private int age;
    //无参数构造方法
    public User() { }
    //有参数构造方法
    public User(int age) {
        setAge(age);
    }
    public void setAge(int age) {
        if(age<0|age>150){
            System.out.println("您的年龄输入不合法!");
            return;
        }
        this.age = age;
    }
    public int getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Age : "+age;
    }
}

若希望某个属性不参与序列化,加上transient 关键字。

序列化版本号可以用来区分类名一样的两个类(类体不同),自动生成缺点:一旦代码确定,后续不可修改,因为修改后版本号不同,JVM会将其识别为另一个类,导致以前序列化的对象无法反序列化。建议实现Serializable接口的类都手动给出固定的序列化版本号:

private static final long serialVersionUID=132l;

IO流

上一篇:ES6特性-rest 与 扩展运算符(...)


下一篇:bzoj4543[POI2014]Hotel