文件和IO流

一、File类

在认识io流之前需要先认识FIle类,因为file类用来表示文件或文件夹的。

通过File类能对文件或文件夹进行新建、删除、重命名操作

1.1)File类的常用构造器

public File(String pathname):
以pathname为路径创建File对象,可以是绝对路径或者相对路径

public File(String parent,String child)
以parent为父路径,child为子路径创建File对象。

public File(File parent,String child)
根据一个父File对象和子文件路径创建File对象

1.2) File类的创建功能

public boolean createNewFile()
创建文件。若文件存在,则不创建,返回false

public boolean mkdir() :
创建文件目录。如果此文件目录存在,就不创建了。
如果此文件目录的上层目录不存在,也不创建。

public boolean mkdirs() :
创建文件目录。如果上层文件目录不存在,一并创建

而IO流则是对文件或文件夹进行读写操作的。

1.3)File类的删除功能

public boolean delete():
删除文件或者文件夹

1.4)File类的获取功能

 public String getAbsolutePath():获取绝对路径
 public String getPath() :获取路径
 public String getName() :获取名称
 public String getParent():获取上层文件目录路径。若无,返回null
 public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
 public long lastModified() :获取最后一次的修改时间,毫秒值
 public String[] list() :获取指定目录下的所有文件或者文件目录的名称数组
 public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组

1.5)File类的判断功能

 public boolean isDirectory():判断是否是文件目录
 public boolean isFile() :判断是否是文件
 public boolean exists() :判断是否存在
 public boolean canRead() :判断是否可读
 public boolean canWrite() :判断是否可写
 public boolean isHidden() :判断是否隐藏

二、IO流

2.1)流的分类

根据流向分:
输入流和输出流
在这里插入图片描述

根据数据单位分:
字节流和字符流

一个字符等于两个字节

根据角色分:
节点流和处理流

如果操作的对象是文件,则该流是节点流;
如果操作的对象是流,则该流是处理流

2.2)流的体系结构

抽象基类

InputStream
OutputStream
Reader
Writer

节点流:

FileInputStream
FileOuptStream
FileReader
FileWriter

缓存流:

BufferedInputStream
BufferedOutputStream
BufferedReader
BufferedWriter

2.3)字符流

FileReader

字符输入流

从文件中的数据写入到
可以通过以下两种方式读取,两种方式都是读取到最后一个字符为-1时,则到达文件末尾

每次读取一个字符
 while ((read=fileReader.read()) != -1) {
   System.out.print((char) read);
 }
@Test
public void test1() {
     File file = new File("src/file/hello.txt");
     FileReader fileReader = null;
     try {
         fileReader = new FileReader(file);
         System.out.println(file.getAbsolutePath());
         int read;
         while ((read=fileReader.read()) != -1) {
             System.out.print((char) read);
         }
     } catch (IOException e) {
         e.printStackTrace();
     } finally {
         try {
             fileReader.close();
         } catch (IOException e) {
             e.printStackTrace();
         }
     }
 }
每次读取一个数组
 char[] chars=new char[5];
 int len;
 while ((len=fileReader.read(chars))!=-1){
     for (int i=0;i<len;i++){
         System.out.print(chars[i]);
     }
     System.out.println();
 }
