Java IO学习总结

File

一.概念

java.io
    将字符串形式的路径,封装成File类,File类提供了大量的直接操作文件和文件夹的方法。

二.File的静态常量

static String pathseparator
    与系统有关的路径分隔符
    返回“;”--------路径和路径用“;”隔开 (比如环境变量)

static String separator
    与系统有关的默认名称分隔符
    返回“\”--------文件名和文件名用“\”隔开

将来开发要求我们写的代码要跨平台
Windows上的路径名称分隔符是 \\
Linux上的路径名称分隔符是 /

String path = "G:\\idea\\io";//如果这样写,到Linux系统上直接就废废了

String path = “G:”+File.separator+"idea"+File.separator+"io";//这才是标准写法!

三.构造方法

File(File parent, String child)
    根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。

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

File(String parent, String child)
    根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。

四.获取File

File getAbsoluteFile()
    返回此抽象路径名的绝对路径名形式。

String getPath()
    将此抽象路径名转换为一个路径名字符串。

String getName()
    返回由此抽象路径名表示的文件或目录的名称。

long length()
    返回由此抽象路径名表示的文件的长度。

File getParentFile()
    返回此抽象路径名父目录的抽象路径名;如果此路径名没有指定父目录,则返回 null。

五.相对路径和绝对路径

    绝对路径:
        从盘符开始写

    相对路径:
        都有一个参照,相对于那个路径,那个路径就是参照
idea中文件的路径都是以我们项目(project)的根路径为参照的(哪个路径作为参照路径,哪个路径就可以不写)
        idea中写相对路径:从模块开始写

六.File的创建方法

boolean createNewFile()
    当且仅当具有该名称的文件尚不存在时,创建一个新的空文件。

boolean mkdir()
    创建单级文件夹

boolean mkdirs()
    创建多级文件夹

七.File类的删除方法

public boolean delete():
    删除由此File表示的文件或者文件夹

 结论:不要随意使用
      1.删除文件夹的时候,只能删除空文件夹
      2.此方法删除之后,不走回收站

八.File类的判断方法

public boolean exists()
    判断我们指定的文件或者文件夹是否存在的
    如果不存在,返回值false
    如果存在,返回的是true

public boolean isDirectory()
    判断是否为文件夹
    如果不是,返回false
    如果是,返回true

public boolean isFile():
    判断是否为文件
    如果不是,返回false
    如果是,返回true

九.File的遍历方法

public String[] list():
    获取指定文件夹路径下的文件夹以及文件的名字(路径)

public File[] listFiles():
    获取指定文件夹路径下的文件夹以及文件路径,把他们封装成File对象


IO

一.分类

字节流:一切皆字节(图片/音乐/视频/文字)
    字节输出流:OutputStream
    字节输入流:InputStream
字符流:操作字符的(主要操作的是保存在文本文档中的内容比如.txt .html .css等)
    字符输出流:Writer
    字符输入流:Reader

二.字节流

字节输出流

因为是抽象类所以我们直接操作他的子类FileOutputStream
1.构造
参数指定我们数据写到哪个位置
我们自定义的文件即使没有,自动创建,如果已经存在,在创建,会把先创建的文件覆盖掉。

  • FileOutputStream(File file)
  • FileOutputStream(String name)

2.所有的流通用的写法
1.创建对象
2.写数据或读取数据
3.关流–>close()

3.方法

  • void write(int b)->一次写一个字节
  • void write(byte[] b)->一次写一个字节数组
  • void write(byte[] b, int off, int len)->一次写一个字节数组一部分
                byte[] b:要写哪个字节数组中的内容
                off:从数组的哪个索引开始写
                len:写多少个
  • void close()->关闭流对象

    当我们想要利用字节流随意的往文件里写字符,但是又不知道该字符对应的ASCII码表对应的数字,那么我们可以用下面这个方法
“要写到文件的字符串”.getbytes();---->将字符串转化为字节数组。

4.FileOutputStream的续写功能

  • FileOutputStream(String name,boolean append)
    append:默认false(不追加内容)
                        true(追加内容)

5.换行符:
windows:\r\n
Linux : \n
但是这样换行也不能实现跨平台

字节输入流

    因为是抽象类所以我们直接操作他的子类FileInputStream

1.构造
参数传递要读取的文件位置

  • FileInputStream(File file)
  • FileInputStream(String name)

