Java基础-IO流

一、使用I/O操作文件

1.操作文件或目录属性
File对象既可表示文件,也可表示目录
(1)File类的构造方法
File(String path) 用指定的文件路径构造文件
File(String dir, String subpath)
在指定的目录下创建指定文件名的文件,dir参数指定目录路径,subpath参数指定文件名
File(File parent, String subpath)
根据一个文件对象和一个字文件构造文件对象,parent参数指定目录文件,subpath参数指定文件名

import java.io.File;
import java.io.IOException;

/**
* 操作文件
*/
public class TestFile {

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

        File f1 = new File("G:\\testFile");
        //mkdir() 创建目录(如果路径不存在,则不执行)   mkdirs() 创建目录(如果路径不存在,则创建路径上的目录)
        createDir(f1);

        File f2 = new File("G:\\testFile","a.txt");
        createFile(f2);

        File f3 = new File(f1,"b.txt");
        createFile(f3);

        //判断该文件对象是文件还是目录     文件对象.isDirectory();
        System.out.println(f1.isDirectory() + "," + f2.isDirectory() + "," + f3.isDirectory());  //true,false,false
        //判断该文件对象是文件还是目录     文件对象.isDirectory();
        System.out.println(f1.isFile() + "," + f2.isFile() + "," + f3.isFile());    //false,true,true
        //获取文件或目录的名称            文件对象.getName()
        System.out.println(f1.getName() + "," + f2.getName() + "," + f3.getName());   //testFile,a.txt,b.txt
        //获取文件或目录的绝对路径         文件对象.getAbsolutePath()
        System.out.println(f1.getAbsolutePath() + "," + f2.getAbsolutePath() + "," + f3.getAbsolutePath());  //G:\testFile,G:\testFile\a.txt,G:\testFile\b.txt
        //获取文件或目录的最后修改日期     文件对象.lastModified()
        System.out.println(f1.lastModified() + "," + f2.lastModified() + "," + f3.lastModified());  //1605079154073,1605079154073,1605079154073
        //获取文件或目录的大小,单位为字节 文件对象.length()
        System.out.println(f1.length() + "," + f2.length() + "," + f3.length());  // 0,0,0

        deleteFile(f2);   //删除a.txt文件
        deleteFile(f3);   //删除b.txt文件
        deleteFile(f1);   //删除testFile目录(PS:如果目录中有文件,则不会执行删除操作)
    }

    static void createDir(File file){
        if(!file.exists()){
            file.mkdirs();
        }
    }
    static void createFile(File file) throws IOException {
        if(!file.exists()){
            file.createNewFile();
        }
    }
    static void deleteFile(File file){
        if(file.exists()){
            file.delete();
        }
    }
}

2.认识Java的流
读文件是指把文件中的数据读取到内存中,写文件是把内存中的数据写到文件中。
流是指一连串流动的字符,是以先进先出的方式发送和接收数据的通道。
如果数据输入到内存中,则称为输入流。如果从内存中输出,则称为输出流。
输入流的read()方法,取出流中的数据用输入流。
输出流的write()方法,向流中写入数据用输出流
字节流是8位通用字节流,其基本单位是字节。
字符流是16位Unicode字符流,其基本单位是Unicode字符,字符流最适合用来梳理字符串和文本。
在这里插入图片描述
3.字节流读写文本文件
(1)使用字节流读文本文件
FileInputStream将文本中的数据输入到内存中,可以利用它来读取文本文件中的数据。

  1. read() 从输入流中(要读取的内容)读取数据的下一个字节到java内部程序。
    返回值为0到255的int类型的值,返回值为字符的ASCII码(如a就返回97,n就返回110)。
    如果没有可用的字节,因为已经到达流的末尾,返回-1。运行一次只读一个字节。
  2. read(byte[] b) 从输入流中(要读取的内容)读取的一定数量的字节数,并将它们存储到缓存数组b中
    返回值为实际读取的字节数,运行一次读取一定数量的字节数。读取的字节数是最多等于b的长度。
    读取到的第一个字节存入b[0], 下一个字节存入b[1]…
    如果没有可用的字节,因为已经到达流的末尾,返回-1。如果b.length为0,返回0。
  3. read(byte[] b, int off, int len) 读取len字节的数据从输入流到缓存字节数组。
    返回值为实际读取的字节数,试图读取多达len字节,但可能读取到少于len字节。
    读取到的第一个字节存入b[off], 下一个字节存入b[off+1]…
