首页 > 其他分享 >IO流(主要是记住四大类InputStream,OutputStream、Reader和Writer,其他都是他们的子类)

IO流(主要是记住四大类InputStream,OutputStream、Reader和Writer,其他都是他们的子类)

时间:2024-03-16 19:32:18浏览次数:21  
标签:文件 OutputStream String 子类 Writer System println new out

IO流

1、文件

(1)文件概念

文件就是保存数据的地方。例如word文档,txt文件,execl文件等等。

(2)文件流

文件在程序中是以流的形式来操作的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 流:数据在数据源(文件)和程序(内存)之间经历的路径
  • 输入流:数据从数据源(文件)到程序(内存)的路径
  • 输出流:数据从程序(内存)到数据源(文件)的路径

2、常用的文件操作

(1)创建文件构造器的相关方法
new File(String pathname) 		//根据路径构建一个File对象
new File(File parent, String child)	//根据父目录文件+子路径构建
new File(String parent, String child) //根据父目录+子路径构建
createNewFile 创建新文件

举例:

方式一:

//方式1 new File(String pathname)
public void create01() throws IOException {
    //两个斜杠是防止一个变成转义字符
    String filePath = "d:\\news1.txt";
    File file = new File(filePath);     //这里file只是一个对象,并没有创建文件
    file.createNewFile();               //执行了createNewFile才会真正的,在磁盘创建文件
    System.out.println("创建文件成功!");
}

方式二:

//方式2 new File(File parent, String child) 根据父目录文件+子路径构建
public void create02() throws IOException {
    //两个斜杠是防止一个变成转义字符
    File parentFile = new File("d:\\");
    String fileName = "news2.txt";
    File file = new File(parentFile, fileName);
    file.createNewFile();
    System.out.println("创建文件成功!");
}

方式三:

//方式2 new File(File parent, String child) 根据父目录文件+子路径构建
public void create02() throws IOException {
    //两个斜杠是防止一个变成转义字符
    File parentFile = new File("d:\\");
    String fileName = "news2.txt";
    File file = new File(parentFile, fileName);
    file.createNewFile();
    System.out.println("创建文件成功!");
}
//IO流的四个抽象类:InputStream, OutputStream, Reader, Writer
(2)获取文件的相关信息
getName,getAbsolutePath,getParent,length,exists,isFile,isDirectory

举例:

public void info(){
    //先创建文件对象
    File file = new File("d:\\new1.txt");
    //调用对应的方法,获取相关信息
    System.out.println("文件名字="+file.getName());
    System.out.println("文件的绝对路径="+file.getAbsolutePath());
    System.out.println("文件父级目录="+file.getParent());
    System.out.println("文件大小(字节)="+file.length());
    System.out.println("文件是否存在="+file.exists());
    System.out.println("是不是一个文件="+file.isFile());
    //目录本质也是一个文件,一种特殊的文件
    System.out.println("是不是一个目录="+file.isDirectory());
}
(3) 目录的操作和文件删除
mkdir  	//创建一级目录
mkdirs 	//创建多级目录
delete  //删除空目录或文件

举例:

public void directoryMethod() throws IOException {
    String fileName1 = "d:\\new1.txt";      //删除文件
    File file = new File(fileName1);
    if(file.exists()){
        file.delete();
        System.out.println("文件已经删除"+(file.exists() == false));
    }

    String fileName2 = "d:\\demo02";        //删除空目录
    File file2 = new File(fileName2);
    if(file2.exists()){
        file2.delete();
        System.out.println("文件已经删除"+(file2.exists() == false));
    }
    else{
        System.out.println("文件不存在");
    }

    String fileName3 = "d:\\demo\\a\\b\\c"; //创建多级目录
    File file3 = new File(fileName3);
    if(file3.exists()){
        System.out.println("文件存在");
    }
    else{
        System.out.println("文件不存在,创建该文件");
        file3.mkdirs();
    }
}

3、IO流原理以及流的分类

(1)Java IO流原理
  • I/O 是Input/Output 的缩写,I/O 技术是非常实用的技术,用于处理传输数据。如读/x写文件,网络通讯等。
  • Java程序中,对于数据的输入/输出以“流(stream)“的方式进行
  • Java.io包提供了各种“流”类和接口,用于获取不同种类的数据,并通过方法输入或输出数据
  • 输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中
  • 输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中
(2)分类方法
按操作数据单位分为:字节流(8 bit)二进制文件字符流(按字符)文本文件
按数据流流向分为:输入流输出流
按流的角色分为:节点流处理流/包装流

四个抽象类:(IO流的40多个流都是由这个抽象基类派生的)

