Java-IO流

Java-IO流

  • IO流体系框架
  • IO流体系分类
  • 为什么要有IO流?
  • IO流初涉:文件
    • 输入流与输出流
    • 如何打开文件
    • File类的相关功能
      • 创建对象文件
      • File类的相关功能
    • FileReader的操作
    • FileWrite的操作
    • 通过字节流实现图片的拷贝
    • 使用处理流对文本操作
    • 使用对象流实现序列化和反序列化
      • 作用:
      • 序列化机制:
      • 序列化和反序列化的注意事项和细节说明
    • RandomAccessFile的使用

IO流体系框架

Java-IO流_第1张图片

IO流体系分类

分类 字节输入流 字节输出流 字符输入流 字符输出流
以下是节点流,一般用于文本文件
抽象基类 InputStream OutputStream Reader Writer
访问文件 FileInputStream FileOutputStream FileReader FileWriter
访问数组 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter
访问管道 PipedInputStream PipedOutputStream PipedReader PipedWriter
访问字符串 StringReader StringWriter
以下是处理流,一般用于非文本文件
缓冲流 BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter
转换流 InputStreamReader OutputStreamWriter
对象流 ObjectInputStream ObjectOutputStream
抽象基类 FilterInputStream FilterOutputStream FilterReader FilterWriter
打印流 PrintStream PrintWriter
推回输入流 PushbackInputStream PushbackReader
特殊流 DataInputStream DataOutputStream

为什么要有IO流?

  • 因为我们在编程过程中对文件进行操作,而Java中对文件的读写都是以流的形式来实现,也就是所谓的IO流。
  • 又因为文件分文字节文件和字符文件,所以出现了字节流和字符流。之后针对不同的文件类型又出现了很多拥有特定功能的IO流子类。

IO流初涉:文件

输入流与输出流

  • 输入流:数据从数据源(文件)到程序(内存)的路径
  • 输出流:数据从程序(内存)到数据源(文件)的路径

如何打开文件

  • 通过创建File类的实例来创建文件。File(String path),其中path可以使相对路径,也可以是绝对路径。
  • File file=new File("Hello.txt") 通过相对路径打开一个叫Hello.txt的文件

File类的相关功能

创建对象文件

  • new File(String pathname) // 根据路径构建一个File对象
  • new File(File parent,String child) //根据父目录文件+子路径构建
  • new File(String parent,String child) //根据父目录+子路径构建

上面三种方式产生的对象都没有在磁盘真正创建文件,最后需要 对象名.createNewFile()才会真正创建

File类的相关功能

File类的相关功能
获取功能 返回值 参数 说明
getAbsolutePath() String 获取绝对路径
getPath() String 获取路径
getName() String 获取名称
getParent() String 获取上一层文件目录路径,不存在返回null
length() long 获取文件长度(字节数)
lastModified() long 获取最后一次修改时间,毫秒级
list() String[] 获取指定目录下的所有文件或者文件目录的名称数组
listFiles() File[] 获取指定目录下的所有文件或者文件目录的File数组
重命名功能 返回值 参数 说明
renameTo() boolean File dest 把文件重命名为指定的文件路径
判断功能 返回值 参数 说明
isDirectory() boolean 判断是否是文件目录
isFile() boolean 判断是否是文件
exists boolean 判断是否存在
canRead() boolean 判断是否可读
canWrite() boolean 判断是否可写
isHidden() boolean 判断是否隐藏
创建功能 返回值 参数 说明
createNewFile() boolean 创建文件。若文件存在就不创建并返回false
mkdirs() boolean 创建文件目录。如果上层文件目录不存在,一并创建
删除功能 返回值 参数 说明
delete() boolean 删除文件或者文件夹(注意:不会进回收站)

FileReader的操作

//创建
		FileReader fr = new FileReader("file.txt");//文件file.txt必须存在,不然会抛出异常
		//返回值为读取到的单个字符,对应的ASCII或者Unicod
		ch = fr.read();
		System.out.println(ch);  //-1代表没有更多字符可以读取
		fr.close();

FileWrite的操作