import java.io.FileInputStream;
import java.io.IOException;

/**
 * 使用字节流读文本文件
 */
public class TestFileInputStream {

    public static void main(String[] args) throws IOException {
        //创建流对象
        FileInputStream fis = null;
        try{
            fis = new FileInputStream("G:/testFile/a.txt");
            int data;
            System.out.println("可读取的字节数:" + fis.available());
            while((data=fis.read()) != -1){
                System.out.print((char)data);    //data为int类型,a.txt中的内容是abc,如果不进行强制类型转换将会输出979898.
            }
        }finally {
            //关闭输入流
            if(fis != null){
                fis.close();
            }
        }
    }
}

(2)使用字节流写文本文件
把内存中数据输出到文件中,可以利用它把内存中的数据写入到文本文件中。
使用FileInputStream类读取文件时应注意以下几个方面:

  • 在创建FileInputStream实例时,如果相应的文件并不存在,就会自动创建一个空的文件。
  • 如果参数file或name表示的文件路径存在,但是代表一个文件目录,则此时会抛出FileNotFoundException类型的异常。
  • 默认情况下,向文件中写数据时将覆盖文件中原有的内容。
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 使用字节流写文本文件
 */
public class TestFileOutputStream {

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

        FileOutputStream fos = null;
        try{
            //append设置为true,表示在文件末位添加数据。如果不填或者设置为false,表示每次向文件中写数据时将覆盖文件中原有的内容。
            fos = new FileOutputStream("G:/testFile/b.txt",true);
            String str = "好好学习Java";
            byte[] words = str.getBytes();   //将字符串转换成字节数组
            //将byte数组从偏移量0ff开始的长度为len的字节数据输出到输出流中
            fos.write(words,0, words.length);
            System.out.println("文件更新成功!");
        }catch(IOException e){
            System.out.println("创建文件失败!");
        }finally {
            //关闭输出流
            if(fos != null){
                fos.close();
            }
        }
    }
}

4.字节流读写二进制文件

package demoIO;

import java.io.*;

/**
 * 使用字节流读写二进制文件
 */
public class TestDataIOStream {

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

        FileInputStream fis = null;
        DataInputStream dis = null;
        FileOutputStream fos = null;
        DataOutputStream dos = null;
        try{
            fis = new FileInputStream("G:/testFile/DemoMath.class");
            dis = new DataInputStream(fis);
            fos = new FileOutputStream("G:/testFile/A.class");
            dos = new DataOutputStream(fos);
            int temp;
            while((temp=dis.read()) != -1){
                dos.write(temp);
            }
        }finally {
            //关闭流
            if(dos != null){
                dos.close();
            }
            if(fos != null){
                fos.close();
            }
            if(dis != null){
                dis.close();
            }
            if(fis != null){
                fis.close();
            }
        }
    }
}

使用DataInputStream和DataOutputStream,按照与平台数据无关的方式在流中读写基本数据类型以及采用UTF-8编码的字符串

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

/**
 * DataInputStream类 可以按照与平台无关的方式从流中读取基本数据类型的数据,readUTF()能读取采用UTF-8字符集编码的字符串
 * DataOutputStream类可以按照与平台无关的方式向流中写入基本数据类型的数据,writeUTF()能写入采用UTF-8字符集编码的字符串
 */
public class TestBufferedIOStream {

