Java学习-IO流

IO流学习

流的分类

  • 根据操作单位不同分为字节流和字符流
  • 根据流向不同分为输入流和输出流
  • 根据角色不同分为节点流和处理流

以下四个类是IO流中最基础的类,都是抽象类。其他流都是继承他们的。

分类字节流字符流
输入流InputStreamReader
输出流OutputStreamWriter

字节流:操作的对象是字节数组
字符流:操作的对象是字符数组

节点流:作用在文件上的流,直接对文件进行读写操作
处理流:作用在节点流上的流,可以加速流的传输

输入流和输入流是相对的,主要看你站在那个角度来看待,如果站在程序的角度,读入数据较输入流,写出数据较输出流。

IO流体系结构

分类字节输入流字节输出流字符输入流字符输出流
抽象基类InputStreamOutputStreamReaderWriter
访问文件FileInputStreamFileOutputStreamFileReaderFileWriter
访问数组ByteArrayInputStreamByteArrayOutputStreamCharArrayReaderCharArayWriter
访问管道PipedInputStreamPipedOutputStreamPipedReaderPipedWriter
访问字符串StringReaderStringWriter
缓冲流BufferedInputStreamBufferedOutputStreamBufferedReaderBufferedWriter
转换流InputStreamReaderOutputStreamWriter
对象流ObjectInputStreamObjectOutputStream
过滤流FilterInputStreamFileOutputStreamFilterReaderFileWriter
打印流PrintStreamPrintWriter
推回输入流PushbackInputStreamPushbackReader
特殊流DataInputStreamDataOutputStream

访问文件的流都是节点流,其他除了抽象基类外都是处理流

File类

想要进行IO操作,肯定离不来文件,所以学习IO流的前提就是要学会File类的操作。

File类的介绍

File是用来操作文件或目录的,但是不能对文件的内容进行操作,主要是用于文件和目录的创建、文件的删除、文件的查找。

File类构造方法

File类表示的是硬盘中实际存在的目录或文件,可以通过以下三种方式创建一个File类的对象。

File(String pathname)//通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。 常用

File(File parent, String child) //从父抽象路径名和子路径名字符串创建新的 File实例。常用

File(String parent, String child) //从父路径名字符串和子路径名字符串创建新的 File实例。 常用

File(URI uri) //通过将给定的 file: URI转换为抽象路径名来创建新的 File实例。

代码举例:

    @Test
    public void test(){

        //根据路径创建
        String path = "d:\\file.txt";
        File file = new File(path);

        //根据父文件和子类路径创建
        File parentFile = new File( "d:\\io");
        File file1 = new File(parentFile,"file1.txt");

        //根据父路径和子路径创建
        String parentPath = "d:\\io";
        String childPath = "file2.txt";
        File file2 = new File(parentPath,childPath);

    }

注意:在Windows中路径分割使用‘\’,在Linux中使用‘/’,为了方便区分在File类中有一个separator 属性,可以用来代替分隔符。
在Java中 \ 是用来转义的,所以这里需要使用两个 \ 字符

路径问题

相对路径:相对于当前的项目路径,不带盘符。如: “hello.txt”
绝对路径:相对于硬盘的物理路径,是一个带有盘符的完整路径。如:“d:\hi.txt”

如代码所示,目前文件只是存在于内存中,还没有在硬盘上创建实际的文件,需要使用一些方法来创建,下面介绍File类中的常用方法。

File类常用方法

1、获取的方法

public String getAbsolutePath() //绝对路径名字符串。
public String getPath() //将此抽象路径名转换为路径名字符串。
public String getName() //返回由此抽象路径名表示的文件或目录的名称。
public String getParent() //返回上层文件目录路径,没有则返回null。
public long length() //返回由此抽象路径名表示的文件的长度。 长度指的是文件的字节数,不能获取目录的长度。
public String[] list() //获取指定目录下的所有文件或文件目录的名称数组
public File[] listFiles() //获取指定目录下的所有文件或文件目录的File数组

    @Test
    public void test3(){
        File file = new File("f:\\io\\hello.txt");

        System.out.println("绝对路径:"+file.getAbsolutePath());
        System.out.println("路径:"+file.getPath());
        System.out.println("名字:"+file.getName());
        System.out.println("上层路径:"+file.getParent());
        System.out.println("长度"+file.length());
        System.out.println("文件目录:"+file.list());
        System.out.println("文件目录"+file.listFiles());
    }

/*
运行结果:
绝对路径:f:\io\hello.txt  
路径:f:\io\hello.txt
名字:hello.txt
上层路径:f:\io
长度0  -->因为文件中没有内容,所以是0
文件目录:null  --> 因为当前是一个文件,所以没有目录,如果是一个目录就会有
文件目录null  --> 因为当前是一个文件,所以没有目录,如果是一个目录就会有
*/
进行判断的方法

