黑马程序员--IO(一)--概述、字符流、字节流、流操作规律
2015-11-10 14:09
429 查看
黑马程序员--IO(一)--概述、字符流、字节流、流操作规律
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
分类:
流按流分为:输入流和输出流。将外设中的数据读取到内存中:输入。将内存中数据写入到外设中:输出。
流按操作数据分为:字节流和字符流。
PS:
流只能操作数据,不能操作文件。
2、常用基类
字节流的抽象基类:InputStream OutputStream
字符流的抽象基类:Reader Writer
PS:
由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:Reader的子类FileReader。
由于字节流是单字节处理方式,当处理汉字这样双字节字符时,它就显得不太方便,这时我们通过字节流+编码表的方式获取字符流。
即让字节流读取文字字节数据后,不直接操作而是先查指定的编码表,获取对应的文字。来便捷文字操作。
字符流的抽象基类:Reader Writer
2、字符流的读写
读取方式有两种:
read():一次读一个字符。而且会自动往下读。
read(char[] cbuf):将字符读入数组。更优。
3、字符流的缓冲区-->BufferedWriter、BufferedReader
a 作用:在流的基础上对流的功能进行了增强。所以缓冲区创建之前,必须有对应的流对象。
b 原理:将数据以数组形式储存在内部,最后一次性取出。减少了数据的在内存上的读取频率,提高效率。
newLine():写入换行,返回数据及回车符。属于BufferedWriter类。可以跨平台。
readLine():读取一行数据。属于BufferedReader类。
原理:使用read方法,缓冲读取到的字符并判读换行标记,将标记前的缓冲数据变成字符串返回。
此类定义了方法setLineNumber(int)和getLineNumber(),它们可分别用于设置和获取当前行号。
1 缓冲区要结合流才可以使用。
2 无论是读一行还是多个字符,最终在硬盘上仍是一个一个读取。
3 read()和readLine()区别:
read():读取字符数据,它覆盖了父类的read方法。
readLine():另外开辟一个缓冲区,存储的是原缓冲区一行的数据,不包含换行符。
4、装饰设计模式
装饰设计模式:对原有类进行功能的改变、增强。装饰类和被装饰类通常都属于一个体系中。
装饰和继承比较:
Reader 专门用于读取数据的类。
|--TextReader:用于读取文本
|--MediaReader:用于读取媒体
功能扩展:提高读取效率,加入缓冲技术
Reader
|--TextReader
|--BufferTextReader
|--MediaReader
|--BufferMediaReader
加入再进行功能扩展,就会发现这个体系会越来越臃肿,不够灵活。
装饰体系思路:
既然加入的都是同一种技术--缓冲。继承是让缓冲和自己的流对象相结合。根据劳动分工,提高效率的特点。
我们可以将缓冲(同一属性的扩展功能)进行单独封装,各司其职,当需要时再针对性调用。
1、将缓冲进行单独封装
class Buffer
{
Buffer(TextReader text){}
Buffer(MediaReader media){}
}
2、优化。用多态封装,提高扩展性。
class BufferReader extends Reader
{
private Reader r;
BufferReader(Reader r){}
}
3、装饰体系
Reader 专门用于读取数据的类。
|--TextReader
|--MediaReader
|--BufferReader
由上面可知装饰和继承的异同:
相同点:都是用于功能的扩展。
不同点:
a 装饰扩展性更强;b 装饰避免了继承臃肿的体系;c 装饰降低了类之间的关联性。
d 装饰是对原有类的补充,继承是覆盖或者说是替代。
a 字节流:基本操作和字符流类相同。但它不仅可以操作字符,还可以操作其他媒体文件。
b 由于媒体文件数据都是以字节存储的,所以字节流对象可直接将媒体文件的数据写入到文件中,不用进行刷新动作。
c 字节流基类:InputStream(读)、OutputStream(写)
1 FileOutputStream、FileInputStream的flush方法内容为空,没有任何实现,调用没有意义。
2 int available():获取对象的数据大小。它是InputStream的特有方法。因为字节流可以操作媒体文件,所以直接获取数据大小,
可能因为获取的数据太大造成内存溢出。虚拟机默认内存是64M。
2、字节流的缓冲区:提高字节流读写效率。
2.1 读写存在类型提升和强转现象
read():会将字节byte类型提升为int类型。原因:防止直接返回byte类型值,造成read误判为程序结束标记的情形。
write():会将int类型强转为byte类型。原因:有始有终,保障数据唯一性。
它们的转变原理是:
因为数据的字节流形式是二进制:0,1;
该文件中,因为字节流中会存在一个字节全是1的情形:1111-1111
定理:负数的二进制等于整数二进制取反+1。
0000-0001 1的二进制
1111-1110 取反
0000-0001 +1
1111-1111 -1的二进制
因为返回指针值是byte类型,但是类的返回值是int类型,所以返回值存在类型提升问题。
这样定义其实是为了解决直接返回值为-1,造成read方法误判断为程序结束标记的情形。即:while((ch=fis.read())!=-1)
byte:-1 ----> int: -1;
00000000 00000000 00000000 11111111类型提升时,若补位为0,则值为 255
11111111 11111111 11111111 11111111 类型提升时,若补位为1,则值为 -1
当byte:-1提升到int类型,若补位为1,其值仍为-1。read方法以读到-1为停止标记,造成程序停
止,无法满足需求。
所以我们要在前面补0,这样就可以避免-1的出现。
补0方式:&255
11111111 11111111 11111111 11111111
& 00000000 00000000 00000000 11111111
------------------------------------------------------------
00000000 00000000 00000000 11111111
同时这也意味着,我们读取完后有4个字节需要写入,这样其实改变了原数据,
所以write实际执行时,会执行一个强转动作,只执行最后一个有效字节。
1.1 标准输入输出流
System.in:对应的标准输入设备:键盘。 它是InputStream类型。
System.out:对应的标准的输出设备,控制台。它是PrintStream类型。
1.2整行录入
当使用输入流进行键盘录入时,只能单字节录入。为了提高效率,可以自定义一个数组将一行字节进行储存。当一行录入完毕,
再放回本行录入内容。这种方式正是字符流的readLine方法的原理。
那我们为什么不直接使用readLine方法呢?但由于readLine方法是字符流BufferedReader类中方法。而键盘录入的read方法是字节流
InputStream的方法。这时我们必须将字节流转换成字符流再使用readLine方法。这样我们就用到了转换流。
1.3 转换流:InputStreamReader、OutputStreamWriter
作用:当字节流中数据都是字符时,将字节流转换成字符流。
1.3.1 InputStreamReader:将字节流转成字符流步骤:
a 获取键盘录入对象
InputStream in = System.in;
b 将字节流对象转成字符流对象,使用转换流。
InputStreamReader isr = new InputStreamReader(in);
c 为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
BufferedReader br = new BufferedReader(isr);
以上步骤可简化为:最常用方式
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
1.3.2 OutputStreamWriter:将字符流转成字节流。
以字符形式录入,以字节形式存储到硬盘。步骤和InputStreamReader相似。
2.1
源:键盘录入。
目的:控制台。
2.2 需求:想把键盘录入的数据存储到一个文件中。
源:键盘。
目的:文件。
文件是字符形式。使用InputStreamReader。
2.3 需求:想要将一个文件的数据打印在控制台上。
源:文件。
目的:控制台。
控制台获取的是字节形式。使用OutputStreamWriter。
2.4 如何选择流对象?
通过三个明确,确定流对象的使用:
a 源和目的。
源:读取流。InputStream Reader
目的:输出流。OutputStream Writer
b 明确体系:操作的数据是否是纯文本。
是:字符流
否:字节流
c 明确要使用的具体对象。通过设备来进行区分:
源设备:内存,硬盘,键盘。
目的设备:内存,硬盘,控制台。
2.5 事例分析:
2.5.1 需求:将一个文件中数据存储到另一个文件中。复制文件
1)源:读取流。InputStream Reader
明确体系:数据类型:纯文本:Reader
明确对象:硬盘上的一个文件。Reader体系中可以操作文件的对象是:FileReader。
FileReader fr = new FileReader("a.txt");
提高效率
BufferedReader bufr = new BufferedReader(fr);
2)目的:输出流:OutputStream Writer
明确体系:数据类型:纯文本:Writer
明确对象:硬盘上的一个文件。Writer体系中可以操作文件的对象FileWriter。
FileWriter fw = new FileWriter("b.txt");
提高效率
BufferedWriter bufw = new BufferedWriter(fw);
2.5.2 需求:将键盘录入的数据保存到一个文件中。
1)源:InputStream Reader
明确体系:数据类型:纯文本:Reader。
明确对象:键盘。对应的是System.in。
但Reader是字符流,System.in是字节流。为了操作键盘的文本数据,所以字符流最方便。
所以既然明确了Reader,那么就将System.in转换成Reader。用Reader体系中的转换流:InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
提高效率
BufferedReader bufr = new BufferedReader(isr);
2)目的:OutputStream Writer
明确体系:数据类型:纯文本:Writer。
明确对象:硬盘上的一个文件:FileWriter。
FileWriter fw = new FileWriter("c.txt");
提高效率
BufferedWriter bufr = new BufferedWriter(fw);
扩展:想要把录入的数据按照指定的编码表(utf-8)存到文件中。
2)目的:OutputStream Writer
明确体系:数据类型:纯文本:Writer。
明确对象:硬盘上的一个文件:FileWriter。
但是FileWriter是使用的默认编码表:GBK。但存储时,需要加入指定编码表utf-8。
而指定的编码表只有转换流可以指定。所以要使用的对象是OutputStreamWriter。
而该转换流对象要接受一个字节输出流。而且还可以操作的文件的字节输出流。FileOutputStream。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");
提高效率
BufferedWriter bufw = new BufferedWriter(osw);
![](http://img.blog.csdn.net/20151110143940841?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
PS:
1 转换流什么时候使用?
通常在涉及到字符编码转换时使用。它是字符和字节之间的桥梁。
2 异常日志信息
当程序在执行出现不希望直接给用户看的问题时,我们需要以异常日志的形式储存信息,方便程序员查看、调整。
Properties getProperties():获取系统信息。
void list(PrintStream out):将信息输出到指定输出流中。
new PrintStream("sysinfo.txt"):将输出流中数据存入指定文件中。
System.setIn(new FileInputStream("1.txt")):将源改成文件1.txt。
System.setOut(new FileOutputStream("2.txt")):将目的改成文件2.txt。
5 体系图
字节流继承体系图:
![](http://img.blog.csdn.net/20151110145326060?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
字符流继承体系图:
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
一、概述
1、IO流(Input Output):用来处理设备之间的数据传输。java对数据的操作通过流的方式。java用于操作流的对象都在IO包中。分类:
流按流分为:输入流和输出流。将外设中的数据读取到内存中:输入。将内存中数据写入到外设中:输出。
流按操作数据分为:字节流和字符流。
PS:
流只能操作数据,不能操作文件。
2、常用基类
字节流的抽象基类:InputStream OutputStream
字符流的抽象基类:Reader Writer
PS:
由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:Reader的子类FileReader。
二、字符流
1、简述由于字节流是单字节处理方式,当处理汉字这样双字节字符时,它就显得不太方便,这时我们通过字节流+编码表的方式获取字符流。
即让字节流读取文字字节数据后,不直接操作而是先查指定的编码表,获取对应的文字。来便捷文字操作。
字符流的抽象基类:Reader Writer
2、字符流的读写
读取方式有两种:
read():一次读一个字符。而且会自动往下读。
read(char[] cbuf):将字符读入数组。更优。
//字符流读取数据方式有两种 import java.io.*; class FileReaderDemo { public static void main(String[] args)throws IOException { //创建一个文件读取流对象和指定名称的文件相关联。 //要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException FileReader fr = new FileReader("demo.txt"); int ch = 0; //第一种方式:调用读取流对象的read()方法,它一次读一个字符。而且会自动往下读。 while((ch=fr.read())!=-1) { System.out.println("ch="+(char)ch); } FileReader fr2 = new FileReader("demo.txt"); //第二种方式:read(char[] cbuf):将字符读入数组。以数组形式读取,一次性输出。更优。 char[] buf = new char[1024]; int num = 0; while((num=fr2.read(buf))!=-1) { System.out.println(new String(buf,0,num)); } fr.close(); } }
/* 字符流:写入、续写、异常处理。 需求:在硬盘上,创建一个文件并写入一些文字数据。处理文字数据首先要考虑字符流。 FileWriter:专门用于操作文件的Writer子类对象。后缀名是父类名;前缀名是流对象功能。 FileWriter会将文件创建到指定目录下,如果该目录下已有同名文件,将被覆盖。 flush():用于对文件刷新。作用:将写入字符流输出到指定文件中。 close和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。 */ import java.io.*; class FileWriterDemo { public static void main(String[] args) { FileWriter fw = null; try { //创建一个FileWriter对象。初始化时必须明确被操作文件。在构造函数中加入true,可实现对文件续写。 fw= new FileWriter("demo.txt",true); //调用Write方法,字符串写入到流中。 fw.write("---www\r\neeeee"); } //处理异常 catch(IOException e) { System.out.println("wrong:"+e.toString()); } //用finally关闭流,可防止代码异常时流无法关闭的问题。 finally { try { if(fw!=null) //关闭流资源,但是关闭前会刷新一次内部的缓冲的数据。 fw.close(); } catch(IOException e) { System.out.println("wrong too:"+e.toString()); } } } }
3、字符流的缓冲区-->BufferedWriter、BufferedReader
a 作用:在流的基础上对流的功能进行了增强。所以缓冲区创建之前,必须有对应的流对象。
b 原理:将数据以数组形式储存在内部,最后一次性取出。减少了数据的在内存上的读取频率,提高效率。
newLine():写入换行,返回数据及回车符。属于BufferedWriter类。可以跨平台。
readLine():读取一行数据。属于BufferedReader类。
原理:使用read方法,缓冲读取到的字符并判读换行标记,将标记前的缓冲数据变成字符串返回。
//缓冲区的应用:通过缓冲区复制一个java文件 import java.io.*; class CopyByBuf { public static void main(String[] args) { //缓冲区要先初始化,不然作用域只在try{}范围内。 BufferedWriter bufw = null; BufferedReader bufr = null; try { //创建字符流缓冲区并加载字符流文件 bufr = new BufferedReader(new FileReader("helloworld.java")); bufw = new BufferedWriter(new FileWriter("hello_copy.txt")); String line = null; //写入信息 while((line=bufr.readLine())!=null) { bufw.write(line); bufw.newLine(); bufw.flush(); } } catch(IOException e) { throw new RuntimeException("读写失败!"); } finally { try { if(bufr!=null) bufr.close(); } catch(IOException e) { throw new RuntimeException("读取关闭失败!"); } finally { try { if(bufw!=null) bufw.close(); } catch(IOException e) { throw new RuntimeException("写入关闭失败!"); } } } } }LineNumberReader:跟踪行号的缓冲字符输入流。LineNumberReader是BufferedReader的子类。
此类定义了方法setLineNumber(int)和getLineNumber(),它们可分别用于设置和获取当前行号。
import java.io.*; class LineNumberReaderDemo { public static void main(String[] args)throws IOException { FileReader fr = new FileReader("helloworld.java"); //读取标的文件 LineNumberReader lnr = new LineNumberReader(fr); String line = null; //设置行号起点 lnr.setLineNumber(100); //获取行号 while((line=lnr.readLine())!=null) { System.out.println(lnr.getLineNumber()+":"+line); } lnr.close(); } }PS:
1 缓冲区要结合流才可以使用。
2 无论是读一行还是多个字符,最终在硬盘上仍是一个一个读取。
3 read()和readLine()区别:
read():读取字符数据,它覆盖了父类的read方法。
readLine():另外开辟一个缓冲区,存储的是原缓冲区一行的数据,不包含换行符。
4、装饰设计模式
装饰设计模式:对原有类进行功能的改变、增强。装饰类和被装饰类通常都属于一个体系中。
装饰和继承比较:
//装饰设计模式 class Person { public void chifan() { System.out.println("吃饭"); } } //继承方法-->覆盖 class NewPerson extends Person { public void chifan() { System.out.println("漱口"); super.chifan(); System.out.println("甜点"); } } //装饰类-->补充 class SuperPerson { private Person p; SuperPerson(Person p) { this.p = p; } public void superChifan() { //基于原来方法并给予丰富 System.out.println("漱口"); p.chifan(); System.out.println("甜点"); } } class DecorateDemo { public static void main(String[] args) { Person p = new Person(); NewPerson np = new NewPerson(); np.chifan(); System.out.println("-------------------"); SuperPerson sp = new SuperPerson(p); sp.superChifan(); } }继承的体系:
Reader 专门用于读取数据的类。
|--TextReader:用于读取文本
|--MediaReader:用于读取媒体
功能扩展:提高读取效率,加入缓冲技术
Reader
|--TextReader
|--BufferTextReader
|--MediaReader
|--BufferMediaReader
加入再进行功能扩展,就会发现这个体系会越来越臃肿,不够灵活。
装饰体系思路:
既然加入的都是同一种技术--缓冲。继承是让缓冲和自己的流对象相结合。根据劳动分工,提高效率的特点。
我们可以将缓冲(同一属性的扩展功能)进行单独封装,各司其职,当需要时再针对性调用。
1、将缓冲进行单独封装
class Buffer
{
Buffer(TextReader text){}
Buffer(MediaReader media){}
}
2、优化。用多态封装,提高扩展性。
class BufferReader extends Reader
{
private Reader r;
BufferReader(Reader r){}
}
3、装饰体系
Reader 专门用于读取数据的类。
|--TextReader
|--MediaReader
|--BufferReader
由上面可知装饰和继承的异同:
相同点:都是用于功能的扩展。
不同点:
a 装饰扩展性更强;b 装饰避免了继承臃肿的体系;c 装饰降低了类之间的关联性。
d 装饰是对原有类的补充,继承是覆盖或者说是替代。
三、字节流
1、简述a 字节流:基本操作和字符流类相同。但它不仅可以操作字符,还可以操作其他媒体文件。
b 由于媒体文件数据都是以字节存储的,所以字节流对象可直接将媒体文件的数据写入到文件中,不用进行刷新动作。
c 字节流基类:InputStream(读)、OutputStream(写)
//读取字节流方式 import java.io.*; class FileStream { public static void main(String[] args)throws IOException { writerFile(); readFile_1(); readFile_2(); readFile_3(); } //方法一:单个字节获取 public static void readFile_1()throws IOException { //读取指定文件字节流 FileInputStream fis = new FileInputStream("fos.txt"); int ch = 0; 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)); } fis.close(); } //方法三:以恰好容量数组读取。可能因为获取的数据太大造成内存溢出。 public static void readFile_3()throws IOException { FileInputStream fis = new FileInputStream("fos.txt"); //int num = fis.available(); //定义一个恰好的缓冲区,不用循环操作。 byte[] buf = new byte[fis.available()]; fis.read(buf); //System.out.println("num="+num); System.out.println(new String(buf)); fis.close(); } public static void writerFile()throws IOException { //输出字节流到指定文件 FileOutputStream fos = new FileOutputStream("fos.txt"); //不涉及任何转换,所以不用刷新。 fos.write("abcde".getBytes()); fos.close(); } }PS:
1 FileOutputStream、FileInputStream的flush方法内容为空,没有任何实现,调用没有意义。
2 int available():获取对象的数据大小。它是InputStream的特有方法。因为字节流可以操作媒体文件,所以直接获取数据大小,
可能因为获取的数据太大造成内存溢出。虚拟机默认内存是64M。
2、字节流的缓冲区:提高字节流读写效率。
2.1 读写存在类型提升和强转现象
read():会将字节byte类型提升为int类型。原因:防止直接返回byte类型值,造成read误判为程序结束标记的情形。
write():会将int类型强转为byte类型。原因:有始有终,保障数据唯一性。
/* 自定义字节流的缓冲区: 1,定义数组 2,定义指针 3,定义计数器。 */ import java.io.*; //装饰类 class MyBufferedInputStream { private InputStream in; private byte[] buf = new byte[1024]; private int pos = 0, count = 0; MyBufferedInputStream(InputStream in) { this.in = in; } //返回数据类型是int类型不是byte类型,这样避免了值为-1,正常情形下程序的停止。 public int myRead() throws IOException { //每句第一次读取数据的情形。通过in对象读取硬盘上数据,并存储在buf中。并计数。 if(count==0) { count = in.read(buf); if(count<0) return -1; pos = 0; //数组以byte类型存储。 byte b = buf[pos]; count--; pos++; //b&255,此时的b已经是int类型,它&255会只获取一个8位,补充位补0,防止-1的出现。 return b&255; } //每句话第二次读取数据的情形 else if(count>0) { byte b = buf[pos]; count--; pos++; //0xff=255 return b&0xff; } return -1; } public void myClose() throws IOException { in.close(); } }PS:
它们的转变原理是:
因为数据的字节流形式是二进制:0,1;
该文件中,因为字节流中会存在一个字节全是1的情形:1111-1111
定理:负数的二进制等于整数二进制取反+1。
0000-0001 1的二进制
1111-1110 取反
0000-0001 +1
1111-1111 -1的二进制
因为返回指针值是byte类型,但是类的返回值是int类型,所以返回值存在类型提升问题。
这样定义其实是为了解决直接返回值为-1,造成read方法误判断为程序结束标记的情形。即:while((ch=fis.read())!=-1)
byte:-1 ----> int: -1;
00000000 00000000 00000000 11111111类型提升时,若补位为0,则值为 255
11111111 11111111 11111111 11111111 类型提升时,若补位为1,则值为 -1
当byte:-1提升到int类型,若补位为1,其值仍为-1。read方法以读到-1为停止标记,造成程序停
止,无法满足需求。
所以我们要在前面补0,这样就可以避免-1的出现。
补0方式:&255
11111111 11111111 11111111 11111111
& 00000000 00000000 00000000 11111111
------------------------------------------------------------
00000000 00000000 00000000 11111111
同时这也意味着,我们读取完后有4个字节需要写入,这样其实改变了原数据,
所以write实际执行时,会执行一个强转动作,只执行最后一个有效字节。
四、流操作规律
1、键盘录入1.1 标准输入输出流
System.in:对应的标准输入设备:键盘。 它是InputStream类型。
System.out:对应的标准的输出设备,控制台。它是PrintStream类型。
1.2整行录入
当使用输入流进行键盘录入时,只能单字节录入。为了提高效率,可以自定义一个数组将一行字节进行储存。当一行录入完毕,
再放回本行录入内容。这种方式正是字符流的readLine方法的原理。
那我们为什么不直接使用readLine方法呢?但由于readLine方法是字符流BufferedReader类中方法。而键盘录入的read方法是字节流
InputStream的方法。这时我们必须将字节流转换成字符流再使用readLine方法。这样我们就用到了转换流。
1.3 转换流:InputStreamReader、OutputStreamWriter
作用:当字节流中数据都是字符时,将字节流转换成字符流。
1.3.1 InputStreamReader:将字节流转成字符流步骤:
a 获取键盘录入对象
InputStream in = System.in;
b 将字节流对象转成字符流对象,使用转换流。
InputStreamReader isr = new InputStreamReader(in);
c 为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
BufferedReader br = new BufferedReader(isr);
以上步骤可简化为:最常用方式
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
1.3.2 OutputStreamWriter:将字符流转成字节流。
以字符形式录入,以字节形式存储到硬盘。步骤和InputStreamReader相似。
//转换流演示 import java.io.*; class TransStreamDemo { public static void main(String[] args) throws IOException { //获取键盘录入对象 //InputStream in = System.in; //将字节流对象转成字符流对象,使用转换流--> InputStreamReader //InputStreamReader isr = new InputStreamReader(in); //加入缓冲区 //BufferedReader bufr = new BufferedReader(isr); //键盘的最常见写法。 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); //字符流转字节流。 //OutputStream out = System.out; //OutputStreamWriter osw = new OutputStreamWriter(out); //BufferedWriter bufw = new BufferedWriter(osw); BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out)); String line = null; while((line=bufr.readLine())!=null) { if("over".equals(line)) break; bufw.write(line.toUpperCase()); bufw.newLine(); bufw.flush(); } bufr.close(); } }2、流操作的基本规律:
2.1
源:键盘录入。
目的:控制台。
2.2 需求:想把键盘录入的数据存储到一个文件中。
源:键盘。
目的:文件。
文件是字符形式。使用InputStreamReader。
2.3 需求:想要将一个文件的数据打印在控制台上。
源:文件。
目的:控制台。
控制台获取的是字节形式。使用OutputStreamWriter。
2.4 如何选择流对象?
通过三个明确,确定流对象的使用:
a 源和目的。
源:读取流。InputStream Reader
目的:输出流。OutputStream Writer
b 明确体系:操作的数据是否是纯文本。
是:字符流
否:字节流
c 明确要使用的具体对象。通过设备来进行区分:
源设备:内存,硬盘,键盘。
目的设备:内存,硬盘,控制台。
2.5 事例分析:
2.5.1 需求:将一个文件中数据存储到另一个文件中。复制文件
1)源:读取流。InputStream Reader
明确体系:数据类型:纯文本:Reader
明确对象:硬盘上的一个文件。Reader体系中可以操作文件的对象是:FileReader。
FileReader fr = new FileReader("a.txt");
提高效率
BufferedReader bufr = new BufferedReader(fr);
2)目的:输出流:OutputStream Writer
明确体系:数据类型:纯文本:Writer
明确对象:硬盘上的一个文件。Writer体系中可以操作文件的对象FileWriter。
FileWriter fw = new FileWriter("b.txt");
提高效率
BufferedWriter bufw = new BufferedWriter(fw);
2.5.2 需求:将键盘录入的数据保存到一个文件中。
1)源:InputStream Reader
明确体系:数据类型:纯文本:Reader。
明确对象:键盘。对应的是System.in。
但Reader是字符流,System.in是字节流。为了操作键盘的文本数据,所以字符流最方便。
所以既然明确了Reader,那么就将System.in转换成Reader。用Reader体系中的转换流:InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
提高效率
BufferedReader bufr = new BufferedReader(isr);
2)目的:OutputStream Writer
明确体系:数据类型:纯文本:Writer。
明确对象:硬盘上的一个文件:FileWriter。
FileWriter fw = new FileWriter("c.txt");
提高效率
BufferedWriter bufr = new BufferedWriter(fw);
扩展:想要把录入的数据按照指定的编码表(utf-8)存到文件中。
2)目的:OutputStream Writer
明确体系:数据类型:纯文本:Writer。
明确对象:硬盘上的一个文件:FileWriter。
但是FileWriter是使用的默认编码表:GBK。但存储时,需要加入指定编码表utf-8。
而指定的编码表只有转换流可以指定。所以要使用的对象是OutputStreamWriter。
而该转换流对象要接受一个字节输出流。而且还可以操作的文件的字节输出流。FileOutputStream。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");
提高效率
BufferedWriter bufw = new BufferedWriter(osw);
/* 练习:将键盘录入的数据按照utf-8编码表存入文件中。 思路: 1)源:InputStream Reader 明确体系:数据类型:纯文本:Reader。 明确对象:键盘:System.in。因为是文本数据,Reader最好操作, 所以需要借助Reader体系中的转换流:InputStreamWriter。 BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); 2)目的:OutputStream Writer 明确体系:数据类型:纯文本:Writer 明确对象:硬盘上的文件:FileWriter。但是FileWriter是使用的默认编码表:GBK。因为存储时需要加入 指定编码表utf-8。而指定的编码表只有转换流可以指定。所以要使用的对象是OutputStreamWriter。 而该转换流对象要接受一个字节输出流。而且还可以操作的文件的字节输出流。FileOutputStream。 BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(),"UTF-8")); */ import java.io.*; class TransStreamDemo1 { public static void main(String[] args) throws IOException { //键盘录入的最常见写法: BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("lady.txt"),"UTF-8")); String line = null; while((line=bufr.readLine())!=null) { if("over".equals(line)) break; bufw.write(line); bufw.newLine(); bufw.flush(); } bufr.close(); } }运行结果:
PS:
1 转换流什么时候使用?
通常在涉及到字符编码转换时使用。它是字符和字节之间的桥梁。
2 异常日志信息
当程序在执行出现不希望直接给用户看的问题时,我们需要以异常日志的形式储存信息,方便程序员查看、调整。
//异常的日志信息独立反映。 import java.io.*; import java.util.*; import java.text.*; class ExceptionInfoDemo { public static void main(String[] args)throws IOException { try { int[] arr = new int[2]; System.out.println(arr[3]); } catch(Exception e) { try { Date d = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//H:24小时制 String s = sdf.format(d); PrintStream ps = new PrintStream("exeception.log"); ps.println(s); System.setOut(ps); } catch(IOException ex) { throw new RuntimeException("日志文件创建失败"); } e.printStackTrace(System.out); } } }3 系统属性信息文本
Properties getProperties():获取系统信息。
void list(PrintStream out):将信息输出到指定输出流中。
new PrintStream("sysinfo.txt"):将输出流中数据存入指定文件中。
// getProperties():确定当前的系统属性。 import java.util.*; import java.io.*; class SystemInfo { public static void main(String[] args)throws IOException { Properties prop = System.getProperties(); prop.list(new PrintStream("sysinfo.txt")); } }4 通过System类的setIn、setOut方法可以对默认设备进行改变。
System.setIn(new FileInputStream("1.txt")):将源改成文件1.txt。
System.setOut(new FileOutputStream("2.txt")):将目的改成文件2.txt。
5 体系图
字节流继承体系图:
字符流继承体系图:
相关文章推荐
- 转:女程序员的微博
- 成为专业程序员的6个技巧
- 黑马程序员_java多线程的同步和死锁
- 黑马程序员_自定义异常
- 老程序员应该记住的 5 件事
- 黑马程序员_继承
- 黑马程序员_IO流BufferWriter、BufferReader
- 黑马程序员-java多线程
- Reverse Linked List
- 黑马程序员-Java异常处理机制
- 黑马程序员_MRC2
- 程序员学习能力提升三要素
- 2015(2016届)校园招聘季——百度 篇
- 黑马程序员-Java面向对象
- 培养程序员的人脉
- 2015求职经历
- 武汉软件工程职业学院与传智播客签约达成深度校企合作
- 程序员 应该关注那些事
- [一心想做张江程序员]Infopath设置Develop开发工具集成
- 为什么中国的程序员总被称为码农?