【Java高级编程】IO流学习笔记

简介: 【Java高级编程】IO流学习笔记

IO流


I(input)O(output)。

流的分类:

  • 按照读写方向,分为输入流和输出流。(在程序角度分析)
  • 按照读写内容单位而言,分为字节流和字符流
  • 按照流的功能不同,分为节点流和处理流
  • 字节流:直接连接在文件上
  • 处理流:嵌套在其它流上

流的家族体系

- 输入 输出
字节流 InputStream OutputStream
字符流 Reader Writer

上面四个都是抽象类

对应文件流:

  • 文件字节输入流 FileInputStream
  • 文本字节输出流FileOutputStream
  • 字符输入流:FileReader
  • 字符输入流:FileWriter

File类

表示操作系统中的文件或者文件夹。

  • 文件路径
  • 绝对路径
  • 相对路径

文件/文件夹基础操作

package eg01_file;
import java.io.File;
import java.io.IOException;
public class Test1 {
    public static void main(String[] args) {
        boolean result = false;
        File file = new File("test01.txt"); // 该文件可有可无
        try {
            result = file.createNewFile();//create a file. create file not folder
            System.out.println("文件创建"+ (result ?"成功":"失败"));
            System.out.println(file.getParent());// 拿到上一级文件夹路径
            System.out.println(file.getParentFile());//拿到上一级文件夹的文件对象
            file.mkdir();//创建单个文件夹。
            file.mkdirs();//支持同时创建多级目录
            result  = file.renameTo(new File("test01_change.txt"));
            System.out.println("文件修改名称"+ (result ?"成功":"失败"));
            //查看相关
            System.out.println(file.exists());//文件是否存在
            System.out.println(file.isAbsolute());//是否是绝对路径
            System.out.println(file.isDirectory());//是否是文件夹
            System.out.println(file.isFile());//是否是文件夹
            System.out.println(file.length());//查看文件大小
        } catch (IOException e) {
            e.printStackTrace();//查看文件是否存在
        }
    }
}

创建文件的完整步骤

package eg01_file;
import java.io.File;
public class Test2 {
    public static void main(String[] args) {
    try{
        File file = new File("abc/test2.txt");
        //判断上层文件夹是否存在
        File parentFile = file.getParentFile();
        if(!parentFile.exists()){
            //上层文件夹不存在,先创建
            parentFile.mkdirs();
        }
        //创建文件
        file.createNewFile();
    }catch (Exception e){
        e.printStackTrace();
    }
    }
}

IO流 - 节点流

读入文件一个字节(一个字节)

不能读取中文。中文是2个字节一个字

