关于IO流看这一篇就够了

14 篇文章 0 订阅
9 篇文章 0 订阅

IO流的介绍



一、简述IO

1.1 什么是IO

IO流,即input(输入)和output(输出)。
主要是用来进行数据的传输,比如我们日常下载东西和上传文件等,都是IO的表现。
我们可以把这种数据的传输看成是一种流向,以内存为基准,流向内存的叫做input(输入流),从内存流出的叫做output(输出流)

1.2 IO的分类

根据数据的流向可以分为输入流和输出流

输入流:把数据从其他设备读取到内存中的流。

输出流:把数据从内存的流中写入到其他设备。

根据数据的类型又可以分为字节流字符流

字节流:以字节为单位,读写数据的流。

字符流:以字符为单位,读写数据的流。

一张简单的图片来说明一下
在这里插入图片描述

1.3 IO的顶级父类们

字节输入流: java.io.InputStream
字节输出流: java.io.OutputStream

字符输入流: java.io.Reader
字符输出流: java.io.Writer

二、输入流

2.1 字节输入流

java.io.InputStream是一个抽象类,是所有字节输入流的父类。它定义了一些字节输入流的共性方法

public void close() 关闭此输入流并且释放掉所有与此流相关的系统资源

public abstract int read() 从此输入流读取数据的下一个字节

public int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中

close 方法,当完成流的操作以后,必须调用此方法释放系统资源,否则系统资源会一直被占用

2.2 FileInputStream

java.io.FileInputStream类是文件输入流,其作用是从文件中读取字节。

常用构造方法

FileInputStream(File file):通过打开和实际文件的连接来创建一个 FileInputStream ,该文件通过文件系统中的FIle对象 file 指定。

FileInputStream(String name):通过打开和实际文件的连接来创建一个 FileInputStream,该文件由文件系统中的路径名 name 来指定。

当指定的 FIle 文件找不到或者传入的name路径中的文件找不到的时候,系统会抛出 FileNotFoundException 异常

代码演示

读取字节

public class FISRead {
    public static void main(String[] args) throws IOException{
      	// 使用文件名称创建流对象
       	FileInputStream fis = new FileInputStream("read.txt");
      	// 读取数据,返回一个字节
        int read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
        read = fis.read();
        System.out.println((char) read);
      	// 读取到末尾,返回-1
       	read = fis.read();
        System.out.println( read);
		// 关闭资源
        fis.close();
    }
}
输出结果:
a
b
c
d
e
-1

// 优化代码
public class FISRead {
    public static void main(String[] args) throws IOException{
      	// 使用文件名称创建流对象
       	FileInputStream fis = new FileInputStream("read.txt");
      	// 定义变量,保存数据
        int b ;
        // 循环读取
        while ((b = fis.read())!=-1) {
            System.out.println((char)b);
        }
		// 关闭资源
        fis.close();
    }
}
输出结果:
a
b
c
d
e

使用字节数组读取

public class FisRead{
	public static void main(String[] args){
		FileInputStream fis =  new FileInputStream("read.txt"); // 该文件中放了abcde
		int len;
		byte[] b = new byte[2];
		while((len=fis.read(b)) != -1){
			 System.out.println(new String(b));
		}
		fis.close();
	}
}
输出结果:
ab
cd
ed

我们会发现多输出了一个d,这是因为最后一次读取的时候只读取到了一个字节e,而数组中上次读取的数据没有被完全替换,所以要通过len,获取有效字节

public class FISRead {
    public static void main(String[] args) throws IOException{
      	// 使用文件名称创建流对象.
       	FileInputStream fis = new FileInputStream("read.txt"); // 文件中为abcde
      	// 定义变量,作为有效个数
        int len ;
        // 定义字节数组,作为装字节数据的容器   
        byte[] b = new byte[2];
        // 循环读取
        while (( len= fis.read(b))!=-1) {
           	// 每次读取后,把数组的有效字节部分,变成字符串打印
            System.out.println(new String(b,0,len));//  len 每次读取的有效字节个数
        }
		// 关闭资源
        fis.close();
    }
}

