java之IO遍

File类

File类可以用来新建、删除、重命名文件和目录,但它不能访问文件内容本身,访问文件内容需要使用输入输出流

访问文件名相关的方法

  • String getName():返回File对象所表示的文件名或路径名
  • String getPath():返回File对象所对应的路径名
  • String getAbsolutePath():返回次Fille对象所对应的绝对路径
  • boolean renameTo(File newName):重命名此File对象所对应的文件或目录,重命名成功返回true

文件检测相关的方法

  • boolean exists():判断File对象对应的文件或目录是否存在
  • boolean canWrite(): 判断File对象对应的文件或目录是否可写
  • boolean canRead():判断File对象对应的文件或目录是否可读
  • boolean isFile():判断File对象对应的是否为文件
  • boolean isDirectory():判断File对象对应的是否为目录

文件操作相关方法

  • long length():返回文件内容长度
  • boolean createNewFile():当此File对象所对应的文件不存在时,该方法将新建一个该File对象所指定的新文件,创建成功返回true
  • boolean delete():删除File对应的文件

目录操作相关的方法

  • boolean mkdir():创建一个File对象所对应的目录
  • String[] list():列出File对象的所以子文件名和路径名
  • File[] listFiles():列出File对象的所有子文件
  • getParentFile():得到文件的父级目录

文件过滤器

File类的list方法了一返回File对象的所有子文件名,该方法中可以接收一个FilenameFilter参数,通过该参数可以只列出符合条件的文件

public static void main(String[] args) {
		--------以当前路径来创建一个file对象
        File file = new File(".");
        --------如果文件名以.java结尾或文件对应一个路径,则返回true
        file.list((dir,name)-> name.endsWith(".java") || new File(name).isDirectory());
        System.out.println(file);
   }

字节流和字符流

在这里插入图片描述

InputStream和Reader是所有输入流的抽象基类,本身不能创建实例来执行输入,但可以使用FileInputStream和FileReader来读取文件