//指明写入到的文件
       File file=new File("helloI.txt");//文件可以不存在,不存在会创建
        try {
            //提供FileWriter类的对象,用于数据写出
            FileWriter fw=new FileWriter(file);
            //写出数据
            fw.write("hello IDEA");
            //关闭流资源
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

通过字节流实现图片的拷贝

 //源图片
 File srcFile=new File("ganyu.jpg");
 //目标图片
 File desFile=new File("ganyu1.jpg");

 //造节点流
 //造输入节点流
 FileInputStream fis=new FileInputStream(srcFile);
 //造输出节点流
 FileOutputStream fos=new FileOutputStream(desFile);
 //造缓冲流,它是处理流,是对节点流的包装
 //造输入缓冲流
 BufferedInputStream bis=new BufferedInputStream(fis);
 //造输出缓冲流
 BufferedOutputStream bos=new BufferedOutputStream(fos);
 //拷贝的细节
 byte ch[]=new byte[100];
 int len;
 while ((len =bis.read(ch))!=-1){
     bos.write(ch,0,len);
 }
 //关闭流(从内往外关闭)
 bos.close();
 bis.close();
 fos.close();
 fis.close();

使用处理流对文本操作

//方式一:使用数组
File srcFile=new File("hello.txt");
File desFile=new File("hello1.txt");
FileReader fr=new FileReader(srcFile);
FileWriter fw=new FileWriter(desFile);
BufferedReader br=new BufferedReader(fr);
BufferedWriter bw=new BufferedWriter(fw);
//实现的细节
char ch[]=new char[1024];
int len;
String data;
while ((len =br.read(ch))!=-1){
    bw.write(ch,0,len);
//            bos.flush();
}
//关闭流(从内往外关闭)
br.close();
bw.close();
fr.close();
fw.close();
//方式二:使用String
File srcFile=new File("hello.txt");
File desFile=new File("hello1.txt");
FileReader fr=new FileReader(srcFile);
FileWriter fw=new FileWriter(desFile);
BufferedReader br=new BufferedReader(fr);
BufferedWriter bw=new BufferedWriter(fw);
//实现的细节
char ch[]=new char[1024];
int len;
String data;
while ((data=br.readLine())!=null){
    bw.write(data);
}
//关闭流(从内往外关闭)
br.close();
bw.close();
fr.close();
fw.close();

使用对象流实现序列化和反序列化

  1. 序列化就是在保存数据时,保存数据的值和数据类型
  2. 反序列化就是在恢复数据时,,恢复数据的值和数据类型
  3. 需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一:
       Serializable //这是一个标记接口,没有方法
       Externalizable//该接口有方法需要实现,因此我们一般实现上面的Serializable接口

序列化和反序列化就是 对象流(ObjectInputStream 和 ObjectOutputStream)的使用

作用:

用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。

序列化机制:

  • 对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。

序列化和反序列化的注意事项和细节说明

  1. 读写顺序要一致
  2. 要求序列化或反序列化对象,需要实现Serializable
  3. 序列化的类中建议添加SerialVersionUID,为了提高版本的兼容性
  4. 序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员
  5. 序列化对象时,要求里面属性的类型也需要实现序列化接口
  6. 序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化
public class Person implements Serializable{//必须要实现Serializable接口

   public static final long serialVersionUID = 475463534532L;

   private String name;
   private int age;
   private int id;
   public Person(String name, int age, int id) {
       this.name = name;
       this.age = age;
       this.id = id;
   }
   public Person(String name, int age, int id) {
       this.name = name;
       this.age = age;
       this.id = id;
   }
   @Override
   public String toString() {
       return "Person{" +
               "name='" + name + '\'' +
               ", age=" + age +
               ", id=" + id +
               '}';
   }
   public int getId() {
       return id;
   }
   public void setId(int id) {
       this.id = id;
   }
   public String getName() {
       return name;
   }
   public void setName(String name) {
       this.name = name;
   }
   public int getAge() {
       return age;
   }
   public void setAge(int age) {
       this.age = age;
   }
   public Person(String name, int age) {
       this.name = name;
       this.age = age;
   }
   public Person() {
   }
}

//序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去,使用ObjectOutputStream实现
public void testObjectOutputStream(){
    ObjectOutputStream oos = null;
    try {
        oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
        oos.writeObject(new String("我爱北京天安门"));
        oos.flush();//刷新操作
        oos.writeObject(new Person("王铭",23));
        oos.flush();
        oos.writeObject(new Person("张学良",23,1001));
        oos.flush();
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(oos != null){
            //3.
            try {
                oos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

//反序列化:将磁盘文件中的对象还原为内存中的一个java对象使用ObjectInputStream来实现
public void testObjectInputStream(){
    ObjectInputStream ois = null;
    try {
        ois = new ObjectInputStream(new FileInputStream("object.dat"));
        Object obj = ois.readObject();
        String str = (String) obj;
        Person p = (Person) ois.readObject();
        Person p1 = (Person) ois.readObject();
        System.out.println(str);
        System.out.println(p);
        System.out.println(p1);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        if(ois != null){
            try {
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

RandomAccessFile的使用

  1. RandomAccessFile直接继承于java.lang.Object类,实现了DataInput和DataOutput接口
  2. RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
  3. 如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。
    如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)
  4. 可以通过相关的操作,实现RandomAccessFile“插入”数据的效果
//既可以作为一个输入流,又可以作为一个输出流的代码实现
RandomAccessFile raf1 = null;
RandomAccessFile raf2 = null;
try {
    //1.
    raf1 = new RandomAccessFile(new File("爱情与友情.jpg"),"r");
    raf2 = new RandomAccessFile(new File("爱情与友情1.jpg"),"rw");
    //2.
    byte[] buffer = new byte[1024];
    int len;
    while((len = raf1.read(buffer)) != -1){
        raf2.write(buffer,0,len);
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    //3.
    if(raf1 != null){
        try {
            raf1.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    if(raf2 != null){
        try {
            raf2.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
//实现RandomAccessFile“插入”数据的效果
RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");
raf1.seek(3);//将指针调到角标为3的位置
//保存指针3后面的所有数据到StringBuilder中
StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
byte[] buffer = new byte[20];
int len;
while((len = raf1.read(buffer)) != -1){
    builder.append(new String(buffer,0,len)) ;
}
//调回指针,写入“xyz”
raf1.seek(3);
raf1.write("xyz".getBytes());
//将StringBuilder中的数据写入到文件中
raf1.write(builder.toString().getBytes());
raf1.close();

你可能感兴趣的:(java,java,流处理)