输出结果:
ab
cd
e

2.3 字符输入流

在我们使用字节输出流的时候会遇到一个尴尬的问题,那就是遇到中文字符的时候,可能会导致不能显示完整的字符,因为一个中文字符占了好几个字节存储。所以Java中提供了一些字符流类,以字符为单位读写数据专门来处理文本文件。

java.io.Reader 抽象类是所有字符输入流的父类,可以去读取字符信息到内存中。它定义了一些字符输入流的共性方法。

public void close() 关闭此流并释放所有与此流相关的系统资源。

public int read() 从输入流读取一个字符。

public int read(char[] cbuf) 从输入流中读取一些字符,并将他们存储到字符数组 cbuf 中。

2.4 FileReader

java.io.FileReader类是读取字符文件的类。构造时使用系统默认的字符编码和默认字节缓冲区。

字符编码:字节和字符对应的规则。Window系统的中文编码默认是GBK编码表。在IDEA开发工具中默认编码是UTF-8。

字节缓冲区:一个字节数组,用来临时存储字节数据。

常用构造方法

FileReader(File file):创建一个新的 FileReader ,给定要读取的File对象。
FileReader(String fileName):创建一个新的 FileReader ,给定要读取的文件的名称。

使用方法和步骤和上面演示代码基本一致,这里不再进行演示

三、输出流

3.1 字节输出流

java.io.OutputStream抽象类是所有字节输出流的父类,它定义了一些基本的共性方法。

public void close():关闭此输入流并且释放所有与此流相关的系统资源。

public void flush() :刷新此输入流并强制任何缓冲的输入字节被写出。

public void writer(byte[] b):将 b.length长度的字节从指定的字节数组写入此输出流。

public void writer(byte[] b,int off, int len):从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。

3.2 FileOutputStream

java.io.FileOutputStream类是文件输出流,主要是用来将数据写出到文件。

常用构造方法
public FileOutputStream(File file) 创建文件输出流以写入由指定的 File对象表示的文件。

public FileOutputStream(String name) 创建文件输出流以指定的名称写入文件。

public FileOutputStream(File file, boolean append): 创建文件输出流以写入由指定的 File对象表示的文件。

public FileOutputStream(String name, boolean append): 创建文件输出流以指定的名称写入文件。

当我们创建一个输出流的时候,必须传入一个文件路径。与输入流不同的是,如果我们传入的路径下没有这个文件,那么则会创建该文件,如果有该文件,则会清空该文件的数据。

代码如下

public class FileOutputStreamConstructor throws IOException {
    public static void main(String[] args) {
   	 	// 使用File对象创建流对象
        File file = new File("a.txt");
        FileOutputStream fos = new FileOutputStream(file);
      
        // 使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("b.txt");
    }
}

代码演示


写出字节
public class FOSWrite {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("fos.txt");     
      	// 写出数据
      	fos.write(97); // 写出第1个字节
      	fos.write(98); // 写出第2个字节
      	fos.write(99); // 写出第3个字节
      	// 关闭资源
        fos.close();
    }
}
输出结果:
abc

// 优化代码

写出字节数组

public class FOSWrite {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("fos.txt");     
      	// 字符串转换为字节数组
      	byte[] b = "我爱写代码".getBytes();
      	// 写出字节数组数据
      	fos.write(b);
      	// 关闭资源
        fos.close();
    }
}
输出结果:
我爱写代码


写出指定长度的字节数组
public class FOSWrite {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("fos.txt");     
      	// 字符串转换为字节数组
      	byte[] b = "abcde".getBytes();
		// 写出从索引2开始,2个字节。索引2是c,两个字节,也就是cd。
        fos.write(b,2,2);
      	// 关闭资源
        fos.close();
    }
}
输出结果:
cd

数据追加续写