(抽象基类)字节流字符流
输入流InputStreamReader
输出流OutputStreamWriter

4、IO流体系图

(1)字节流

InputStream

在这里插入图片描述

OutputStream

在这里插入图片描述

(2)字符流

Reader:

在这里插入图片描述

Writer:

在这里插入图片描述

5、IO流类各类实践

(1)FileInputStream

函数接口:(只列举常用方法)

FileInputStream(File file)         // 构造函数1:创建“File对象”对应的“文件输入流”
FileInputStream(String path)       // 构造函数3:创建“文件(路径为path)”对应的“文件输入流”

void     close()                 // 关闭“文件输入流”
int      read()                  // 返回“文件输入流”的下一个字节
int      read(byte[] b)          // 从该输入流读取最多 b.length个字节的数据为字节数组。 

方法举例:

public void readFile01(){//读取一个字节
    String filePath = "d:\\test.txt";
    int readData = 0;
    FileInputStream fileInputStream = null;
    try {
        fileInputStream = new FileInputStream(filePath);
        //read,读取一个字节,直到-1结束
        while((readData = fileInputStream.read()) != -1){
            System.out.print((char) readData);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        //关闭文件流,释放资源,文件流是一种资源,需要主动关闭
        try {
            fileInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


public void readFile02(){//读取多个字节
    String filePath = "d:\\test.txt";
    byte readData[] = new byte[16];     //一次读取16个字节
    int readLen = 0;
    FileInputStream fileInputStream = null;
    try {
        fileInputStream = new FileInputStream(filePath);
        //read(byte),返回实际读取的字符数
        while(((readLen = fileInputStream.read(readData)) != -1)){
            System.out.println(new String(readData, 0, readLen));
        }
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        //关闭文件流,释放资源,文件流是一种资源,需要主动关闭
        try {
            fileInputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
(2)FileOutputStream

功能:将数据写入到文件中,如果文件不存在,就会创建这个文件。

方法举例:

    public void FileOutput01() throws IOException {
        //如果文件不存在,就会创建这个文件
        String filePath = "d:\\test.txt";
        FileOutputStream fileOutputStream = null;
        fileOutputStream = new FileOutputStream(filePath);      //写入内容会覆盖原来的内容
//        fileOutputStream = new FileOutputStream(filePath,true);      //写入内容会增加到当前文件的末尾
        fileOutputStream.write('s');        //写一个字节
        String str = "hello, you are so beautiful";
        //str.getBytes() 可以将字符串转为字符数组
        fileOutputStream.write(str.getBytes());
        fileOutputStream.write(str.getBytes(), 0,3);        //off为偏移量,3为要写入的长度
        fileOutputStream.close();       //关闭文件流
    }
(3)FileReader

方法介绍:

  • new FileReader(File/String)
  • read() 每次读取单个字符,返回该字符,如果读到文件末尾返回-1
  • read(char[]) 批量读取多个字符到数组中能够,返回读取到字符数量,如果读到文件末尾返回-1

方法举例:

    public void FileRead01() throws IOException{
        String filePath = "d:\\test.txt";
        FileReader fileReader = new FileReader(filePath);
        int data;       //读取单个字符
//        while((data = fileReader.read()) != -1){
//            System.out.print((char)data);
//        }
        char read[] = new char[10]; //每次读取10个字符,注释是因为上次的流已经到文件末尾了,所以要么重新更新流的指向,要么注释掉,这里选择注释
        int readLen = 0;
        while((readLen = fileReader.read(read) )!= -1){
            System.out.println(new String(read));
        }
        fileReader.close();
    }
(4)FileWriter

方法介绍:

  • new FileReader(File/String) 覆盖模式,覆盖掉当前文件
  • new FileReader(File/String,true) 追加模式,流的指针在末尾
  • write() 写入单个字符
  • write(char[]),写入指定数组
  • write(char[], off, len) 写入指定数组的某个部分
  • write(string) 写入整个字符串
  • write(string, off, len) 写入字符串的指定部分

方法举例:

public void fileWrite01() throws IOException{
    String dest = "风雨之后,定见彩虹";
    String filePath = "d:\\test.txt";
    FileWriter fileWriter = new FileWriter(filePath);
    fileWriter.write(dest);                                 //写入字符串
    fileWriter.write(dest.toCharArray());                   //转换为字符数组写入
    fileWriter.write(dest.toCharArray(),0,4);       //从0开始写入字符
    fileWriter.close(); //close 等价于 flush() + 关闭,执行close的时候底层才执行写文件的操作
    
}

5、节点流和处理流

(1)介绍
  • 节点流可以从一个特定的数据源读写数据,比如FilReader,FileWriter等
  • 处理流(包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供更强大的读写功能,更加灵活。比如:BufferedReader,BufferedWriter,创建对象时,需要传入一个节点流进行实现

节点流与处理流分类:

在这里插入图片描述

节点流与处理流的区别与联系:

  1. 节点流是底层流/低级流,直接跟数据源相接
  2. 处理流(包装流)包装节点流,既可以消除不同节点之间的实现差异,也可以提供更方便的方法来完成输入输出
  3. 处理流(包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相接。

处理流的功能主要体现在以下两个方面:

  1. 性能的提高,主要增加缓冲的方式来提高输入输出的效率
  2. 操作的便捷:处理流可能提供了一系列的方法来一次输入输出大量的数据,使用更急灵活方便
(2)处理流-BufferedReader和BufferedWriter

BufferedReader和BufferedWriter属于字符流,是按照字符来读取数据的

会创建一个内部缓冲区的数组,可以直接将多个字节写入底层输出流当中,不必对每次字节写入调用底层系统,提高了效率。

关闭时处理流,只需要关闭外层流即可。

举例:

//BufferedReader和BufferedWriter是安装字符操作,不能操作二进制文件[声音、视频、doc,pdf等等],可能造成文件损坏
public void ReaderAndWriter() throws IOException{
    String filePath = "d:\\FileReadStream01.java";
    //创建bufferedReader,里面要传一个与源文件直接相关的节点流
    BufferedReader br = new BufferedReader(new FileReader(filePath));
    String line;        //可以直接按行读取,效率较高
    while((line = br.readLine()) != null){  //readLine不会读取换行符
        System.out.println(line);
    }
    //关闭流只需要关闭外层流即可,底层会自动关闭节点流
    br.close();

    String writePath = "d:\\test.txt";
    BufferedWriter bw = new BufferedWriter(new FileWriter(writePath));
    bw.write("hello, how are you");
    bw.newLine();       //换行
    bw.write("hello2,how old are you");
    bw.close();     //底层自动关闭FileWriter
}
(3)处理流-BufferedInputStream和BufferedOutputStream

BufferedInputStream和BufferedOutputStream属于字节流,是按照字节来读取数据的,可以读取二进制文件,比如图像,声音,视频等

关闭时处理流,只需要关闭外层流即可。

举例:

   public void BufferedInputAndOutput() throws IOException{
        String src1 = "d:\\bp.jpg";
        String src2 = "d:\\FileReadStream01.java";
        String dest1 = "d:\\bp1.jpg";
        String dest2 = "d:\\FileReadStream02.java";

        //创建对象,因为 FileInputStream是InputStream的子类,所以可以传FileInputStream
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(src1));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest1));

        byte buf[] = new byte[1024];
        int readLen = 0;
        while((readLen = bis.read(buf)) != -1){
//            bos.write(buf, 0, readLen);
            bos.write(buf);
        }
        bis.close();
        bos.close();
    }
(4)对象流-ObjectInputStream和ObjectOutputStream

对象流在进行输入输出的过程中,可以保存数据的值和数据类型

序列化和反序列化:

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

ObjectOutputStream 提供序列化功能

ObjectInputStream 提供反序列化功能

举例:

public class ObjectInputAndOutputStream {
    public static void main(String[] args) throws IOException, ClassNotFoundException {

        //序列化后,保存的文件格式,不是存文本,而是按照他的格式来保存
        //序列化
        String filePath = "d:\\data.dat";
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
        //序列化数据到 e:\data.dat
        oos.writeInt(100);// int -> Integer (实现了 Serializable)
        oos.writeBoolean(true);// boolean -> Boolean (实现了 Serializable)
        oos.writeChar('a');// char -> Character (实现了 Serializable)
        oos.writeDouble(9.5);// double -> Double (实现了 Serializable)
        oos.writeUTF("韩顺平教育");//String
        //保存一个dog 对象
        oos.writeObject(new Dog("旺财", 10));
        oos.close();
        System.out.println("数据保存完毕(序列化形式)");

        //反序列化
        // 1.创建流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:\\data.dat"));
        // 2.读取, 注意顺序,顺序与读取的顺序一致
        System.out.println(ois.readInt());
        System.out.println(ois.readBoolean());
        System.out.println(ois.readChar());
        System.out.println(ois.readDouble());
        System.out.println(ois.readUTF());
        System.out.println((Dog)ois.readObject());

        // 3.关闭
        ois.close();
        System.out.println("以反序列化的方式读取(恢复)ok~");
    }
}

class Dog implements Serializable{  //必须实现序列化接口才能调用Object对象流
    String name;
    int age;

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

注意事项和细节说明

  • 读写顺序要一致
  • 要求序列化或反序列化对象,需要实现Serializable接口
  • 序列化的类建议添加SerialVersionUID,可以提高版本的兼容性
  • 序列化对象中,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员
  • 序列化对象中,要求里面属性的类型也需要实现序列化接口
  • 序列化具备可继承性,如果某个类已经实现了序列化,则它的子类也默认实现了序列化
(5)标准输入输出流
类型默认设备
System.in 标准输入InputStream键盘
System.out 标准输入OutputStream显示器

案例:

传统的Scanner是从标准输入键盘中获取数据的

public static void main(String[] args) {
    // System.in 类为: public final static InputStream in = null;
    //编译类型:InputStream
    //运行类型:BufferedInputStream
    //表示标准输入:键盘
    System.out.println(System.in.getClass());
    
    // System.in 类为: public final static PrintStream out = null;
    //编译类型:PrintStream
    //运行类型:PrintStream
    //表示标准输出:显示屏
    System.out.println(System.out.getClass());
    Scanner scanner = new Scanner(System.in);	//传入的是BufferedInputStream
}
(6)转换流InputStreamReader和OutputStreamWriter

介绍:

  1. InputStreamReader:是Reader的子类,可以将InputStream(字节流)包装成(转换成)Reader(字符流)
  2. OutputStreamWriter:是Writer的子类,可以将OutputStream(字节流)包装成Writer(字符流)
  3. 当处理纯文本数据时,如果使用字符流的效率更高,并且可以有效解决中文问题,建议将字节流转换成字符流
  4. 可以在使用时指定编码格式(比如:UTF-8,gbk,gb2312,ISO8859-1等)

举例:

public static void main(String[] args) throws IOException {
    //InputStreamReader,可以将字节流转换为字符流,然后还可以指定编码,比较方便
    String filePath = "d:\\test.txt";
    //1、把FileInputStream转换为InputStreamReader
    InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), "gbk");
    //2、把InputStreamReader 传入 BufferedReader
    BufferedReader br = new BufferedReader(isr);
    //3、读取
    String s = br.readLine();
    System.out.println("读取内容:"+s);
    br.close();

    //OutputStreamWriter,写文件,可以指定编码方式
    //1、创建流对象
    OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath), "gbk");
    //2、写入
    osw.write("hello,你好吗!");
    //3、关闭
    osw.close();
}
(7)打印流 PrintStream和PrintWriter

打印流只有输出流,没有输入流

举例:

public static void main(String[] args) throws IOException {
    PrintStream out = System.out;
    //默认情况下,输出数据的位置是标准输出,就是显示器
    out.println("hack,hello");
    //因为print 底层使用的是write , 所以我们可以直接调用write 进行打印/输出
    out.write("你好".getBytes());
    out.close();
    //我们可以去修改打印流输出的位置/设备
    System.setOut(new PrintStream("d:\\text1.txt"));
    System.out.println("hello, 你好哇");
    System.out.close();
    
    PrintWriter pw = new PrintWriter(System.out);   //这里是在显示屏中输出
    pw.print("hi,这里是PrintWriter");
    pw.close();
    PrintWriter pw1 = new PrintWriter(new FileWriter("d:\\text1.txt"));     //这里是在文件中输出
    pw1.println("hi,这里是PrintWriter");
    pw1.close();
}

6、PROPERTIES 类

(1)基本介绍
  • 专门用于读写配置文件的集合类
  • 配置文件的格式为:
    • 键=值
  • 键与值不需要空格,值不需要引号一起来。默认类型是String
(2)常见方法
  • load:加载配置文件的键值对到Properties对象
  • list:将数据显示到指定的设备
  • getProperty(key):根据键获取值
  • setProperty(key,value):设置键值对到Properties对象中
  • store:将Properties中的键值对存储到配置文件,在idea中,保存信息到配置文件,如果含有中文,会存储为unicode编码

举例:

public static void main(String[] args) throws IOException {
    //使用Properties类来读取mysql.properties文件
    //1、创建Properties对象
    Properties properties = new Properties();
    //2、加载指定配置文件
    properties.load(new FileReader("src\\mysql.properties"));
    //3、把k-v显示到控制台
    properties.list(System.out);
    //4、根据key获取对应的值
    String user = properties.getProperty("user");
    String pwd = properties.getProperty("pwd");
    System.out.println("用户名:"+user);
    System.out.println("密码:"+pwd);

    //使用Properties 类来创建 配置文件, 修改配置文件内容
    //创建
    //1.如果该文件没有key 就是创建
    //2.如果该文件有key ,就是修改
    properties.setProperty("charset", "utf8");
    properties.setProperty("user", "汤姆");//注意保存时,是中文的 unicode 码值
    properties.setProperty("pwd", "888888");
    //将k-v 存储文件中即可
    properties.store(new FileOutputStream("src\\mysql2.properties"), null);
    System.out.println("保存配置文件成功~");
}

标签:文件,OutputStream,String,子类,Writer,System,println,new,out
From: https://blog.csdn.net/m0_46335449/article/details/136768003

相关文章

  • 线程工具类与原子类
    参考文档:CountDownLatch、CyclicBarrier、Semaphore的用法和区别juc15_基本AtomicInteger、数组、引用AtomicStampedReference、对象的属性修改原子类AtomicIntegerFieldUp、原子操作增强类LongAdder辅助工具类CountDownLatch(闭锁)做减法允许一个或多个线程等待直到......
  • 【C++】【OpenCV-4.9.0】视频写入(VideoWriter,借助samples中的代码示例来进行学习)
    借助官方离线文档中的samples来理解VideoWriter文档位置:samples/cpp/tutorial_code/videoio/video-write/video-write.cpp注:需要提前下载openh264-1.8.0-win64.dll,然后放在Release文件夹下,否则无法正确对输出文件进行编码从而运行失败1#include<iostream>2#include......
  • 七个子类视图 LL
     1)CreateAPIView提供post方法继承自:GenericAPIView、CreateModelMixin2)ListAPIView提供get方法继承自:GenericAPIView、ListModelMixin3)RetrieveAPIView提供get方法继承自:GenericAPIView、RetrieveModelMixin4)DestoryAPIView提供delete方法继承自:GenericAP......
  • 多线程系列(十六) -常用并发原子类详解
    一、简介在Java的java.util.concurrent包中,除了提供底层锁、并发同步等工具类以外,还提供了一组原子操作类,大多以Atomic开头,他们位于java.util.concurrent.atomic包下。所谓原子类操作,顾名思义,就是这个操作要么全部执行成功,要么全部执行失败,是保证并发编程安全的重要一环。相......
  • [译]The Day You Became A Better Writer
    这是在《纳瓦尔宝典》中提到的一篇文章,题目让我非常好奇。我对写作感兴趣,也想锻炼下英语,就决定翻译一下。TheDayYouBecameABetterWriterbyScottAdams当你成为一个更好的作者的那天-斯考特·亚当斯Iwentfrombeingabadwritertoagoodwriteraftertaking......
  • 子类包含父类成员的构造与析构顺序
    子类包含父类成员的构造与析构顺序#include<iostream>usingnamespacestd;classF1{public:F1(){cout<<"F1构造函数"<<endl;}~F1(){cout<<"F1析构函数"<<endl;}};classF2{public:F2(){cout<<"......
  • 原子类
    原子类目录原子类什么是原子类,有什么作用6类原子类纵览Atomic*基本类型,以AtomicInteger为例常用方法Atomic*Array数组类型原子类Atomic*Reference引用类型原子类把普通变量升级为原子类:用AtomicIntegerFieldUpdate升级原有变量Adder累加器Accumulator累加器什么是原子类,有什么作......
  • pd.ExcelWriter 实现数据写入不同sheet
    pd.ExcelWriter将数据写入不同sheet当结合for循环使用时,需注意放在for循环前面以下写法,仅生成一个sheet,原因在于pd.ExcelWriter的mode默认是w,每次for循环写入数据都会对原有的数据进行覆盖,最终只会生成一个sheet。importpandasaspddf1=pd.DataFrame([["AAA","BBB"]],......
  • C++多线程 第五章 C++内存模型和原子类型
    第五章C++内存模型和原子类型无论其他语言如何,C++是一门系统编程语言.委员会希望不再需要一个比C++低级的语言.内存模型基础C++程序中所有的数据均是由对象(object)组成的.C++标准定义对象为"存储区域",经管它会为这些对象分配属于它们的类型和生存期.无论什么类型,对象......
  • dremio CTAS STORE AS && WITH SINGLE WRITER 简单说明
    dremioCTAS支持存储格式以及写入的文件数量(相对分区还说)参考CTAS格式CREATETABLE"s3"."91733d30-d1d2-46bf-8f2b-3c34d587a96c"STOREAS(type=>'text',fieldDelimiter=>',',lineDelimiter=>'')WITHSINGLE......