在JAVA 中把不同的输入输出源(键盘、文件、网路连接)抽象表述为“流”。一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。
Java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。
IO流的分类
根据处理数据类型的不同分为:字符流和字节流
* 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
* 字节流:一次读入或读出是8位二进制。
* 字符流:一次读入或读出是16位二进制。
* 处理对象不同:设备上的数据无论是图片或者视频,文字,它们都以二进制存储的。二进制的最终都是以一个8位为数据单元进行体现,所以计算机中的最小数据单元就是字节。意味着,字节流可以处理设备上的所有数据(如图片、avi等),而字符流只能处理字符类型的数据。只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。
根据数据流向不同分为:输入流和输出流
* 输入流只能进行读操作,输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。
IO流之字符流
字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。(我们的系统一般都是GBK编码)
字符流通过抽象基类Reader和Writer来操作,数据单元是16位的字符。
字符输入流FileReader类
* 功能:读数据一次读取一个字符
* 构造方法:
FileReader(String fileName)
FileReader(File file)
* 常用方法
int read() 读取单个字符,返回一个int型变量代表读取到的字符
int read(char [] c, int offset, int len) 读取字符到c数组,返回读取到字符的个数
void close() 关流释放系统底层资源
* FileReader读取文件步骤:
A: 创建输入流对象
B: 调用输入流对象的读数据方法
C: 释放资源
* 注意事项:
用完流后记得要关闭流
使用流对象要抛出IO异常
在读取文件时,必须保证该文件已存在,否则出异常
import java.io.FileReader; import java.io.IOException; import java.io.Reader; public class Test { public static void main(String[] args) throws IOException{ readFromFile(); } private static void readFromFile() throws IOException { //创建输入流对象 Reader reader = new FileReader("D:\\TEST.txt"); //调用输入流对象的读数据方法 char[] buf = new char[100]; reader.read(buf); StringBuffer s = new StringBuffer(); //如果读取数据的返回值是-1的时候,就说明没有数据了 while(reader.read(buf) != -1) s.append(buf); //释放资源 reader.close(); System.out.println(s.toString()); } }
字符输入缓冲流BufferedReader类
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取
* 缓冲区
缓冲区的出现是为了提高流的操作效率而出现的,相对于一个字符/字节地读取、转换、返回来说,它有一个缓冲区,在缓冲区中封装了一个数组,读满缓冲区才取出
需要被提高效率的流作为参数传递给缓冲区的构造函数;一般情况下,都建议使用它们把其它Reader/InputStream包起来,使得读取数据更高效。
* 常用方法
readline()一次读一行,方便对文本数据的获取。只返回回车符前面的字符,不返回回车符。如果是复制文本的话,必须加入 newLine(),写入回车符。readLine()方法是阻塞式的, 如果到达流末尾, 就返回null。
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.io.Reader; public class Test { public static void main(String[] args) throws IOException{ readFromFile(); } private static void readFromFile() throws IOException { Reader reader = new FileReader("D:\\TEST.txt"); BufferedReader bufr = new BufferedReader(reader); String s = null; while((s = bufr.readLine()) != null) { System.out.println(s); } reader.close(); } }
字符输出流FileWriter类
* 构造方法
FileWriter(String fileName)
FileWriter(File file)
* 常用方法
void write(String str) 向文件中写str
void flush() 将内存中的数据刷新到文件中
void close() 关流释放系统底层资源
* FileWriter向文件中写数据操作步骤:
A: 使用FileWriter流关联文件
B: 利用FileWriter的写方法写数据
C: 利用FileWriter的刷新方法将数据从内存刷到硬盘上
D: 利用FileWriter的关流方法将释放占用的系统底层资源
* 注意事项:
写入文件后必须要用flush()刷新
用完流后记得要关闭流
使用流对象要抛出IO异常
在创建一个文件时,如果目录下有同名文件将被覆盖
import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; public class Test { public static void main(String[] args) throws IOException{ writeToFile(); } private static void writeToFile() throws IOException { File file = new File("D:\\TEST.txt"); if (!file.exists()) { file.createNewFile(); } //创建输出流对象 Writer writer = new FileWriter(file, true); //写内容 writer.write("This\n is\n an\n example\n"); //清空缓冲区,立即将输出流里的内容写到文件里 writer.flush(); //关闭输出流,施放资源 writer.close(); } }
字符输出缓冲流BufferedWriter类
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
* 常用方法
newLine() 写一个换行符,这个换行符由系统决定,不同的操作系统newLine()方法使用的换行符不同(windows: \r\n|linux: \n|mac: \r)
import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; public class Test { public static void main(String[] args) throws IOException{ writeToFile(); } private static void writeToFile() throws IOException { Writer writer = new FileWriter("D:\\SAMPLE.txt", true); BufferedWriter bufw = new BufferedWriter(writer); bufw.write("hello"); bufw.newLine(); bufw.write("Hello again"); bufw.flush(); bufw.close(); } }
使用场景
* 文本复制
用FileReader和FileWriter实现文本复制
import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.io.Writer; public class Test { public static void main(String[] args) throws IOException{ copyFile(); } private static void copyFile() throws IOException { Reader reader = new FileReader("D:\\TEST.txt"); Writer writer = new FileWriter("D:\\copy.txt"); char[] temp = new char[1024]; while(reader.read(temp) != -1) { writer.write(temp); writer.flush(); } reader.close(); writer.close(); } }
用BufferedReader和BufferedWriter实现文本复制
import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.io.Writer; public class Test { public static void main(String[] args) throws IOException{ writeToFile(); } private static void writeToFile() throws IOException { Writer writer = new FileWriter("D:\\SAMPLE.txt", true); BufferedWriter bufw = new BufferedWriter(writer); Reader reader = new FileReader("D:\\TEST.txt"); BufferedReader bufr = new BufferedReader(reader); String temp = null; while((temp = bufr.readLine()) != null) { bufw.write(temp); bufw.newLine(); } bufr.close(); bufw.flush(); bufw.close(); } }
* 把集合中的数据写到文本文件
把ArrayList集合中的字符串数据存储到文本文件sample.txt中
每一个字符串元素作为文件中的一行数据
import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; public class Test { public static void main(String[] args) throws IOException { //创建集合对象 ArrayList<String> array = new ArrayList<String>(); //往集合中添加字符串元素 array.add("hello"); array.add("world"); array.add("java"); //创建输出缓冲流对象 BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\sample.txt")); //遍历集合,得到每一个字符串元素,然后把该字符串元素作为数据写到文本文件 for(String s: array) { bw.write(s); bw.newLine(); bw.flush(); } //释放资源 bw.close(); } }
* 把文本文件中的数据读取到集合
从sample.txt文本文件中读取数据到ArrayList集合中,并遍历集合,每一行数据作为一个字符串元素
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; public class Test { public static void main(String[] args) throws IOException { //创建输入缓冲流对象 BufferedReader br = new BufferedReader(new FileReader("D:\\sample.txt")); //创建集合对象 ArrayList<String> array = new ArrayList<String>(); //读取数据,每次读取一行数据,把该行数据作为一个元素存储到集合中 String line; while((line=br.readLine())!=null) { array.add(line); } //释放资源 br.close(); //遍历集合 for(int x=0; x<array.size(); x++) { String s = array.get(x); System.out.println(s); } } }
IO流之字节流
字节流通过抽象基类InputStream和OutputStream来操作,数据单元是8位的字节
* 字节流和字符流的基本操作是相同的,但是要想操作媒体流就需要用到字节流。
* 字节流因为操作的是字节,所以可以用来操作媒体文件。(媒体文件也是以字节存储的)
* 输入字节流 InputStream
- InputStream 是所有的输入字节流的父类,它是一个抽象类。
- ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer和本地文件中读取数据。
- PipedInputStream 是从与其它线程共用的管道中读取数据,与Piped 相关的知识后续单独介绍。
- ObjectInputStream 和所有FilterInputStream 的子类都是装饰流(装饰器模式的主角)。
* 输出字节流 OutputStream
- OutputStream 是所有的输出字节流的父类,它是一个抽象类。
- ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组和本地文件中写入数据。
- PipedOutputStream 是向与其它线程共用的管道中写入数据。
- ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流。
* 字节流操作可以不用刷新流操作。
字节输入流FileInputStream类
* 构造方法
FileInputStream(String fileName)
FileInputStream(File file)
* 常用方法
int read() 从 InputStream 对象读取一字节的数据;该方法返回整数,若读取的是字符串,则需强制转换;如果已经到结尾则返回-1
int read(byte[] r) 这个方法从输入流读取r.length长度的字节,返回读取的字节数。如果是文件结尾则返回-1
int available() 返回下一次对此输入流调用方法可以不受阻塞地从此输入流读取的字节数。注:可以利用此方法来指定读取方式中传入数组的长度,从而省去循环判断。但是如果文件较大,而虚拟机启动分配的默认内存一般为64M。当文件过大时,此数组长度所占内存空间就会溢出。所以,此方法慎用,当文件不大时,可以使用。
void close() 关流释放系统底层资源
字节输入缓冲流BufferedInputStream类
BufferedInputStream比FileInputStream多了一个缓冲区,执行read时先从缓冲区读取,当缓冲区数据读完时再把缓冲区填满。因此,当每次读取的数据量很小时,FileInputStream每次都是从硬盘读入,而BufferedInputStream大部分是从缓冲区读入。读取内存速度比读取硬盘速度快得多,因此BufferedInputStream效率高。BufferedInputStream的默认缓冲区大小是8192字节。当每次读取数据量接近或远超这个值时,两者效率就没有明显差别了。
常见应用
* 复制图片
用FileInputStream和FileOutputStream实现图片复制
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; public class Test { public static void main(String[] args) throws Exception { FileInputStream in = new FileInputStream(new File("D:\\test.jpg"));// 指定要读取的图片 File file = new File("D:\\copy.jpg"); if (!file.exists()) {// 如果文件不存在,则创建该文件 file.createNewFile(); } FileOutputStream out = new FileOutputStream(new File("D:\\copy.jpg"));// 指定要写入的图片 int n = 0;// 每次读取的字节长度 byte[] bb = new byte[1024];// 存储每次读取的内容 while ((n = in.read(bb)) != -1) { out.write(bb, 0, n);// 将读取的内容,写入到输出流当中 } out.close();// 关闭输入输出流 in.close(); } }
用BufferedInputStream和BufferedOutputStream实现图片复制
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; public class Test { public static void main(String[] args) throws Exception { // 指定要读取文件的缓冲输入字节流 BufferedInputStream in = new BufferedInputStream(new FileInputStream("F:\\test.jpg")); File file = new File("E:\\test.jpg"); if (file != null) { file.createNewFile(); } // 指定要写入文件的缓冲输出字节流 BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file)); byte[] bb = new byte[1024];// 用来存储每次读取到的字节数组 int n;// 每次读取到的字节数组的长度 while ((n = in.read(bb)) != -1) { out.write(bb, 0, n);// 写入到输出流 } out.close();// 关闭流 in.close(); } }