2.方法

  • int read():读一个字节
  • int read(byte[] b):读取一个字节数组
  • int read(byte[] b, int off, int len):读一节字节数组
                b:要读取的字节数组
                off:从哪个索引开始读
                len:读多少个
  • void close():关闭资源

3.循环读取一个字节
我们在对应的.txt文件中存入abc三个字符

public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("day15\\a.txt");

        int read1 = fis.read();
        System.out.println(read1);

        int read2 = fis.read();
        System.out.println(read2);

        int read3 = fis.read();
        System.out.println(read3);

        int read4 = fis.read();
        System.out.println(read4);
    }

运行结果
通过以下代码运行结果我们可以看到,当调用了4个读取一个字节的方法时,最后以获取到的是-1,至于为什么返回的负一,这个不得而知,因为这方法的底层是native方法,c语言写的本地方法。
这只是有3个字符,当有很多个字符一个一个的写显然不怎么样!那么竟然读不到数据返回-1,我们可以利用这个条件作为循环条件来读。

public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("day15\\a.txt");

        int len = 0;
        //如果读不到数据了len = fis.read()这是len的值就是-1,就会停止循环
        while ((len = fis.read())!= -1){
            System.out.println(len);
        }
    }

4.读取字节数组的问题
我们依旧在对应的.txt文件中存入abc三个字符

public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("day15\\a.txt");

        byte[] b = new byte[2];
        
        int len = 0;
        while ((len =fis.read(b)) != -1){
            System.out.println(new String(b));
        }

    }

结果
打印结果不尽人意,为什么会出现这个问题呢。
图解
5.循环读取字节数组正确姿势

public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("day15\\a.txt");

        byte[] b = new byte[2];

        int len = 0;
        while ((len =fis.read(b)) != -1){
            System.out.println(new String(b,0,len));
        }

        fis.close();
    }

二.字符流

    当使用字节流读取文本文件时,可能会有一个小问题。就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储。所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。

字节流读取中文问题演示在a.txt文件中存入字符串"张三")

public static void main(String[] args) throws Exception{
        FileInputStream fis = new FileInputStream("day16\\a.txt");

        byte[] b = new byte[2];
        int len = 0;

        while ((len = fis.read(b)) != -1){
            System.out.println(new String(b,0,len));
        }
    }

运行结果
结果
出现乱码的原因
    idea使用的编码格式是utf-8,一个中文占三个字节。使用一次读取一个字节数组的方法,一次只读了两个字节,两个字节构不成一个汉字,所以出现乱码。

字符输入流

使用起来与字节流差别不大无非就是把byte数组改为char数组了
1.构造:
创建对象,指定要操作的文件路径

  • FileReader(File file)
  • FileReader(String fileName)

2.方法:

  • int read()->第一读取一个字符,返回值int
  • int read(char[] cbuf)->一次读取一个字符数组
  • int read(char[] cbuf, int off, int len)->一次读取一个字符数组一部分
                cbuf:要读取的字符数组
                off:从字符数组的哪个索引开始读取
                len:读多少个
  • void close()->关流

完美解决乱码问题:因为这个是每次读取一个字符!

public static void main(String[] args) throws Exception{
        FileReader fr = new FileReader("day16\\a.txt");

        char[] c = new char[2];
        int len = 0;

        while ((len = fr.read(c)) != -1){
            System.out.println(new String(c,0,len));
        }
    }

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

字符输出流

字符输出流自带一个缓冲区
因为是抽象类所以我们直接操作他的子类FileWriter
1.构造
参数指定我们数据写到哪个位置
我们自定义的文件即使没有,自动创建,如果已经存在,在创建,会把先创建的文件覆盖掉。

  • FileWriter(File file)
  • FileWriter(String name)

3.方法

  • void write(int c)->一次写一个字符
  • void write(char[] c)->一次写一个字符数组
  • void write(char[] c, int off, int len)->一次写一个字符数组一部分
                char[] c:要写哪个字符数组中的内容
                off:从数组的哪个索引开始写
                len:写多少个
  • void write(String str)->一次写一个字符串

    因为内置缓冲区的原因,如果不关闭输出流,无法写出字符到文件中。
    如果关闭流对象,是无法继续写出数据的。如果我们既想写出数据,又想继续使用流,就需要flush 方法。

  • void flush()->刷新缓冲区。如果不刷新缓冲区
  • void close()->刷新缓冲区,并关闭流对象

4.FileWriter的续写功能

  • FileWriter(String name,boolean append)
    append:默认false(不追加内容)
                        true(追加内容)