public boolean exists()//判断文件或目录是否存在
public boolean isDirectory()//判断是否是目录
public boolean isFile()//判断是否是文件

    @Test
    public void test5(){
        File file = new File("hello.txt");//该文件没建过
        System.out.println("文件是否存在"+file.exists());//false
        System.out.println("是否是目录"+file.isDirectory());//false
        System.out.println("是否是文件"+file.isFile());//false,因为连文件都没有,所以是false

        File file1 = new File("hello.txt");//该文件我已经创建过了
        System.out.println("文件是否存在"+file1.exists());//true
        System.out.println("是否是目录"+file1.isDirectory());//false
        System.out.println("是否是文件"+file1.isFile());//true
    }

进行创建的方法

public boolean createNewFile() //如果文件不存在则创建一个新的空文件返回true,如果存在,不创建,返回false;
public boolean mkdir()//创建文件目录,如果文件目录存在,不创建,如果文件的上层目录不存在,也不创建;
public boolean mkdirs()//创建文件目录,如果上层文件目录不存在,也一起创建

    @Test
    public void test4() throws IOException {
        File file = new File("test.txt");
        
        System.out.println(file.createNewFile());//true
        
        File file1 = new File("f:\\test\\hello");
        file1.mkdir();//test和hello目录都不存在,不会创建
        
        File file2 = new File("f:\\test\\hello\\java");
        file2.mkdirs();//test和hello目录都不存在,会全部创建
        
    }
进行删除的方法

public boolean delete()//删除文件或目录

File类练习

打印指定文件目录下的所有文件-递归实现

//递归打印文件
    @Test
    public void test6(){
        File file = new File("f:\\io");
        printFile(file);
    }

    public void printFile(File file){
        File[] files = file.listFiles();
        for (File f : files) {
            if(f.isDirectory()) printFile(f);
            System.out.println(f.getName());
        }
    }

字符流

纯文本文件都用字符流来处理

字符输入流

FileReader

1、构造方法

FileReader(File file) //根据file创建一个对象
FileReader(String fileName)//根据文件目录创建一个对象

2、常用方法

public int read()//从文件中读取一个字符,如果文件中没有字符了返回-1
public int read(char[] cbuf)//从文件中读取多个字符,如果文件中没有字符了返回-1,如果有返回读了多少个字符
public void close();//关闭流