    public static void main(String[] args) throws IOException {
        FileInputStream fis = null;
        DataInputStream dis = null;
        FileOutputStream fos = null;
        DataOutputStream dos = null;
        try{
            fis = new FileInputStream("G:/testFile/c.txt");
            dis = new DataInputStream(fis);

            fos = new FileOutputStream("G:/testFile/c.txt");
            dos = new DataOutputStream(fos);

            dos.writeByte(1);
            dos.writeLong(2);
            dos.writeChar('c');
            dos.writeUTF("Hello");

            System.out.println(dis.readByte());
            System.out.println(dis.readLong());
            System.out.println(dis.readChar());
            System.out.println(dis.readUTF());

        } catch (IOException e){
            e.printStackTrace();
        } finally {
            if(dos != null){
                dos.close();
            }
            if(fos != null){
                fos.close();
            }
            if(dis != null){
                dis.close();
            }
            if(fos != null){
                fos.close();
            }
        }
    }
}

5.字符流读写文本文件
通过字符流的方式读取文件,会使用缓冲区,提高了读文本文件的效率
(1)使用字符流读文本文件

package demoIO;

import java.io.BufferedReader;
import java.io.FileReader;

/**
 * 使用字符流读文本文件
 */
public class TestReader {

    public static void main(String[] args) throws IOException{
        FileReader fr = null;
        BufferedReader br = null;
        try{
            //创建一个FileReader对象
            fr = new FileReader("G:/testFile/c.txt");
            //创建一个BufferedReader对象
            br = new BufferedReader(fr);
            //读取一行数据
            String line = br.readLine();
            while(line != null){
                System.out.println(line);
                line = br.readLine();
            }
        }catch (IOException e){
            System.out.println("文件不存在");
        }finally {
            //关闭流
            if(br != null){
                br.close();
            }
            if(fr != null){
                fr.close();
            }
        }
    }
}

(2)使用字符流写文本文件

package demoIO;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 使用字符流写文本文件
 */
public class TestWriter {

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

        FileWriter fw = null;
        BufferedWriter bw = null;
        try{
            //创建一个FileWriter对象,写文件直接在文件后面添加
            fw = new FileWriter("G:/testFile/d.txt",true);
            //创建一个BufferedWriter对象
            bw = new BufferedWriter(fw);

            //写入信息
            bw.write("你也在学Java吗?");
            bw.newLine();
            bw.write("是啊");
            bw.newLine();
            bw.write("请多多指教!");
            bw.newLine();

            System.out.println("使用BufferedWriter写文件完成!");
            bw.flush();   //刷新缓冲区
        }catch (IOException e){
            System.out.println("该文件不存在!");
        }finally {
            //关闭流
            if(bw != null){
                bw.close();
            }
            if(fw != null){
                fw.close();
            }
        }
    }
}

6.重定向标准I/O
System.in和System.out,主要是用于从键盘接受数据以及向屏幕输出数据。
输入本来默认是键盘输入,改成其他的输入方式,就是输入重定向。
输出本来输出的位置是显示器,改成其他输出方式,就是输出重定向。
System.in常见方法
int read(),此方法从键盘结束一个字节的数据,返回值是该字符的ASCII码
int read(byte[] buf),此方法从键盘接收多个字节的数据,保存至buf中,返回值是接收字节数据的个数,非ASCII码
System.out常见方法
int print(),向屏幕输出数据,不换行,参数可以是Java的任意数据类型
int println(),向屏幕输出数据,换行,参数可以是Java的任意数据类型
(1)重定向输入

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;

/**
 * 重定向输入
 * 1.有一个已经初始化的FileInputStream输入流
 * 2.调用System.setIn()方法,将标准输入流重定向到目的输入流
 * 3.读取System.in中的内容
 */
public class ReIn {

    public static void main(String[] args) throws Exception{
        FileInputStream fis = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        try{
            //1.声明一个输入流
            fis = new FileInputStream("G:/testFile/e.txt");
            //2.重定向
            System.setIn(fis);
            //3.读取System.in标准输入流中的内容
            isr = new InputStreamReader(fis);
            br = new BufferedReader(isr);
            //4.输出System.in(也就是e.txt文件)中的内容
            String line;
            while((line=br.readLine()) != null){
                System.out.print(line);
            }
        } finally {
            if(br != null){
                br.close();
            }
            if(isr != null){
                isr.close();
            }
            if(fis != null){
                fis.close();
            }
        }
    }
}