在我们上面的代码演示中,我们每次程序运行创建输出流对象,都会清空目标文件,那么我们怎么在保留原有文件数据的情况下,继续添加新数据呢?

代码演示

public class FOSWrite {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        // 参数中需要传入一个boolean类型的值,true表示为追加数据,false表示情况原有数据
        FileOutputStream fos = new FileOutputStream("fos.txt"true);     
      	// 字符串转换为字节数组
      	byte[] b = "abcde".getBytes();
		// 写出从索引2开始,2个字节。索引2是c,两个字节,也就是cd。
        fos.write(b);
      	// 关闭资源
        fos.close();
    }
}
文件操作前:cd
文件操作后:cdabcde

写出换行

public class FOSWrite {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        FileOutputStream fos = new FileOutputStream("fos.txt");  
      	// 定义字节数组
      	byte[] words = {97,98,99,100,101};
      	// 遍历数组
        for (int i = 0; i < words.length; i++) {
          	// 写出一个字节
            fos.write(words[i]);
          	// 写出一个换行, 换行符号转成数组写出
            fos.write("\r\n".getBytes());
        }
      	// 关闭资源
        fos.close();
    }
}

输出结果:
a
b
c
d
e
  • 回车符\r和换行符\n
    • 回车符:回到一行的开头(return)。
    • 换行符:下一行(newline)。
  • 系统中的换行:
    • Windows系统里,每行结尾是 回车+换行 ,即\r\n
    • Unix系统里,每行结尾只有 换行 ,即\n
    • Mac系统里,每行结尾是 回车 ,即\r。从 Mac OS X开始与Linux统一。

3.3 字符输出流

java.io.Writer抽象类是所有字符输出流的父类。它定义了字符输出流的基本共性方法。

void write(int c) 写入单个字符。

void write(char[] cbuf)写入字符数组。

abstract void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。

void write(String str)写入字符串。

void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。

void flush()刷新该流的缓冲。

void close() 关闭此流,但要先刷新它。

3.4 FileWriter

java.io.FileWriter类是写出字符到文件的类。构造时使用系统默认的字符编码和默认字节缓存区。

构造方法

FileWriter(File file): 创建一个新的 FileWriter,给定要读取的File对象。

FileWriter(String fileName): 创建一个新的 FileWriter,给定要读取的文件的名称。

使用方法和步骤和上面演示代码基本一致,这里不再进行演示

关闭和刷新

因为内置缓冲区的原因,如果不关闭输出流则无法写出数据到文件中。但是关闭的流对象是无法再次写出数据的。我们如果既想要写出数据,又想继续使用流,这时候就需要用到 flush 方法了。

flush :刷新缓冲区,流对象可以继续使用。

close:先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。

public class FWWrite {
    public static void main(String[] args) throws IOException {
        // 使用文件名称创建流对象
        FileWriter fw = new FileWriter("fw.txt");
        // 写出数据,通过flush
        fw.write('刷'); // 写出第1个字符
        fw.flush();
        fw.write('新'); // 继续写出第2个字符,写出成功
        fw.flush();
      
      	// 写出数据,通过close
        fw.write('关'); // 写出第1个字符
        fw.close();
        fw.write('闭'); // 继续写出第2个字符,【报错】java.io.IOException: Stream closed
        fw.close();
    }
}

四、IO的异常处理

JDK7之前的处理

我们之前使用的方法,都是把异常抛出,但是实际开发中并不能这样去处理,所以这里建议使用try...catch...finally 代码块,处理异常部分。

public class HandleException1 {
    public static void main(String[] args) {
      	// 声明变量
        FileWriter fw = null;
        try {
            //创建流对象
            fw = new FileWriter("fw.txt");
            // 写出数据
            fw.write("我爱写代码"); //我爱写代码
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fw != null) {
                    fw.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

总结

IO流是我们在日常开发中使用非常频繁的类,虽然它的分类有点多,但是都有异曲同工之妙,我们只需要多多练习就一定能够将其掌握~

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值