三.io异常处理

    平常练习,我们一直把异常抛出,而实际开发中并不能这样处理,建议使用 try…catch…finally 代
码块,处理异常部分,代码使用演示:

public static void main(String[] args) {
        FileWriter fw = null;
        try {
            fw  = new FileWriter("day16\\a.txt");
            fw.write("李四");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(fw != null){
                    fw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    还可以使用JDK7优化后的 try-with-resource 语句,该语句确保了每个资源在语句结束时关闭。所谓的资源(resource)是指在程序完成后,必须关闭的对象。

public static void main(String[] args) {
        try (FileWriter fw = new FileWriter("day16\\a.txt");){
            fw.write("张三");
        }catch (IOException e){
            e.printStackTrace();
        }
   }

Properties属性集

特点

  • 数据结构是哈希表,无序
  • 线程安全
  • 不允许出现null值,null键
  • new对象的时候不用指定泛型,作为双列集合,key和value类型都是String
  • 可以和IO流结合使用,从流中将数据加载到集合中

构造方法

  • public Properties() :创建一个空的属性列表

基本的存储方法

  • public Object setProperty(String key, String value) : 保存一对属性。
  • public String getProperty(String key) :使用此属性列表中指定的键搜索属性值。
  • public Set< String > stringPropertyNames() :把所有键存到set集合中。

与流相关的方法

  • void load(输入流对象)

演示

por.Properties文件内容
在这里插入图片描述

public static void main(String[] args)throws Exception {
        //创建Properties集合
        Properties properties = new Properties();

        //创建字节输入流
        FileInputStream fis = new FileInputStream("day16\\pro.properties");

        //调用load方法,加载流中的信息,将信息加载到Properties集合中

        properties.load(fis);

        System.out.println(properties);

        System.out.println("========根据key获取value=========");

        String username = properties.getProperty("username");
        String password = properties.getProperty("password");
        System.out.println(username+"="+password);

    }

ResourceBundle工具类

java.util.ResourceBundle:工具类
    作用:
        可以简化使用Properties集合中load方法读取文件

        ResourceBundle它是一个抽象类,无法直接创建对象,我们可以使用静态方法获取ResourceBundle的子类对象
        static ResourceBundle getBundle(String baseName)
        参数:String baseName:传递以.properties文件的名称 prop.properties==>prop

    注意:.properties文件必须放在当前模块的src下边

一.ResourceBundle对象的创建

public class Demo01ResourceBundle {
    public static void main(String[] args) {
        //getBundle方法返回的是ResourceBundle的子类对象  
        //ResourceBundle(父类) 变量 = PropertyResourceBundle(子类对象)
        //多态
        ResourceBundle prop = ResourceBundle.getBundle("pro");
        System.out.println(prop);//java.util.PropertyResourceBundle@74a14482
    }
}

二.ResourceBundle类的getString方法

    ResourceBundle类中提供了一个方法getString,用于读取配置文件
        String getString(String key)  根据key读取配置文件中的value值
    注意:
    	文件一定要在src目录下
        使用ResourceBundle读取配置文件的时候,key不能是中文,不支持,会抛出异常
        使用ResourceBundle读取配置文件的时候,value可以使用中文,但是读取出来会出现乱码
public class Demo02ResourceBundle {
    public static void main(String[] args) {
        //获取ResourceBundle对象
        ResourceBundle bundle = ResourceBundle.getBundle("pro");
        //使用ResourceBundle对象中的方法getString,根据key获取value值
        String v1 = bundle.getString("tangyan");
        System.out.println("v1:"+v1);
        System.out.println("----------------------------------");
        ResourceBundle bundle2 = ResourceBundle.getBundle("data");
        String username = bundle2.getString("username");
        System.out.println(username);
        String password = bundle2.getString("password");
        System.out.println(password);
    }
}

缓冲流

字节缓冲流

BufferedOutputStream exends OutputStream:字节缓冲输出流->提高写的效率
BufferedInputStream exends InputStream:字节缓冲输入流->提高读的效率

1.构造:

  • public BufferedInputStream(InputStream in) :创建一个 新的缓冲输入流。
  • public BufferedOutputStream(OutputStream out) : 创建一个新的缓冲输出流。

2.方法:
     和字节流方法一毛一样

字符缓冲流

BufferedWriter extends Writer:字符缓冲输出流->提高写的效率

1.构造:

  • BufferedWriter(Writer out)->由于Writer是抽象类,使用要使用它的子类(FileWriter)

2.特有方法:

  • void newLine()->BufferedWriter中特有方法,换行

BufferedReader extends Reader->提高读的效率

1.构造:

  • BufferedReader(Reader r)->Reader是抽象类,不能直接new对象,需要传递Reader的子类(FileReader)

2.特有方法:

  • String readLine() ->一次读取一行

转换流

    当我们使用字符输入流对本地上的文件进行读取的时候,可能会出现乱码的问题,那是因为:在Idea中的编码是utf-8(一个中文占3个字节)但是Windows系统默认编码是GBK(一个中文占两个字节)编码。那么这个问题我们就可以使用转换流来解决!

InputStreamReader extends Reader:转换流->读数据

1.概述:

  • InputStreamReader 是字节流通向字符流的桥梁:
                它使用指定的 charset 读取字节并将其解码为字符

2.构造方法:

  • InputStreamReader(InputStream in, String charsetName)
                 in:传递的是字节输入流对象->InputStream的子类
                charseName:指定什么编码去读数据->不区分大小写
                如果不指定编码,默认UTF-8

OutputStreamWriter extends Writer:转换流->写数据

1.概述:

  • OutputStreamWriter 是字符流通向字节流的桥梁:
                可使用指定的 charset 将要写入流中的字符编码成字节

2.构造方法:

  • OutputStreamWriter(OutputStream out, String charsetName)
                out:OutputStream是抽象类,所以我们用子类
                charseName:指定以什么编码的方式去写数据
        指定什么编码写数据,造出来的文件就是什么编码的内容也就是什么编码的
    不指定编码,默认是UTF-8

序列化流

    序列化:对象需要实现Serializable接口

1.序列化流_ObjectOutputStream

构造
    ObjectOutputStream(OutputStream out)

写对象的方法:
    writeObject(对象)

2.反序列化_ObjectInputStream

构造:
    ObjectInputStream(InputStream in)

方法:
     readObject()->读对象

3.如果不想被反序列化的操作
     1.将成员变量其变成:static
     2.瞬态关键字:transient(常用)

4.反序列化时出现的问题以及分析以及解决
序列化数据后,再次修改类文件,读取数据会出问题,如何解决呢?

答:在实体类中加上:public static final long serialVersionUID = 42L;


Commons-io工具包

一.介绍

    IO技术开发中,代码量很大,而且代码的重复率较高。如果我们要遍历目录,拷贝目录就需要使用方法的递归调用,也增大了程序的复杂度。
Apache软件基金会,开发了IO技术的工具类commonsIO,大大简化IO开发。

二.添加第三方jar包

    Apahce软件基金会属于第三方,(Oracle公司第一方,我们自己第二方,其他都是第三方)我们要使用第三方开发好的工具,需要添加jar包。
jar包:就是Java自己的压缩包,包中是开发好的功能,全部以class文件形态出现,我们添加直接使用即可。

引入jar包:
    1.在module下创建文件夹lib
    2.将jar包文件复制到lib下面
    3.lib文件夹右键.选择add as library
    4.level选项,选择module

三.工具包的使用

IOUtils类

  • 静态方法:IOUtils.copy(InputStream in,OutputStream out)传递字节流,实现文件复制。
  • 静态方法:IOUtils.closeQuietly(任意流对象)悄悄的释放资源,自动处理close()方法抛出的异常。
public class CommonsIO01 {
    public static void main(String[] args)throws Exception {
        //复制
        IOUtils.copy(new FileInputStream("G:\\idea\\io\\image\\2.jpg"),
                new FileOutputStream("G:\\idea\\io\\image\\bb\\julisha.jpg"));
    }
}

FileUtils类

  • 静态方法:FileUtils.copyDirectoryToDirectory(File src,File dest);
                      传递File类型的目录,进行整个目录的复制,自动进行递归遍历。
  • 静态方法:writeStringToFile(File file,String str)写字符串到文本文件中。
  • 静态方法:readFileToString(File file)读取文本文件,返回字符串。
public class CommonsIO02 {
    public static void main(String[] args)throws Exception {
       //复制文件夹
       // FileUtils.copyDirectoryToDirectory(new File("G:\\idea\\io\\image"),new File("G:\\idea"));
       //写数据
       // FileUtils.writeStringToFile(new File("day16\\fileutils.txt"),"涛哥");
        //读数据
        String s = FileUtils.readFileToString(new File("day16\\fileutils.txt"));
        System.out.println(s);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章