流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
IO流中使用了大量的装饰者模式
只要是处理纯文本数据,就优先考虑使用字符流。 除此之外都使用字节流。
1、字节流和字符流的基本操作是相同的,但是要想操作媒体流就需要用到字节流。
2、字节流因为操作的是字节,所以可以用来操作媒体文件。(媒体文件也是以字节存储的)
3、读写字节流:InputStream 输入流(读)和OutputStream 输出流(写)
4、字节流操作可以不用刷新流操作。
5、InputStream特有方法:
int available();//返回文件中的字节个数
注:可以利用此方法来指定读取方式中传入数组的长度,从而省去循环判断。但是如果文件较大,而虚拟机启动分配的默认内存一般为64M。当文件过大时,此数组长度所占内存空间就会溢出。所以,此方法慎用,当文件不大时,可以使用。
处理8位的字节
(该类中所有的方法遇到错误时都会抛出异常)
read()方法:从输入流中读取数据的下一个字节。返回0~255之间的int值、
read(byte[] b)方法 :从输入流中读取一定的字节长度,并以整数的形式返回字节数
mark(int readlimit)方法 :做标记
reset()方法:返回标记位
close()方法:关闭资源
复制一张图片F:\java_Demo\day9_28\1.BMP到F:\java_Demo\day9_28\2.bmp
import java.io.*; class CopyPic { public static void main(String[] args){ copyBmp(); System.out.println("复制完成"); } public static void copyBmp() { FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream("F:\\java_Demo\\day9_28\\1.bmp"); //写入流关联文件 fos = new FileOutputStream("F:\\java_Demo\\day9_28\\2.bmp"); //读取流关联文件 byte[] copy = new byte[1024]; int len = 0; while((len=fis.read(copy))!=-1) { fos.write(copy,0,len); } } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("复制文件异常"); } finally { try { if(fis!=null) fis.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException("读取流"); } } } }
write()方法:将指定的字节写入流中
write(byte [] b)方法: 将b个字节从指定的byte 数组写入此流
write(byte [] b, int off,int len)方法:将指定byte数组从off开始的len 个字节写入此输出流。
flush() 方法:完成输出并清空缓存区
close()方法:关闭输出流。
只提供字节的读取方法。
用File类创建一个文本对象:
File file =new File(“D:/1.txt”)
使用数据输入输出流,读取一个数据时不必在关心这个数值应当是那种字节
字符流只用来处理文本数据 处理16位的字符
* 写入文件后必须要用flush()刷新。
* 用完流后记得要关闭流
* 使用流对象要抛出IO异常
* 定义文件路径时,可以用“/”或者“\\”。
* 在创建一个文件时,如果目录下有同名文件将被覆盖。
* 在读取文件时,必须保证该文件已存在,否则出异常
read()方法:从输入流中读取数据的下一个字符。返回0~255之间的int值、
read(byte[] b)方法 :从输入流中读取一定的字符长度
mark(int readlimit)方法 :做标记
reset()方法:返回标记位
close()方法:关闭资源
write()方法:将指定的字符写入流中
write(byte [] b)方法: 将b个字符从指定的byte 数组写入此流
write(byte [] b, int off,int len)方法:将指定byte数组从off开始的len 个字符写入此输出流。
flush() 方法:完成输出并清空缓存区
close()方法:关闭输出流。
示例1:在硬盘上创建一个文件,并写入一些文字数据
class FireWriterDemo { public static void main(String[] args) throws IOException { //需要对IO异常进行处理 //创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。 //而且该文件会被创建到指定目录下。如果该目录有同名文件,那么该文件将被覆盖。 FileWriter fw = new FileWriter("F:\\1.txt");//目的是明确数据要存放的目的地。 //调用write的方法将字符串写到流中 fw.write("hello world!"); //刷新流对象缓冲中的数据,将数据刷到目的地中 fw.flush(); //关闭流资源,但是关闭之前会刷新一次内部缓冲中的数据。当我们结束输入时候,必须close(); fw.write("first_test"); fw.close(); //flush和close的区别:flush刷新后可以继续输入,close刷新后不能继续输入。 } }
示例2:FileReader的reade()方法.
要求:用单个字符和字符数组进行分别读取
class FileReaderDemo { public static void main(String[] args) { characters(); } /*****************字符数组进行读取*********************/ private static void characters() { try { FileReader fr = new FileReader("Demo.txt"); char [] buf = new char[6]; //将Denmo中的文件读取到buf数组中。 int num = 0; while((num = fr.read(buf))!=-1) { //String(char[] value , int offest,int count) 分配一个新的String,包含从offest开始的count个字符 sop(new String(buf,0,num)); } sop('\n'); fr.close(); } catch (IOException e) { sop(e.toString()); } } /*****************单个字母读取*************************/ private static void singleReader() { try { //创建一个文件读取流对象,和指定名称的文件关联。 //要保证文件已经存在,否则会发生异常:FileNotFoundException FileReader fr = new FileReader("Demo.txt"); //如何调用读取流对象的read方法? //read()方法,一次读取一个字符,并且自动往下读。如果到达末尾则返回-1 int ch = 0; while ((ch=fr.read())!=-1) { sop((char)ch); } sop('\n'); fr.close(); /*int ch = fr.read(); sop("ch=" + (char)ch); int ch2 = fr.read(); sop("ch2=" + (char)ch2); //使用结束注意关闭流 fr.close(); */ } catch (IOException e) { sop(e.toString()); } } /**********************Println************************/ private static void sop(Object obj) { System.out.print(obj); } }
示例3:对已有文件的数据进行续写
import java.io.*; class FileWriterDemo3 { public static void main(String[] args) { try { //传递一个参数,代表不覆盖已有的数据。并在已有数据的末尾进行数据续写 FileWriter fw = new FileWriter("F:\\java_Demo\\day9_24\\demo.txt",true); fw.write(" is charactor table?"); fw.close(); } catch (IOException e) { sop(e.toString()); } } /**********************Println************************/ private static void sop(Object obj) { System.out.println(obj); } }
练习:
将F盘的一个文件复制到E盘。
思考:
其实就是将F盘下的文件数据存储到D盘的一个文件中。
步骤:
1.在D盘创建一个文件,存储F盘中文件的数据。
2.定义读取流和F:盘文件关联。
3.通过不断读写完成数据存储。
4.关闭资源。
源码:
import java.io.*; import java.util.Scanner; class CopyText { public static void main(String[] args) throws IOException { sop("请输入要拷贝的文件的路径:"); Scanner in = new Scanner(System.in); String source = in.next(); sop("请输入需要拷贝到那个位置的路径以及生成的文件名:"); String destination = in.next(); in.close(); CopyTextDemo(source,destination); } /*****************文件Copy*********************/ private static void CopyTextDemo(String source,String destination) { try { FileWriter fw = new FileWriter(destination); FileReader fr = new FileReader(source); char [] buf = new char[1024]; //将Denmo中的文件读取到buf数组中。 int num = 0; while((num = fr.read(buf))!=-1) { //String(char[] value , int offest,int count) 分配一个新的String,包含从offest开始的count个字符 fw.write(new String(buf,0,num)); } fr.close(); fw.close(); } catch (IOException e) { sop(e.toString()); } } /**********************Println************************/ private static void sop(Object obj) { System.out.println(obj); } }
InputStreamReader 将字节输入流转化成字符输入流
OutputStreamReader 将字节输出流转化成字符输出流
1. 字符流的缓冲区:BufferedReader和BufferedWreiter
* 缓冲区的出现时为了提高流的操作效率而出现的.
* 需要被提高效率的流作为参数传递给缓冲区的构造函数
* 在缓冲区中封装了一个数组,存入数据后一次取出
BufferedReader示例:
读取流缓冲区提供了一个一次读一行的方法readline,方便对文本数据的获取。
readline()只返回回车符前面的字符,不返回回车符。如果是复制的话,必须加入newLine(),写入回车符
newLine()是java提供的多平台换行符写入方法。
class BufferedReaderDemo { public static void main(String[] args) throws IOException { //创建一个字符读取流流对象,和文件关联 FileReader rw = new FileReader("buf.txt"); //只要将需要被提高效率的流作为参数传递给缓冲区的构造函数即可 BufferedReader brw = new BufferedReader(rw); for(;;) { String s = brw.readLine(); if(s==null) break; System.out.println(s); } brw.close();//关闭输入流对象 } }
BufferedWriter示例:
import java.io.*; class BufferedWriterDemo { public static void main(String[] args) throws IOException { //创建一个字符写入流对象 FileWriter fw = new FileWriter("buf.txt"); //为了提高字符写入效率,加入了缓冲技术。 //只要将需要被提高效率的流作为参数传递给缓冲区的构造函数即可 BufferedWriter bfw = new BufferedWriter(fw); //bfw.write("abc\r\nde"); //bfw.newLine(); 这行代码等价于bfw.write("\r\n"),相当于一个跨平台的换行符 //用到缓冲区就必须要刷新 for(int x = 1; x < 5; x++) { bfw.write("abc"); bfw.newLine(); //java提供了一个跨平台的换行符newLine(); bfw.flush(); } bfw.flush(); //刷新缓冲区 bfw.close(); //关闭缓冲区,但是必须要先刷新 //注意,关闭缓冲区就是在关闭缓冲中的流对象 fw.close(); //关闭输入流对象 } }
一、两个明确:(明确体系) 1. 明确源和目的 源:输入流 InputStream Reader 目的:输出流 OutputStream Writer 2. 操作的数据是否是纯文本 是: 字符流 否: 字节流 二、明确体系后要明确具体使用的对象 通过设备区分:内存,硬盘,键盘 目的设备:内存,硬盘,控制台 示例1:将一个文本文件中的数据存储到另一个文件中: 复制文件 一、明确体系 源:文件-->读取流-->(InputStream和Reader) 是否是文本:是-->Reader 目的:文件-->写入流-->(OutputStream Writer) 是否纯文本:是-->Writer 二、 明确设备 源:Reader 设备:硬盘上一个文本文件 --> 子类对象为:FileReader FileReader fr = new FileReader("Goods.txt"); 是否提高效率:是-->加入Reader中的缓冲区:BufferedReader BufferedReader bufr = new BufferedReader(fr); 目的:Writer 设备:键盘上一个文本文件 --> 子类对象:FileWriter FileWriter fw = new FileWriter("goods1.txt"); 是否提高效率:是-->加入Writer的缓冲区:BufferedWriter BufferedWriter bufw = new BufferedWriter(fw); 示例2:将一个图片文件数据复制到另一个文件中:复制文件 一、明确体系 源:文件-->读取流-->(InputStream和Reader) 是否是文本:否-->InputStream 目的:文件-->写入流-->(OutputStream Writer) 是否纯文本:否-->OutputStream 二、 明确设备 源:InputStream 设备:硬盘上一个媒体文件 --> 子类对象为:FileInputStream FileInputStream fis = new FileInputStream("Goods.txt"); 是否提高效率:是-->加入InputStream中的缓冲区:BufferedInputStream BufferedInputStream bufi = new BufferedInputStream(fis); 目的:OutputStream 设备:键盘上一个媒体文件 --> 子类对象:FileOutputStream FileOutputStream fos = new FileOutputStream("goods1.txt"); 是否提高效率:是-->加入OutputStream的缓冲区:BufferedOutputStream BufferedOutputStream bufo = new BufferedOutputStream(fw); 示例3:将键盘录入的数据保存到一个文本文件中 一、明确体系 源:键盘-->读取流-->(InputStream和Reader) 是否是文本:是-->Reader 目的:文件-->写入流-->(OutputStream Writer) 是否纯文本:是-->Writer 二、 明确设备 源:InputStream 设备:键盘 --> 对用对象为:System.in --> InputStream 为了操作方便,转成字符流Reader --> 使用Reader中的转换流:InputStreamReader InputStreamReader isr = new InputStreamReader(System.in); 是否提高效率:是-->加入Reader中的缓冲区:BufferedReader BufferedReader bufr = new BufferedReader(isr); 目的:Writer 设备:键盘上一个文本文件 --> 子类对象:FileWriter FileWriter fw = new FileWriter("goods1.txt"); 是否提高效率:是-->加入Writer的缓冲区:BufferedWriter BufferedWriter bufw = new BufferedWriter(fw);
5.指定编码表(转换流可以指定编码表)
要求:用UTF-8编码存储一个文本文件
import java.io.*; public class IOStreamLaw { /** * @param args */ public static void main(String[] args) throws IOException { //键盘的最常见写法 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("goods1.txt"),"UTF-8")); String line = null; while((line=bufr.readLine())!=null){ if("over".equals(line)) break; bufw.write(line.toUpperCase()); bufw.newLine(); bufw.flush(); } bufr.close(); } }
八。格式化的输入输出。
stream 系列用来处理二进制数据
read write系列用来处理文本
判断方法:
九。流的应用
十。对象串行化
对象的寿命通常随着生成该对象的程序的终止而终止。有时候,可能需要将对象的状态保存下来,在需要时再将对象恢复。我们把对象的这种能记录自己的状态以便将来再生的能力。叫作对象的持续性(persistence)。对象通过写出描述自己状态的数值来记录自己,这个过程叫对象的串行化