@Test
public void test2(){
    File File2=new File("src/file/hello.txt");
    FileReader fileReader = null;
    try {
        fileReader=new FileReader(File2);
        char[] chars=new char[5];
        int len;
        while ((len=fileReader.read(chars))!=-1){
            for (int i=0;i<len;i++){
                System.out.print(chars[i]);
            }
            System.out.println();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        try {
            if (fileReader!=null){
                fileReader.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

FileWriter

字符输出流
将字符从内存中写到文件(硬盘)

1、如果文件不存在,则进行创建
2、如果文件存在:

使用FIleWriter(file,true),则将字符追加到文件中
使用FileWriter(file,false)或FileWriter(file),则写入的内容覆盖原有的内容

 fileWriter=new FileWriter(file2,true);
 char[] chars=new char[10];
 int len;
 while ((len=fileReader.read(chars))!=-1){
    fileWriter.write(chars);
 }

2.4) 字节流

FileInputStream

字节输入流,可以将字节数据读取到内存中

使用该流可以读取图片,视频,音频等

File file1=new File("E:\\temp\\aof1.png");
fileInputStream=new FileInputStream(file1);
 byte[] bytes=new byte[10];
 int len;
 while ((len=fileInputStream.read(bytes))!=-1){
     System.out.println(new String(bytes,0,len));
 }

int read()
从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因
为已经到达流末尾而没有可用的字节,则返回值 -1。

int read(byte[] b)
从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。如果因为已
经到达流末尾而没有可用的字节,则返回值 -1。否则以整数形式返回实际读取
的字节数。

int read(byte[] b, int off,int len)
将输入流中最多 len 个数据字节读入 byte 数组。尝试读取 len 个字节,但读取
的字节也可能小于该值。以整数形式返回实际读取的字节数。如果因为流位于
文件末尾而没有可用的字节,则返回值 -1。

FileOutputStream

File write=new File("src/file/hello.gif");
FileOutputStream fileOutputStream=new FileOutputStream(write,true);
byte[] bytes=new byte[10];
int len;
 while ((len=fileInputStream.read(bytes))!=-1){
     //System.out.println(new String(bytes,0,len));
     fileOutputStream.write(bytes);
 }

public void flush()throws IOException:

刷新此输出流并强制写出所有缓冲的输出字节,调用此方法指示应将这些字节立
即写入它们预期的目标。

void write(int b)
将指定的字节写入此输出流。write 的常规协定是:向输出流写入一个字节。要写
入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。 即写入0~255范围的。

void write(byte[] b)
将 b.length 个字节从指定的 byte 数组写入此输出流。write(b) 的常规协定是:应该
与调用 write(b, 0, b.length) 的效果完全相同。

void write(byte[] b,int off,int len)
将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流

2.5)缓冲流

缓冲流要“套接”在相应的节点流之上,根据数据操作单位可以把缓冲流分为:

BufferedInputStream 和 BufferedOutputStream
BufferedReader 和 BufferedWriter

当读取数据时,数据按块读入缓冲区,其后的读操作则直接访问缓冲区

读文件

当使用BufferedInputStream读取字节文件时,BufferedInputStream会一次性从
文件中读取8192个(8Kb),存在缓冲区中,直到缓冲区装满了,才重新从文件中
读取下一个8192个字节数组。

写文件

向流中写入字节时,不会直接写到文件,先写到缓冲区中直到缓冲区写满,
BufferedOutputStream才会把缓冲区中的数据一次性写到文件里。使用方法
flush()可以强制将缓冲区的内容全部写入输出流

关闭流

关闭流的顺序和打开流的顺序相反。只要关闭最外层流即可,关闭最外层流也
会相应关闭内层节点流

举个例子:

FileReader fileReader = null;
FileWriter fileWriter = null;

BufferedReader bufferedReader = null;
BufferedWriter bufferedWriter = null;

fileReader = new FileReader(source);
fileWriter = new FileWriter(target);
bufferedReader = new BufferedReader(fileReader);
bufferedWriter = new BufferedWriter(fileWriter);

String s = null;
while ((s = bufferedReader.readLine()) != null) {
    bufferedWriter.write(s);
}

2.6)转换流(属于字符流)

转换流提供了在字节流和字符流之间的转换

Java API提供了两个转换流:

InputStreamReader:将InputStream转换为Reader
OutputStreamWriter:将Writer转换为OutputStream

在这里插入图片描述

InputStreamReader

将字节输入流转换为字符输入流

OutputStreamWriter

将字节输出流转为字符输出流

编码:将字符转为字节(看得懂的转成看不懂的)
解码:将字节转为字符(看不懂的转成看得懂的)

转换流复制文件

@Test
public void test1() {
   File read = null;
   File write = null;
   FileInputStream fileInputStream = null;
   FileOutputStream fileOutputStream = null;
   OutputStreamWriter outputStreamWriter=null;
   InputStreamReader inputStreamReader=null;
   try {
       read = new File("hell01.txt");
       write = new File("temp.txt");
       fileInputStream = new FileInputStream(read);
       fileOutputStream = new FileOutputStream(write);
       inputStreamReader=new InputStreamReader(fileInputStream,"utf-8");
       outputStreamWriter=new OutputStreamWriter(fileOutputStream,"utf-8");
       char[] chars=new char[10];
       int len = 0;
       while ((len = inputStreamReader.read(chars)) != -1) {
           System.out.println();
           outputStreamWriter.write(String.valueOf(chars));
       }
   } catch (IOException e) {
       e.printStackTrace();
   } finally {
       if (inputStreamReader != null) {
           try {
               inputStreamReader.close();
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
       if (outputStreamWriter != null) {
           try {
               outputStreamWriter.close();
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
   }

}

2.7)对象流

ObjectInputStream和OjbectOutputSteam

用于存储和读取基本数据类型数据或对象的处理流。

序列化:ObjectOutputStrem保存基本数据类型或对象
反序列化:ObjectInputStream读取基本数据类型或对象

注意
ObjectOutputStream和ObjectInputStream不能序列化 static和transient修
饰的成员变量

对象的序列化

特点:

1、可以将基本数据类型或java对象转换成二进制流;
2、任何实现serializeable接口的对象转换成的字节数据都可以在保存和传输时被还原
3、如果要进行网络传输,就必须进行序列化
4、如果要让对象支持序列化就必须实现Serializable或Externalizable接口
5、凡是实现Serializable接口的类 必须 有一个表示序列化标识符的静态变量
private static final long serialVersionUID
6、除了当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性也必须是可序列化的。(默认情况下,基本数据类型可序列化)

为什么凡是实现Serializable接口的类 必须 有一个表示序列化标识符的静态变量?

如果类没有显示定义这个静态常量,它的值是Java运行时环境根据类的内部细节自
动生成的。若类的实例变量做了修改,serialVersionUID 可能发生变化。

举个例子:(为了让代码看起来少一点,这里没有在finally中关闭资源)

演示不加入serialVersionUID

public class Person implements Serializable {
   // public static final long serialVersionUID=1L;

    private String name;
    private String sex;

    public Person(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
}
@Test
public void test1(){
    serializableString(); // 序列化
    unSerializableString(); // 反序列化
}

private void serializableString() {
    try {
        ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream("data.txt"));
        Person person=new Person("张三","男");
        objectOutputStream.writeObject(person);
        objectOutputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private void unSerializableString() {
    try {
        ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream("data.txt"));
        Person person= (Person) objectInputStream.readObject();
        System.out.println(person.toString());
        objectInputStream.close();
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    }
}

在序列化之后没有对类进行更改,发现反序列化之后可以恢复
在这里插入图片描述
如果在·序列化之后,修改了类

public class Person implements Serializable {
   // public static final long serialVersionUID=1L;

    private String name;
    private String sex;
    pricate int age;

    public Person(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
}

执行反序列化操作

 @Test
 public void test1(){
      unSerializableString(); // 反序列化
  }

在这里插入图片描述
这是因为通过serialVersionUID可以识别出是哪一个类,即使改变了也可以反序列化处理,但是 如果没有serialVersionUID,就不知道是哪个类,所有就无法反序列化。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值