Java文件操作与IO流学习笔记

本文详细介绍了Java中的IO流,包括文件操作、字节流(如FileInputStream和FileOutputStream)、字符流(如BufferedReader和BufferedWriter)、序列化流(ObjectInputStream和ObjectOutputStream)以及打印流的使用。重点讲解了如何处理文件操作、数据读写和对象序列化/反序列化。
摘要由CSDN通过智能技术生成

IO流与文件操作

文件操作

文件:硬盘上的文件,txt docx 电影 图片

常见的文件操作

import java.io.File;//大多数文件io操作的包
import java.io.IOException;

public class IO {
    public static void main(String[] args) {
        //file可以放一个不存在的路径 file:文件、目录、文件
        File file = new File("d:/abc.txt");//new一个新文件

        System.out.println("相对路径:"+file.getPath());
        System.out.println("绝对路径:"+file.getAbsolutePath());
        System.out.println("文件名称:"+file.getName());
        System.out.println("文件大小:"+file.length());//单位字节
        //创建一个文件,没有就创建,有就删除
        boolean flag = file.exists();//判断是否存在
        System.out.println(file.isFile() == true ? "文件" : "非文件");
        System.out.println(file.isDirectory() == true ? "目录" : "非目录");
        if (flag){
            file.delete();//彻底删除
            System.out.println("删除成功");
        }else{
            try {
                file.createNewFile();//创建文件
                System.out.println("创建成功");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 如果File(“绝对路径”):getPath()getAbsolutePath()的结果一致,打印的都是绝对路径

  • 如果File(“相对路径”):getPath()相对路径,getAbsolutePath()绝对路径

IO流

IO流:是一种FIFO(先进先出)的数据结构

在这里插入图片描述

打开流后不要忘了关闭close,否则会让数据卡在管道(缓冲区)里,导致数据丢失

flush可以把缓冲区里的东西冲出去,调用close实际上先调用了flush

按流向分:

  • 输入流:InputStream(字节流)顶层抽象类 Reader(字符流)顶层抽象类

  • 输出流:OutputStream(字节流)顶层抽象类 Writer(字符流)顶层抽象类

按照处理单元:

  • 字节流:(以字节复制任何东西)字节流就是将内容转为字节形式传输,1字节是8位二进制,二进制可以传输任何东西,所以字节也可以传输任何东西,文件的后缀名无所谓,重要的是他的字节内容(内容不变)
  • 字符流:文件内容变成字符,只能传输字符(文本文件),其他形式会有乱码,16位的Unicode处理文本文件

图片引用自B站黑马Java磊哥视频

字节流的文件操作

//输入流操作
//实现类FileInputStream   FileOutputStream
public static void test01() {
    InputStream in = null;
    try {
        in = new FileInputStream("d://hh.txt");//创建输入流对象
        byte[] buf = new byte[in.available()];//获取文件大小(这里采用一次全部读入,下面的实战会使用循环读入)
        in.read(buf);//读取文件内容
        System.out.println(new String(buf));//打印读出的内容
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    finally {
        try {
            if (in != null) in.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

//输出流操作
public static void test02() {
    String need = "abandon";
    OutputStream out = null;
    File file = new File("D://hh.txt");
    if (!file.exists()) {//检查文件是否存在
        try {
            file.createNewFile();
            System.out.println("文件不存在,创建成功");
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
    try {
        out = new FileOutputStream(file);//打开输出流
        out.write(need.getBytes());//通过输出流向文件内写入字节
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    finally {
        try {
            if (out != null) out.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

实战演练:运用IO流传输复制文件

public static void test03() {
    InputStream in = null;
    OutputStream out = null;
    File file = new File("D://Study//copy.txt");
    if (!file.exists()) {
        try {
            file.createNewFile();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
    try {
        in = new FileInputStream("D://Study//target.txt");//预先准备好一个需要拷贝的文件
        out = new FileOutputStream(file);
        int length = -1;
        byte[] buf = new byte[10];
        while ((length = in.read(buf)) != -1) {
            out.write(buf, 0, length);//控制写入的内容长度,否则会因为最后一次比10个字节小的情况没有完全覆盖上一次内容,而导致多写入一部分
        }
    }
    catch (Exception e) {
        e.printStackTrace();
    }
    finally {
        try {
            if (out != null) out.close();
            if (in != null) in.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

字符流的文件操作

传输改变文件测试,细节与字节流中的测试基本一致

/*
实现类FileReader   FileWriter
原信息:你好我是{name},目前工作单位{enterprise},个人微信{weixin}
替换占位符,并且输出
新信息:你好我是菜鸡,目前工作单位啃老,个人微信114514
*/
public static void test04(){
    FileReader in = null;
    FileWriter out = null;
    try {
        in = new FileReader("D://Study//abc.txt");
        out = new FileWriter("D://Study//xyz.txt");//以字节流的形式打开输入输出流
        char[] buf = new char[4];//字符流缓冲区是字符数组
        StringBuffer sb = new StringBuffer();
        int length = -1;
        while ((length = in.read(buf)) != -1) {
            sb.append(buf,0,length);
        }
        String content = sb.toString();
        content = content.replace("{name}","菜鸡").replace("{enterprise}","啃老").replace("{weixin}","114514");
        //字符串的练习操作
        out.write(content);
        System.out.println(content);
    }
    catch (IOException e) {
        e.printStackTrace();
    }
    finally {
        try {
            if (out != null) out.close();
            if (in != null) in.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

缓冲流

作用:加快读写操作速度

在已有流的基础上再打开一层(下面的流基本都有该特性,即更强大的包装流)缓冲流,关闭流时遵循先输出后输入,先外后内的原则

/*
自带缓冲区的字符流:缓冲区大小,每次读一行
实现类BufferedReader   BufferedWriter(字符流)   BufferedInputStream   BufferedOutputStream(字节流)
*/
public static void test04() {
    FileReader in = null;
    FileWriter out = null;
    BufferedReader br = null;
    BufferedWriter bw = null;
    try {
        in = new FileReader("d:/abc.txt");
        out = new FileWriter("d:xyz.txt");
        br = new BufferedReader(in);//这里展示一下字符缓冲流
        bw = new BufferedWriter(out);
        //再打开一层带缓冲区的流
        StringBuffer sb = new StringBuffer();
        String line = null;
        while ((line = br.readLine()) != null) {//打开后可以直接一行一行的读
            sb.append(line);
        }
        String content = sb.toString();
        content = content.replace("{name}", "张三").replace("{enterprise}", "家里蹲").replace("{weixin}", "1110");
        out.write(content);
        System.out.println(content);
    } 
    catch (IOException e) {
        e.printStackTrace();
    } 
    finally {
        try {
            //先关闭输出再关闭输入流,从外往内关闭
            if (bw != null) bw.close();
            if (br != null) bw.close();
            if (out != null) out.close();
            if (in != null) in.close();
        } 
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}

二进制流(数据流)

只需将字节流加一层二进制流的打开即可

//二进制流
//实现类DataInputStream   DataOutputStream
public static void test03() {
    InputStream in = null;
    OutputStream out = null;
    InputStream dataInput = null;
    OutputStream dataOutput = null;
    try {
        in = new FileInputStream("d:/abc.txt");
        dataInput = new DataInputStream(in);//将字节流转换成二进制流
        out = new FileOutputStream("d:xyz1.txt");
        dataOutput = new DataOutputStream(out);//将字节流转换成二进制流
        byte[] buf = new byte[10];
        int len = -1;
        while ((len = dataInput.read(buf)) != -1) {//通常使用二进制流时是为了用它读入不同类型数据的能力,如readInt(),readDouble()方法等等,写入同理,写入相应类型的数据可直接进行转换,这里就不进行了
        	dataOutput.write(buf, 0, len);
        }
    } 
    catch (IOException e) {
    	e.printStackTrace();
    } 
    finally {
        try {
        	if (dataOutput != null) dataOutput.close();
        	if (dataInput != null) dataInput.close();
        	if (out != null) out.close();
        	if (in != null) in.close();
        } 
        catch (IOException e) {
        	e.printStackTrace();
        }
    }
}

转换流

作用:指定编码形式以解决直接用字符流读取文件内容时的乱码问题

  • InputStreamReader将字节流转换字符流

    public  static void test07() {
        try {
            InputStream in = new FileInputStream("D://Study//hh.txt");
            InputStreamReader hh = new InputStreamReader(in, StandardCharsets.UTF_8);//字节读入和需要转换的编码形式,读取文件内容同上一部分中的操作
            hh.close();
            in.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    
  • OutputStreamWriter将字节流转换成字符流

    public  static void test07() {
        try {
            OutputStream out = new FileOutputStream("D://Study//hh.txt");
            OutputStreamWriter hh = new OutputStreamWriter(out, StandardCharsets.UTF_8);//格式同上
            //hh.write("基尼泰美~~");
            hh.close();
            out.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    

打印流

  • PrintStream字节打印流

    public static void test05() {
        //终端打印write方法
        OutputStream out = new PrintStream(System.out);//顶层为OueputStream
        try {
            out.write("hh".getBytes());//需要获取其字节输出防止乱码
            //out.close();标准输出流不需要手动关闭
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        
        //直接打印到相应的文件里
        try {
            PrintStream dd = new PrintStream("D://Study//hh.txt");
            System.setOut(dd);//重定向(打印流的应用):改变标准输出流的输出方向
            System.out.println("hh123");
            dd.close();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    
  • PrintWriter字符打印流

    public static void test06() {
        PrintWriter out = new PrintWriter(System.out);//顶层为Writer
        out.println("hh");
        //out.close();标准输出流不需要手动关闭
        try {
            PrintWriter printWriter = new PrintWriter(new FileWriter("D://Study//hh.txt"));
            printWriter.print("manbaout");
            printWriter.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    

对象流(序列化流)

作用:将前面各种流没办法操作的对象进行读取或存储(在文件或网络中传输)

先准备一个实现Serializable接口的Person类(必须实现该接口否则无法将其对象进行序列化相关操作)

该接口内部无任何需要实现的抽象方法,只是一个标记接口,给编译器看的提醒它要进行序列化

public class Person implements Serializable {
    private String account;
    private String name;
    private String password;

    public Person() {
    }

    public Person(String account, String name, String password) {
        this.account = account;
        this.name = name;
        this.password = password;
    }
    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getName() {
        return name;
    }

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

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "Person{" +
                "account='" + account + '\'' +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
  • ObjectInputStream对象字节输出流(序列化流)(把对象写到文件中去)

    public static void test08() {
        Person person = new Person("0001", "QQ", "1234");
        try (OutputStream out = new FileOutputStream("D://Study//hh.txt");
             ObjectOutputStream obj = new ObjectOutputStream(out)){
            obj.writeObject(person);
            System.out.println("序列化成功");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    /*这是文件中的内容,是一种给机器看的写法
     sr TestStream.Person擛铲氖2? L  accountt Ljava/lang/String;L nameq ~ L passwordq ~ xpt 0001t QQt 1234 
    tips:可以发现一个不妥之处,实际开发中这样写会把密码也序列化了,黑客随便一黑就能get到用户密码,显然不够安全
    所以就有了相应的关键字  transient
    将这个关键字赋给类中不想序列化存储的变量即可让它出局,eg.private transient String password;
    */
    
  • ObjectOutputStream对象字节输入流(反序列化流)(将对象从文件中读出来)

    public static void test08() {
        try (InputStream in = new FileInputStream("D://Study//hh.txt");
             ObjectInputStream obj = new ObjectInputStream(in)){
            Person myperson = (Person)obj.readObject();//注意读出来的数据进行强制转化
            System.out.println(myperson);
        }  catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    //当有多个对象,在进行序列化存储时可以操作用ArrayList集合进行存储,它已经实现过Serializable接口
    

关于IO流主要有这些分类,需要我们熟练掌握的其实也就是最开始的字节流操作和序列化流,还有打印流的重定向,在学完Java进行实际开发时似乎会用的比较频繁,本文到这里就结束了!!感谢阅读

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值