使用FileReader读取hello.txt中的内容
hello.txt

    @Test
    public void test1()   {
        FileReader reader = null;
        try {
            File file = new File("hello.txt");
            reader = new FileReader(file);
            char[] cbuf = new char[5];
            int len = 0;
            // 方式一,每次读一个字符
            while((len = reader.read()) != -1){//每次读一个字符
                System.out.print((char)len);

            }
            /*方式二,每次读多个字符
            while ((len = reader.read(cbuf)) != -1){
                for (int i = 0; i < len; i++) {//这里不能使用cbuf.length;因为在最后可能字符不够5个,所以使用len
                    System.out.print(cbuf[i]);
                }
            }
            */
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
/*
运行结果:
      hellojava
*/

使用IO流都有可能会出现异常,所以在这里需要使用try\catch\finally来处理异常

字符输出流

FileWriter

1、构造方法

FileWriter(File file) //根据file创建一个对象
FileWriter(File file, boolean append) // 根据file创建一个对象,并根据append判断在多次写入数据是否覆盖,默认false,选择覆盖
FileWriter(String fileName) // 根据字符串创建一个对象
FileWriter(String fileName, boolean append) //同上,true表示不覆盖,false表示覆盖,默认false

2、常用方法

public void wirte(int c)//写入一个字符
public void wirte(char[] cbuf)//写入多个字符
public void wirte(char[] cbuf, int off, int len)//写入字符的长度由len决定,off表示从那开始。
public void wirte(String str)//写入字符串
public void wirte(String str, int off, int len)//写入部分字符串,有off和len决定,off表示开始的下标,len表示长度
public void flush()//刷新缓存区,如果没有关闭流则数据不会写入文件
public void close()//关闭流,关闭流之后会自动刷新缓存

使用FileWriter向hello.txt中写入数据

    @Test
    public void test8(){
        FileWriter fw = null;
        try {
            File file = new File("hello.txt");
            fw = new FileWriter(file);
            String str = "i love java";
            fw.write(str);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fw != null) {
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

结果:

注意:字符流不能处理非文本的数据

字节流

非纯文本文件使用字节流来处理

字节输入流

FileInputStream

1、构造方法

FileInputStream(File file)//根据file创建一个字节输入流对象
FileInputStream(String name)//根据文件路径创建一个字节输入流对象

2、常用方法

public int read()//从文件中读取一个字节,如果文件中没有字节了返回-1
public int read(b[] b)//从文件中读取多个字节,如果文件中没有字节了返回-1,如果有返回读了多少个字节
public void close();//关闭流

使用FileInputStream读取hello.txt中的内容

    @Test
    public void test9(){
        FileInputStream fis = null;
        try {
            File file = new File("hello.txt");
            fis = new FileInputStream(file);
            int len;
            while((len = fis.read()) != -1){//每次读一个字节
                System.out.print((char)len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

字节输出流

FileOutputStream

1、构造方法

FileOutputStream(File file)//根据file创建一个字节输出流对象
FileOutputStream(File file, boolean append)//通过append判断是否覆盖,默认为false,覆盖,true为不覆盖
FileOutputStream(String name) //根据文件路径创建一个字节输出流对象
FileOutputStream(String name, boolean append)//同上

2、常用方法

public void wirte(int c)//写入一个字节
public void wirte(byte[] b)//写入多个字节
public void wirte([] b, int off, int len)//写入字节的长度由len决定,off表示从那开始。
public void close()//关闭流,

使用FileOutputStream向hello.txt中写入数据

    @Test
    public void test10(){
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(new File("hello.txt"));
            String str = "hellojava";
            fos.write(str.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

运行结果:

因为我都选择默认不append,所以每次都是将之前的覆盖掉

缓冲流

缓冲流的主要目的就是提高之前的流的读取或写入的速度。
缓冲流的使用方法和字符流或字节流一样。这里就介绍一下如何声明一个缓冲流。

字符缓冲流

1、构造方法

BufferedReader(Reader in)
BufferedWriter(Writer out)
注意:构造方法的参数是一个抽象类,在传参的时候应该传该抽象类的实现类
使用

BufferedReader br = new BufferedReader(new FileReader(new File("hello.txt")));
BufferedWriter bw = new BufferedWriter(new FileWriter(new File("hello.txt")));

2、特有方法

public String readLine()//读一行
public void newLine()//换行

字节缓冲流

1、构造方法

BufferedInputStream(InputStream in)
BufferedOutputStream(OutputStream out)

注意:构造方法的参数是一个抽象类,在传参的时候应该传该抽象类的实现类

BuffededInputStream bis = new BufferedInputStream(new FileInputStream("hello.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileInputStream("hello.txt"));

转换流

转换流就是将字节流转换为字符流或将字符流转换为字节流。

InputStreamReader(将字节流转换为字符流)

1、构造方法

InputStreamReader(InputStream in) //创建一个默认字符集的转换流
InputStreamReader(InputStream in, String charsetName) //创建一个指定字符集的转换流

2、使用

@Test
    public void test11(){
        InputStreamReader isr = null;
        InputStreamReader isr1 = null;
        try {
            isr = new InputStreamReader(new FileInputStream("hello.txt"));//默认字符集
            isr1 = new InputStreamReader(new FileInputStream("hello.txt"),"GBK");//默认GBK字符集,会出现乱码
            int len = 0;
            while((len = isr.read()) != -1){
                System.out.print((char)len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(isr != null) {
                try {
                    isr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
/*
运行结果:
hellojava
*/

OutputStreamWriter(将字符流转换为字节流)

1、构造方法

OutputStreamWriter(OutputStream out)//创建一个默认字符集的转换流
OutputStreamWriter(OutputStream out, String charsetName) //创建一个指定字符集的转换流

2、使用

@Test
    public void test12(){
        OutputStreamWriter osw = null;
        try {
            osw = new OutputStreamWriter(new FileOutputStream("hello.txt",true));
            String str = "hellojava";
            osw.write(str);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(osw != null) {
                try {
                    osw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

运行结果:
在这里插入图片描述

序列化流

序列化流分为:序列化和反序列化
序列化:就是将自己写的一个对象持久化到硬盘上,
反序列化:将序列化到硬盘上的对象取出来
要求:序列化的类必须实现Serializable接口,而且这个类的属性也必须是可序列化的。8个基本类型是可序列化的。

重点:被static和transient修饰的属性是不会被序列化的。

序列化-ObjectOutputStream

1、构造方法

ObjectOutputStream(OutputStream out) //参数是一个抽象类,需要传一个它的子类

2、使用

    @Test
    public void test13(){
        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream("hello.txt"));
            oos.writeObject(new User("Tom",3));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

运行结果:

报错了,为什么呢?因为User类没有实现Serializable接口。当实现了接口后就能正常的序列化了。

ObjectInputStream-反序列化

1、构造方法

ObjectInputStream(InputStream in)

2、使用

    @Test
    public void test14(){
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("hello.txt"));
            User user = (User) ois.readObject();
            System.out.println(user);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if(ois != null){
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }  

运行结果:

反序列化后,得到了刚才序列化的内容。

写在最后

花了一天时间,总算是自己把IO的部分总结了一下,怎么说呢,总结的肯定是不够完整和细致的,以后在实践中慢慢的在完善吧!
自己还是太菜了。需要学习的地方还很多!不学习就找不到工作!!!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值