------- android培训、java培训、期待与您交流! ----------
IO流
IO流用来处理设备之间的数据传输
Java对数据的操作时通过流的方式
Java用于操作流的对象都存在IO包中
流是一种抽象概念,代表任何有能力产生数据的数据源对象或是有能力接受数据的接收端对象。“流”屏蔽了实际的I/O设备中处理数据的细节。这样我们在处理数据传输时,只需调用I/O对象,不需要关心设备是如何处理数据。
流按操作数据分为两种:字节流与字符流
流按流向分为:输入流,输出流
字符流
字符流可以一次处理一个字符,它底层仍是操作的字节。
字符流继承体系图
可以看出Reader和Writer是字符流的两个基类。BufferedWriter分别是个装饰类,目的是提高数据写入的速度。BufferedReader可以提高数据读取速度。FileWriter用于向文件中写入数据,它的父类OutputStreamWriter以指定的编码方式向目的写入数据,所以可以认为FileWriter就是一个用GBK编码方式进行数据操作的OutputStreamWriter。FileReader是用于读取数据,它的父类InputStreamReader也可指定编码方式。
Reader
用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。
Writer
写入字符流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。
FileWriter
用来写入字符文件的便捷类。可以将流中数据写入文件。
向文件写入数据的步骤
1.创建流对象,建立数据存放文件
FileWriter fw = new FileWriter(“Test.txt”);
2.调用流对象的写入方法,将数据写入流,可以写入字符,字符串,字符数组。
在字节流中,只能写入字节,字节数组。
fw.write(“text”);
3.关闭流资源,并将流中的数据清空到文件中。
fw.close();
java垃圾回收器只能回收java对象,而不能关闭底层资源。所以必须调用close方法关闭流对象。
练习
需求:在硬盘上,创建一个文件并写入一些文字数据。
import java.io.*; class FileWriterDemo { public static void main(String[] args) throws IOException { //创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。 //而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。 //其实该步就是在明确数据要存放的目的地。 FileWriter fw = new FileWriter("demo.txt"); //调用write方法,将字符串写入到流中。 fw.write("abcde"); //刷新流对象中的缓冲中的数据。 //将数据刷到目的地中。 //fw.flush(); //关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。 //将数据刷到目的地中。 //和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。 fw.close(); } }
IO异常的处理方式。
import java.io.*; class FileWriterDemo2 { public static void main(String[] args) { FileWriter fw = null; try { fw = new FileWriter("demo.txt"); fw.write("abcdefg"); } catch (IOException e) { System.out.println("catch:"+e.toString()); } finally { try { if(fw!=null)//判断fw是否指向了实体对象 fw.close();//最后必须关闭流,释放资源 } catch (IOException e) { System.out.println(e.toString()); } } } }
由于流必须关闭,所以讲关闭流的代码写在finally中。
FileReader
用来读取字符文件的便捷类。可以将文件中的字符读取到流中。
读取文件中数据的基本步骤
1.建立一个流对象,将已存在的一个文件加载进流。
FileReader fr = new FileReader(“Test.txt”);
2.向流中写入数据。
fr.read(ch);
3.关闭流资源。
fr.close();
缓冲区
缓冲区的出现是为了提高读写效率,原理是在内存中创建一个数组(大小为8192比特),需要进行数据写入时,先将数据放入数组中,直到数组装满或调用flush才将数据写入目的,而不是每写入一个字符都调用一次底层资源,这样就大大节约时间。
对应的类
字符写入流缓冲区:BufferedWriter
字符读取流缓冲区:BufferedReader
缓冲区要结合流才可以使用。.
在流的基础上对流的功能进行了增强,可以认为缓冲去是一种修饰类,用于增强已有对象的功能。
BufferedWriter 字符写入流缓冲区:
缓冲区的出现是为了提高流的操作效率而出现的。
所以在创建缓冲区之前,必须要先有流对象。
该缓冲区中提供了一个跨平台的换行符。
newLine();
import java.io.*; class BufferedWriterDemo { public static void main(String[] args) throws IOException { //创建一个字符写入流对象。 FileWriter fw = new FileWriter("buf.txt"); //为了提高字符写入流效率。加入了缓冲技术。 //只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。 BufferedWriter bufw = new BufferedWriter(fw); for(int x=1; x<5; x++) { bufw.write("abcd"+x); bufw.newLine(); bufw.flush(); } //记住,只要用到缓冲区,就要记得刷新。 //bufw.flush(); //其实关闭缓冲区,就是在关闭缓冲区中的流对象。 bufw.close(); } }
BufferedReader 字符读取流缓冲区:
该缓冲区提供了一个一次读一行的方法 readLine,方便于对文本数据的获取。
当返回null时,表示读到文件末尾。
readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。
import java.io.*; class BufferedReaderDemo { public static void main(String[] args) throws IOException { //创建一个读取流对象和文件相关联。 FileReader fr = new FileReader("buf.txt"); //为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。 BufferedReader bufr = new BufferedReader(fr); String line = null; while((line=bufr.readLine())!=null) { System.out.print(line); } bufr.close(); } }
缓冲区的原理是在内存中创建一个数组在提高效率。readLine方法一次读一行,原理是在内存中创建一个数组,直到换行或数据末尾才返回数组数据。换行标志为‘\r’和‘\n’,两个字符必须同时出现。
import java.io.*; //MyBuffereReader需要继承Reader //是因为BufferedReader继承了Reader,属于继承体系里面需要用到Reader的方法 class MyBufferedReader extends Reader { private Reader r; MyBufferedReader(Reader r) { this.r = r; } //可以一次读一行数据的方法。 public String myReadLine()throws IOException { //定义一个临时容器。原BufferReader封装的是字符数组。 //为了演示方便。定义一个StringBuilder容器。因为最终还是要将数据变成字符串。 StringBuilder sb = new StringBuilder(); int ch = 0; while((ch=r.read())!=-1) { if(ch=='\r') continue; if(ch=='\n') return sb.toString(); else sb.append((char)ch); } if(sb.length()!=0) return sb.toString(); return null; } /* 覆盖Reader类中的抽象方法。 */ public int read(char[] cbuf, int off, int len) throws IOException { return r.read(cbuf,off,len) ; } public void close()throws IOException { r.close(); } public void myClose()throws IOException { r.close(); } }
LineNumberReader
跟踪行号的缓冲字符输入流。 可以获取行号,也可以设置行号。
默认情况下,行编号从 0 开始。该行号随数据读取在每个行结束符处递增,并且可以通过调用 setLineNumber(int)
更改行号。但要注意的是,setLineNumber(int)
不会实际更改流中的当前位置;它只更改将由 getLineNumber() 返回的值。
public class LineNumberReaderDemo { public static void main(String[] args) throws IOException { FileReader fr = new FileReader("PersonDemo.java"); LineNumberReader lnr = new LineNumberReader(fr); String line = null; lnr.setLineNumber(100); while((line=lnr.readLine())!=null){ lnr.setLineNumber(100);//设置行号,但并不改变流中的位置 System.out.println(lnr.getLineNumber()+":"+line); } lnr.close(); } }
字节流
基本操作与字符流类相同,一次只能操作一个字节。但它不仅可以操作字符,还可以操作其他媒体文件,这是因为所有文件包括文本文件是由字节组成。
字节流继承体系图
InputStream和OutputStream是字节流的基类,其它子类都是已这两个类为父类,这些类的功能
和字符类中对应的类功能相似,只是字符流中的类只能处理文本数据,字节流中的类能处理所有数据。
InputStream
读取文件中数据的步骤与FileReader基本相同,read方法读取数据时,可以一次读一个字节,也可以一次读取一个数组的字节。
public static void readFile_1() throws IOException{ FileInputStream fis = new FileInputStream("fos.txt"); int ch = 0; //每次读一个数据,直到流的末尾返回-1 while((ch=fis.read())!=-1){ System.out.println((char)ch); } fis.close(); } //方法二 public static void readFile_2() throws IOException{ FileInputStream fis = new FileInputStream("fos.txt"); //创建一个数组,作为缓冲,可提供数据读取速度 byte[] buf = new byte[1024]; int len=0; while((len=fis.read(buf))!=-1){ System.out.println(new String(buf,0,len)); } } //方法三 public static void readFile_3() throws IOException{ FileInputStream fis = new FileInputStream("fos.txt"); //获取流中数据的大小,并创建一个相同大小的数组 //就可以一次读完数据,不用循环读。 byte[] buf = new byte[fis.available()]; fis.read(buf); System.out.println(new String(buf)); fis.close(); }
OutputStream
与FileWriter相似,将数据写入指定文件中。
public static void writeFile()throws IOException { FileOutputStream fos = new FileOutputStream("fos.txt"); fos.write("abcde".getBytes()); fos.close(); }
字节流缓冲区
原理也是通过在内存中创建一个数组中来提高数据读写速度。
通过在内存中创建数组来模拟字节流缓冲区
import java.io.IOException; import java.io.InputStream; public class MyBufferedInputStream { private InputStream in; private byte[] buf = new byte[1024*4]; private int pos =0,count = 0; MyBufferedInputStream(InputStream in){ this.in = in; } public int myRead() throws IOException{ if(count==0){ count = in.read(buf); if(count<0) return -1; pos = 0; byte b=buf[pos]; pos++; count--; return b&255; } else if(count>0){ byte b = buf[pos]; count--; pos++; return b&255; } return -1; } public void myClose() throws IOException { in.close(); } }
调用myRead方法时,首先判断数组中是否有数据,如果没有就将数据写入数组中,然后再从数组中读取数据。直到文件中数据末尾。
转换流
转换流是属于字符流体系的,但它是字节流和字符类之间的桥梁,所以很有必要单独介绍。
转换流对象
InputStreamReader
是字节流通向字符流的桥梁:它使用指定的编码方式读取字节并将其解码为字符。它使用的字符集可以由名
称指定或显式给定,或者可以接受平台默认的字符集(GBK)。
OutputStreamWriter
是字符流通向字节流的桥梁:可使用指定的编码方式将要写入流中的字符编码成字节。它使用的字符集可以
由名称指定或显式给定,否则将接受平台默认的字符集。
转换流用于字节流与字符流间的转换,字节流中的数据都是字符时,转成字符流操作更高效。
import java.io.*; class TransStreamDemo { public static void main(String[] args) throws IOException { //获取键盘录入对象。 InputStream in = System.in; //将字节流对象转成字符流对象,使用转换流。InputStreamReader InputStreamReader isr = new InputStreamReader(in); //为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader BufferedReader bufr = new BufferedReader(isr); //通过控制台输出 OutputStream out = System.out; //控制台只能打印字节,所以需要将字符转换为字节 OutputStreamWriter osw = new OutputStreamWriter(out); //加入缓冲区 BufferedWriter bufw = new BufferedWriter(osw); String line = null; while((line=bufr.readLine())!=null) { if("over".equals(line)) break; bufw.write(line.toUpperCase()); bufw.newLine(); bufw.flush(); } bufr.close(); } }
转换流中还可以指定编码方式
OutputStreamWriter(OutputStream out, Charset cs),创建使用给定字符集的OutputStreamWriter。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");
将以UTF-8的编码方式,将数据写入文件d.txt中。
如果没有指定编码方式,将使用默认编码方。默认编码方式为GBK。
标准输入输出流
System类中的字段:in,out。
它们各代表了系统标准的输入和输出设备。
默认输入设备是键盘,输出设备是显示器。
System.in的类型是InputStream.
System.out的类型是PrintStream是OutputStream的子类FilterOutputStream 的子类.
System类中提供了静态方法,可以更改标准输入和输出设备。
setIn(InputStream in)
重新分配“标准”输入流。
setOut(PrintStream out)
重新分配“标准”输出流。
例:获取键盘录入数据,然后将数据流向显示器,那么显示器就是目的地。
通过System类的setIn,setOut方法对默认设备进行改变。
System.setIn(new FileInputStream(“1.txt”));//将源改成文件1.txt。 System.setOut(new FileOutputStream(“2.txt”));//将目的改成文件2.txt
因为是字节流处理的是文本数据,可以转换成字符流,操作更方便。
BfferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
流的基本应用小节
流是用来处理数据的。
处理数据时,一定要先明确数据源,与数据目的地(数据汇)。
数据源可以是文件,可以是键盘。
数据目的地可以是文件、显示器或者其他设备。
而流只是在帮助数据进行传输,并对传输的数据进行处理,比如过滤处理.转换处理等。
------- android培训、java培训、期待与您交流! ----------