(2)重定向输出

import java.io.FileOutputStream;
import java.io.PrintStream;

/**
 * 重定向输出流
 * 1.初始化PrintStream对象
 * 2.调用System.setOut()方法,将标准输出流重定向至PrintStream对象
 * 3.操作System.out流
 */
public class ReOut {

    public static void main(String[] args) throws Exception{
        FileOutputStream fos = null;
        PrintStream ps = null;
        try{
            //1.声明一个输出流PrintStream对象
            fos = new FileOutputStream("G:/testFile/f.txt",true);
            ps = new PrintStream(fos);
            //2.重定向标准输出流
            System.setOut(ps);
            //3.使用PrintStream对象向流中写信息
            System.out.println("测试重定向输出是否成功");
            System.out.println(new ReOut());
        }finally {
            if(ps != null){
                ps.close();
            }
            if(fos != null){
                fos.close();
            }
        }
    }
}

二、使用对象流读写对象信息

1.认识序列化
使用序列化将对象保存在文件中,使用反序列化从文件中读取对象信息。
Java中只有实现了java.io.Serializable接口的类的对象才能被序列化。
Serializable表示可串行的,可序列化的。
2.序列化保存对象信息

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * 使用序列化将学生对象保存在文件中
 */
public class SerializableObj {
    public static void main(String[] args) {
        ObjectOutputStream oos = null;
        FileOutputStream fos = null;
        try{
            //创建ObjectOutputStream输出流
            fos = new FileOutputStream("G:/testFile/stu.txt");
            oos = new ObjectOutputStream(fos);

            List<Student> list = new ArrayList<>();
            Student stu1 = new Student("lsw",22,"男");
            Student stu2 = new Student("monster",21,"男");
            list.add(stu1);
            list.add(stu2);
            
            //对象序列化,写入输出流
            oos.writeObject(list);
        }  catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(oos != null){
                try{
                    oos.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }

}
class Student implements Serializable {

    private static final long serialVersionUID = 2883734592647323105L;

    private String name;
    private Integer age;
    private String sex;

    public Student() {
    }

    public Student(String name, Integer age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

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

3.反序列化获取对象信息

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;

/**
 * 使用反序列化读取文件中的学生对象
 */
public class ReverseSerializable {

    public static void main(String[] args) {
        ObjectInputStream ois = null;
        FileInputStream fis = null;
        try{
            //创建ObjectInputStream输入流
            fis = new FileInputStream("G:/testFile/stu.txt");
            ois = new ObjectInputStream(fis);

            //反序列化,进行强制类型转换
            ArrayList<Student> list = (ArrayList<Student>)ois.readObject();
            //输出生成后的学生信息
            for(Student stu:list){
                System.out.print("姓名:" + stu.getName());
                System.out.print(" 年龄:" + stu.getAge());
                System.out.println(" 性别:" + stu.getSex());
            }

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

        }
    }
}

注意:

  • 如果向文件中使用序列化机制写入多个对象,那么反序列化恢复对象时,必须按照写入的顺序读取。
  • 如果一个可序列化的类,有多个父类(包括直接或间接父类),则这些父类要么是可序列化的,要么有无参数的构造器,否则会抛出异常。

4.对象引用的序列化

如果一个类的成员包含其他类的对象(如班级类中包含学生类型的对象),那么当要序列化班级对象时,则必须保证班级类和学生类都是可序列化的。

序列化的算法规则如下:

  • 所有保存到磁盘中的对象都有一个序列号
  • 当程序试图序列化一个对象时,将会检查是否已经被序列化,只有序列化后的对象才能被转换成字节序列输出
  • 如果一个对象已经被序列化,则程序直接输出一个序列号编号,而不再重新序列化
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值