package eg02_io;
import java.io.FileInputStream;
import java.io.InputStream;
public class TestFileInputStream {
  public static void main(String[] args) {
    //创建流
    try {
      InputStream fis = new FileInputStream("test01.txt");
      //----------------------------------------------
      int result = fis.read();//读出来的是字符ASCII码
      System.out.println((char) result);//强制转换
      //---------------------------------------------- 
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

[FileInputStream]字节数组的方式读取(读取全部内容)

package eg02_io;
import java.io.FileInputStream;
import java.io.InputStream;
public class TestFileInputStream {
  public static void main(String[] args) {
    //创建流
    try {
      InputStream fis = new FileInputStream("test01.txt");
      byte[] bs = new byte[1024];//一次读kb
      int len = fis.read(bs);//读出来的是字节数组。返回值为读取的字节数量。
      System.out.println(new String(bs, 0, len));//字节数组转为字符
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

[FileInputStream]读取文件最重要的一套写法

package eg02_io;
import java.io.FileInputStream;
import java.io.InputStream;
public class TestFileInputStream {
  public static void main(String[] args) {
    //创建流
    try {
      InputStream fis = new FileInputStream("test01.txt");
      byte[] bs = new byte[1024];//一次读kb
      int len = 0;
      while ((len = fis.read(bs)) != -1) {// 不等于-1表示没读完,便继续读取。
        //该写法仅限于IO流使用,其他地方不要用。
        String s = new String(bs, 0, len);
        System.out.println(s);
      }
      //关流
      fis.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

[FileoutputStream]向文件写入内容

package eg02_io;
import java.io.File;
import java.io.FileOutputStream;
public class TestFileOutputStream {
  public static void main(String[] args) {
    try {
      FileOutputStream fos = new FileOutputStream(new File("test01.txt"), true);//true追加。则不会清空原有数据
      fos.write("牛啊牛啊,醉酒的向日狼".getBytes());
      fos.flush();
      fos.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

[FileReader]读入文件一个字符(两个字节)

package eg02_io;
import java.io.File;
import java.io.FileReader;
public class TestFileReader {
  public static void main(String[] args) {
    try {
      FileReader fr = new FileReader(new File("test01.txt"));
      int i = fr.read();//以字符为单位。
      System.out.println((char) i);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

[FileReader]读入文件所有字符

package eg02_io;
import java.io.File;
import java.io.FileReader;
public class TestFileReader {
  public static void main(String[] args) {
    try {
      FileReader fr = new FileReader(new File("test01.txt"));
      char[] cs = new char[1024];
      int len = fr.read(cs);
      System.out.println(new String(cs, 0, len));
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

对于存在大量内容需要读取时的写法

package eg02_io;
import java.io.File;
import java.io.FileReader;
public class TestFileReader {
  public static void main(String[] args) {
    try {
      FileReader fr = new FileReader(new File("test01.txt"));
      char[] cs = new char[1024];
      int len = 0;
      while ((len = fr.read(cs)) != -1) {
        System.out.println(new String(cs, 0, len));
      }
      fr.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

[FileWriter]向文件写入内容

package eg02_io;
import java.io.File;
import java.io.FileWriter;
public class TestFileWriter {
  public static void main(String[] args) {
    try {
      FileWriter fw = new FileWriter(new File("test01.txt"), true);//追写则true
      fw.write("刑啊,太刑了。");
      fw.flush();
      fw.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

如何选择流?

字节流:常用于读取非文本文件

字符流:常用于读取文件中的文字信息

IO流练习:复制图片操作

选择的流:字节流

package eg03_copypic;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class test3 {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream(new File("1.jpg"));
        FileOutputStream fos = new FileOutputStream(new File("2.jpg"),true);
        byte[] bs = new byte[1024];
        int len = 0;
        while ((len = fis.read(bs))!=-1){
            fos.write(bs,0,len);
        }
        fis.close();
        fos.flush();
        fos.close();
    }
}

如果不是复制,而是剪切

package eg03_copypic;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class test3 {
    public static void main(String[] args) throws IOException {
        File file = new File("2.jpg");
        FileInputStream fis = new FileInputStream(file);
        FileOutputStream fos = new FileOutputStream(new File("3.jpg"),true);
        byte[] bs = new byte[1024];
        int len = 0;
        while ((len = fis.read(bs))!=-1){
            fos.write(bs,0,len);
        }
        fis.close();
        fos.flush();
        fos.close();
        file.delete();
    }
}

IO流 - 处理流

缓冲流

缓冲流:带有缓冲区的数据流

重点是BufferedReader ,这是读取文本文件最好的方式

  • BufferedInputStream
  • BufferedOutputStream
  • BufferedReader
  • BufferedWirter
package eg04.buffer;
import java.io.*;
public class test04 {
    public static void main(String[] args) throws IOException {
       // BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("test01.txt"))); //一般不用
        BufferedReader br = new BufferedReader(new FileReader(new File("test01.txt")));
//        System.out.println(br.readLine()); //读取文本文件最好用的方法。
//        System.out.println(br.readLine());
        String str = "";
        while ((str= br.readLine())!=null){
            //读取内容
            System.out.println(str);
        }
        br.close();
    }
}

转换流

字节流 ==> 字符流 :

  • [输入] InputStreamReader
  • [输出] OutputStreamWriter
package eg05_convert;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
public class test_out {
    public static void main(String[] args) throws IOException {
//        System.out.println();
        Writer writer = new OutputStreamWriter(System.out);
        writer.write("abc路人甲");
        writer.flush();
        //writer.close();//有时候流不可以关,如果这里关了,后面的 System.out.println(); 也不会输出。
        System.out.println("关闭了流");
    }
}

对象流

  • ObjectInputStream
  • ObjectOutputStream

[对象] Person.java

package eg06_obj;
public class Person {
    private int id;
    private String name;
    private int age;
    public Person(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    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;
    }
}

[测试] test06.java

package eg06_obj;
import java.io.*;
public class test06 {
    public static void main(String[] args) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("person.data")));
        Person p = new Person(1,"萌狼蓝天",18);
        oos.writeObject(p);
        oos.flush();
        oos.close();
    }
}

[运行结果]报错

q2.png

序列化:把一个对象转化为字节的过程

反序列化:把字节转化成对象

解决方案:在Java中只需要给类添加一个实现,Serialable。这样这个类就可以被序列化了。过程是全自动的。(实质:让数据可以进行序列化)

更改 Person.java

package eg06_obj;
import java.io.Serializable;
public class Person implements Serializable {
    private int id;
    private String name;
    private int age;
    public Person(int id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    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;
    }
}

此时运行,便不会报错。

那么如何读取呢?(反序列化)

package eg06_obj;
import java.io.*;
public class Test07 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("person.data")));
        Object obj =  ois.readObject();
        Person p = (Person) obj;
        System.out.println(p.getName());
    }
}

文件修改操作

思路:偷梁换柱。逐行读取文件内容,将内容进行替换,将替换结果记录在一个新文件中,直到数据写入完毕,把源文件删除。

把新文件的名字改成源文件的名字

代码如下

package eg07_update;
import java.io.*;
import java.nio.Buffer;
public class test7 {
    public static void main(String[] args) throws Exception {
        File res  = new File("test.txt");
        //没有test.txt需要先手动创建,内容如下
        /**
         * 记录生活的博客:萌狼蓝天の小世界 - 萌狼蓝天 (mllt.cc)
         *
         * 记录学习笔记的博客:萌狼蓝天 - 博客园 (cnblogs.com)
         *
         * 分享信息技术相关内容的哔哩哔哩账号:萌狼蓝天的个人空间_哔哩哔哩_bilibili
         *
         * 分享个人生活的哔哩哔哩账号:醉酒的向日狼的个人空间_哔哩哔哩_bilibili
         *
         * 这四个网站是我主要活跃的网站
         *
         * 其中,mllt.cc这个网站是搭建在我自己服务器的,也许我会因为续费不起服务器而在2023年的时候关闭这个网站。
         *
         * 如果你想获取我的学习笔记,应该去看我的博客园
         *
         * 如果你想观看我录制的计算机相关知识视频,应该去看萌狼蓝天的个人空间_哔哩哔哩_bilibili
         */
        File new_res  = new File("副本_test.txt");
        BufferedReader br = new BufferedReader(new FileReader(res));
        BufferedWriter bw = new BufferedWriter(new FileWriter(new_res));
        String line = "";
        while((line = br.readLine())!=null){
            line = line.replace("萌狼蓝天","易水千");
            bw.write(line);
            bw.newLine();//另起一行(换行)
        }
        br.close();
        bw.flush();
        bw.close();
        //删除源文件
        res.delete();
        //重命名新文件
        new_res.renameTo(res);
    }
}

[运行结果]

q1.png


相关文章
|
2月前
|
存储 缓存 Java
Java 并发编程——volatile 关键字解析
本文介绍了Java线程中的`volatile`关键字及其与`synchronized`锁的区别。`volatile`保证了变量的可见性和一定的有序性,但不能保证原子性。它通过内存屏障实现,避免指令重排序,确保线程间数据一致。相比`synchronized`,`volatile`性能更优,适用于简单状态标记和某些特定场景,如单例模式中的双重检查锁定。文中还解释了Java内存模型的基本概念,包括主内存、工作内存及并发编程中的原子性、可见性和有序性。
Java 并发编程——volatile 关键字解析
|
2月前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
233 2
|
2月前
|
算法 Java 调度
java并发编程中Monitor里的waitSet和EntryList都是做什么的
在Java并发编程中,Monitor内部包含两个重要队列:等待集(Wait Set)和入口列表(Entry List)。Wait Set用于线程的条件等待和协作,线程调用`wait()`后进入此集合,通过`notify()`或`notifyAll()`唤醒。Entry List则管理锁的竞争,未能获取锁的线程在此排队,等待锁释放后重新竞争。理解两者区别有助于设计高效的多线程程序。 - **Wait Set**:线程调用`wait()`后进入,等待条件满足被唤醒,需重新竞争锁。 - **Entry List**:多个线程竞争锁时,未获锁的线程在此排队,等待锁释放后获取锁继续执行。
87 12
|
2月前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
2月前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
73 3
|
2月前
|
Java 程序员
Java编程中的异常处理:从基础到高级
在Java的世界中,异常处理是代码健壮性的守护神。本文将带你从异常的基本概念出发,逐步深入到高级用法,探索如何优雅地处理程序中的错误和异常情况。通过实际案例,我们将一起学习如何编写更可靠、更易于维护的Java代码。准备好了吗?让我们一起踏上这段旅程,解锁Java异常处理的秘密!
|
2月前
|
开发框架 安全 Java
Java 反射机制:动态编程的强大利器
Java反射机制允许程序在运行时检查类、接口、字段和方法的信息,并能操作对象。它提供了一种动态编程的方式,使得代码更加灵活,能够适应未知的或变化的需求,是开发框架和库的重要工具。
88 4
|
3月前
|
安全 Java 开发者
Java中的多线程编程:从基础到实践
本文深入探讨了Java多线程编程的核心概念和实践技巧,旨在帮助读者理解多线程的工作原理,掌握线程的创建、管理和同步机制。通过具体示例和最佳实践,本文展示了如何在Java应用中有效地利用多线程技术,提高程序性能和响应速度。
96 1
|
3月前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
3月前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####

热门文章

最新文章