public static void main(String[] args) {
        try {
            //准备文件lol.txt其中的内容是AB,对应的ASCII分别是65 66
            File f =new File("d:/lol.txt");
            //创建基于文件的输入流
            FileInputStream fis =new FileInputStream(f);
            //创建字节数组,其长度就是文件的长度
            byte[] all =new byte[(int) f.length()];
            //以字节流的形式读取文件所有内容
            fis.read(all);
            for (byte b : all) {
                //打印出来是65 66
                System.out.println(b);
            }
             
            //每次使用完流,都应该进行关闭
            fis.close();
              
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
          
    }

OutputStream和Writer是所有输出流的抽象基类,本身不能创建实例来执行输出,但可以使用FileOutputStream和FileWriter来读取文件,如果用来输出字符串内容使用FileWriter会更好些

处理流的用法

使用处理流的优势:输入输出更简单;执行效率更高

使用PrintStream来包装OutputStream

FileOutputStream fileOutputStream = new FileOutputStream("F://tcp.txt");
 PrintStream printStream = new PrintStream(fileOutputStream);

字符流

FileReader:用来读取访问文件
FileWriter:用来写入文件

StringReader:用字符流来读取字符串,该对象传入的是字符串节点
StringWriter:用字符流来写入字符串,该对象实际上是以一个StringBuffer作为输出节点,字符串的长度是可变的

StringWriter stringWriter = new StringWriter();

stringWriter.write("你好");

转换流

InputStreamReader:将字节输入流转换成字符输入流

 InputStreamReader inputStreamReader = new InputStreamReader(System.in);

OutputStringWriter:将字节输出流转换成字符输出流

BufferedReader: 用来将Reader再次包装变成BufferedReader ,可以利用 bufferedReader.readLine()来读取一行,BufferedReader 具有缓冲功能,它一次读取一行文本,以换行符为标志,如果没有读取到换行符,则程序阻塞,等待读取到换行符为止,这也是在控制台只有按下回车才会打印出内容的原因

BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
 bufferedReader.readLine();

关闭流的方法

所有的流,无论是输入流还是输出流,使用完毕之后,都应该关闭。 如果不关闭,会产生对资源占用的浪费。 当量比较大的时候,会影响到业务的正常开展。

在try的作用域里关闭文件流

在try的作用域里关闭文件输入流,在前面的示例中都是使用这种方式,这样做有一个弊端;
如果文件不存在,或者读取的时候出现问题而抛出异常,那么就不会执行这一行关闭流的代码,存在巨大的资源占用隐患。 不推荐使用

在finally中关闭

这是标准的关闭流的方式
1. 首先把流的引用声明在try的外面,如果声明在try里面,其作用域无法抵达finally.
2. 在finally关闭之前,要先判断该引用是否为空
3. 关闭的时候,需要再一次进行try catch处理

这是标准的严谨的关闭流的方式,但是看上去很繁琐,所以写不重要的或者测试代码的时候,都会采用上面的有隐患try的方式,因为不麻烦~

public static void main(String[] args) {
        File f = new File("d:/lol.txt");
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(f);
            byte[] all = new byte[(int) f.length()];
            fis.read(all);
            for (byte b : all) {
                System.out.println(b);
            }
 
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 在finally 里关闭流
            if (null != fis)
                try {
 
                    fis.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
        }
 
    }

字符编码问题

FileReader得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了
而FileReader使用的编码方式是Charset.defaultCharset()的返回值,如果是中文的操作系统,就是GBK
FileReader是不能手动设置编码方式的,为了使用其他的编码方式,只能使用InputStreamReader来代替,像这样:

new InputStreamReader(new FileInputStream(f),Charset.forName(“UTF-8”));

public class TestStream {
 -----为什么中字前面有一个?
 	 如果是使用记事本另存为UTF-8的格式,那么在第一个字节有一个标示符,
 	 叫做BOM用来标志这个文件是用UTF-8来编码的
    public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {
        File f = new File("E:\\project\\j2se\\src\\test.txt");
        System.out.println("默认编码方式:"+Charset.defaultCharset());
        //FileReader得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了
        //而FileReader使用的编码方式是Charset.defaultCharset()的返回值,如果是中文的操作系统,就是GBK
        try (FileReader fr = new FileReader(f)) {
            char[] cs = new char[(int) f.length()];
            fr.read(cs);
            System.out.printf("FileReader会使用默认的编码方式%s,识别出来的字符是:%n",Charset.defaultCharset());
            System.out.println(new String(cs));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //FileReader是不能手动设置编码方式的,为了使用其他的编码方式,只能使用InputStreamReader来代替
        //并且使用new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8")); 这样的形式
        try (InputStreamReader isr = new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8"))) {
            char[] cs = new char[(int) f.length()];
            isr.read(cs);
            System.out.printf("InputStreamReader 指定编码方式UTF-8,识别出来的字符是:%n");
            System.out.println(new String(cs));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
         
    }
}

在这里插入图片描述

序列化

序列化机制允许将实现序列化的java对象转换成字节序列,也可使用反序列化将从二进制流中恢复Java对象;一个对象以流的形式进行传输,叫做序列化。 该对象所对应的类,必须是实现Serializable接口;web应用中需要保存到HttpSession或ServletContext属性的java对象都应该实现序列化

使用对象流实现序列化

ObjectOutputStream,是一个处理流,必须建立在其它节点流之上,使用ObjectOutputStream对象的writeObject可以将一个对象写入输出流```

public class ScannerSerizable implements Serializable {
    String name;
    int age;
    public ScannerSerizable(String name,int age)
    {
        this.name=name;
        this.age=age;
    }
}
  public static void main(String[] args) throws IOException {
        
        FileOutputStream fileOutputStream = new FileOutputStream(new File("F://java.txt"));
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        ScannerSerizable person = new ScannerSerizable("张三",20);
        objectOutputStream.writeObject(person);

    }

使用 ObjectInputStream进行反序列化

FileInputStream fileInputStream = new FileInputStream("F://java.txt");
 ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream );
 ScannerSerizable person2 =(ScannerSerizable) objectInputStream.readObject();

使用引用的序列化

如果某个类的成员变量的类型不是基本类型而是引用类型,那么这个引用类型必须也是可序列化的,否则拥有该引用类型的类也不可序列化,如下面代码,如果student对象的类没有可序列化,不管ScannerSerizable 有没有实现Serializable接口,ScannerSerizable 都是不可序列化的

public class ScannerSerizable implements Serializable
 {
    String name;
    int age;
    private ScannerSerizable student;
    }

练习:准备一个长度是10,类型是Hero的数组,使用10个Hero对象初始化该数组
然后把该数组序列化到一个文件heros.lol
接着使用ObjectInputStream 读取该文件,并转换为Hero数组,验证该数组中的内容,是否和序列化之前一样

 public static void main(String[] args) throws IOException, ClassNotFoundException
    {

        ScannerSerizable scannerSerizable1 = new ScannerSerizable("张1",20);
        ScannerSerizable scannerSerizable2 = new ScannerSerizable("张2",20);
        ScannerSerizable scannerSerizable3 = new ScannerSerizable("张3",20);
        ScannerSerizable scannerSerizable4 = new ScannerSerizable("张4",20);
        ScannerSerizable scannerSerizable5 = new ScannerSerizable("张5",20);
        ScannerSerizable scannerSerizable6 = new ScannerSerizable("张6",20);
        ScannerSerizable scannerSerizable7 = new ScannerSerizable("张7",20);
        ScannerSerizable scannerSerizable8 = new ScannerSerizable("张8",20);
        ScannerSerizable scannerSerizable9 = new ScannerSerizable("张9",20);
        ScannerSerizable scannerSerizable10 = new ScannerSerizable("张10",20);

        ScannerSerizable[] scannerSerizables = new ScannerSerizable[10];

        scannerSerizables[0] = scannerSerizable1;
        scannerSerizables[1] = scannerSerizable2;
        scannerSerizables[2] = scannerSerizable3;
        scannerSerizables[3] = scannerSerizable4;
        scannerSerizables[4] = scannerSerizable5;
        scannerSerizables[5] = scannerSerizable6;
        scannerSerizables[6] = scannerSerizable7;
        scannerSerizables[7] = scannerSerizable8;
        scannerSerizables[8] = scannerSerizable9;
        scannerSerizables[9] = scannerSerizable10;

        FileOutputStream fileOutputStream = new FileOutputStream("F://heros.lol");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        for(int i =0;i<10;i++)
        {
            objectOutputStream.writeObject(scannerSerizables[i]);
        }

        FileInputStream fileInputStream = new FileInputStream("F://heros.lol");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        for(int i =0;i<10;i++)
        {
            ScannerSerizable scannerSerizable = (ScannerSerizable) objectInputStream.readObject();
            System.out.println("姓名:"+scannerSerizable.getName()+";age:"+scannerSerizable.getAge());
        }

    }

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值