一,概述
IO流(input output):用来处理设备之间的数据。
Java对数据的操作是通过流的方向。
Java用于操作流的对象都在IO包中。
流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
二,IO流的分类
根据处理数据类型的不同分为:字符流和字节流
根据数据流向不同分为:输入流和输出流
字符流的由来:在早期IO包中存在的都是字节流,因为无论是内存还是硬盘中的数据,它们的底层都是字节。随着编码技术的不断提高,人们陆续创造出了不同的编码表,【如:ASCII(美国信息交换标准代码),gb2312, GBK, unicode(国际标准码表:无论哪个字符都用两个字节表示),utf-8(国际标准码表的优化表:根据字符使用的字节长度来调整字节位数)】,但是当存储数据的计算机和取出数据的计算机使用的编码表不同时,就会造成取出数据的乱码情况。
为了解决这个乱码问题,Java就在字节流的基础上产生了一个字符流,而这个字符流的好处就是当读取数据时可以自己指定编码表。
字节流和字符流的区别:
(1)读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
字节流:一次读入或读出是8位二进制。字符流:一次读入或读出是16位二进制。
(2)处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
(3)字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流在操作的时候是会用到缓冲区的,是通过缓冲区来操作文件。
结论:只要是处理纯文本数据,就优先考虑使用字符流, 除此之外建议使用字节流。但字节流是通用的。
字节流的抽象基类:InputStream OutputStream
字符流的抽象基类:Reader Writer
注意:由这四个类派生出来的子类名称都是以其父类作为子类名的后缀。
如:InputStream的子类FileInputStream
Reader的子类FileReader
对输入流只能进行读操作,对输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。
三,Java IO体系
1.1字符流writer
Writer 写入字符流的抽象类。
它的子类有:
BufferedWriter 是一个装饰器为Writer 提供缓冲功能。
CharArrayWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。
FilterWriter
PipedWriter 是向与其它线程共用的管道中写入数据,
PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。
OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。功能和使用和OutputStream 极其类似,后面会有它们的对应图。
构造函数:
方法:
【演示案例】:在硬盘上创建一个文件并写入一些文字数据。
分析:因为是写操作,所以找到一个专门用于操作文件的Writer子类对象,FileWriter,(后缀名是父亲名,前缀名是该流对象的功能)
1 import java.io.FileWriter; 2 import java.io.IOException; 3 public class WriterDome { 4 public static void main(String[] args) throws IOException { 5 //创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。 6 //并且该文件会被创建到指定目录下,如果该目录下已有同名文件,将会被覆盖。 7 FileWriter fw=new FileWriter("C:\\html\\demo.txt"); 8 fw.write("abcde"); 9 //调用write方法,将字符串写入流中 10 fw.flush(); 11 //调用flush方法,刷新流对象的缓冲中的数据,将数据刷到目的地。 12 fw.close(); 13 //调用close方法,关闭流资源,但关闭之前会刷新一次内部缓冲中的数据。 14 } 15 }
【演示案例】: IO异常处理的方式:
1 import java.io.FileWriter; 2 import java.io.IOException; 3 public class WriterDome { 4 public static void main(String[] args) { 5 FileWriter fw=null; 6 try{ 7 fw=new FileWriter("C:\\html\\demo.txt"); 8 fw.write("abcdeljl"); 9 fw.flush(); 10 11 }catch (IOException e){ 12 System.out.println("写失败"); 13 } 14 finally {//finally中的代码不管前面try中的代码是否执行成功,finally中的代码总会执行。因此将关闭流的代码放在finally中 15 try{ 16 fw.close(); 17 }catch (IOException e){ 18 System.out.println("关闭失败"); 19 } 20 } 21 } 22 }
1.2字符流 Reader
Reader 是所有读取字符流的父类,它是一个抽象类。
它的子类有:
BufferedReader 很明显就是一个装饰器,它和其子类(LineNumberReader)负责装饰其它Reader 对象。
CharReader、StringReader是两种基本的介质流,它们分别将Char 数组、String中读取数据。PipedReader 是从与其它线程共用的管道中读取数据。
FilterReader 是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号。
InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。
FileReader可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。我们可以从这个类中得到一定的技巧。
Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。后面会有Reader 与InputStream 的对应关系。
构造函数:
方法:
【演示案例】:从文件中读取内容
1 import java.io.FileReader; 2 import java.io.IOException; 3 4 public class ReaderDemo { 5 public static void main(String[] args) throws IOException { 6 FileReader fr=new FileReader("c:\\html\\demo.txt"); 7 /** 8 * 一次读一个字符。 9 */ 10 int ch1=0;//因为read()方法返回的int型数据,所以定义一个int型数据接收 11 while ((ch1=fr.read())!=-1){ 12 // 调用read()方法,该方法返回的是本次读到的字符的整数型,当本次没有读到字符时,返回的是-1 13 System.out.println((char) ch1); //强转成char类型 14 } 15 16 /** 17 * 一次读多个字符。 18 */ 19 char[] buf=new char[1024];//定义一个字符 20 int num=0; 21 while ((num=fr.read(buf))!=-1){ 22 //调用read(char[] ch)方法,将读到的字符都存到ch数组中,该方法返回的是本次读到的字符的个数 23 //当本次没有读到字符时,返回的是-1 24 System.out.print(new String(buf,0,num));//将数组中的数据输出 25 } 26 fr.close(); 27 28 } 29 }
【演示案例】:将C盘的一个文本文档复制到D盘。
1 import java.io.FileReader; 2 import java.io.FileWriter; 3 import java.io.IOException; 4 5 public class CopyTxt { 6 public static void main(String[] args) throws IOException { 7 FileReader fr=new FileReader("c:\\html\\demo.txt"); 8 FileWriter fw=new FileWriter("D:\\demo\\demo.txt"); 9 char[] buf=new char[1024]; 10 while (fr.read(buf)!=-1){ 11 fw.write(buf);//fw.write(buf,0,num); 12 fw.flush(); 13 } 14 fr.close(); 15 fw.close(); 16 } 17 }
1.3字符流的缓冲区
缓冲区的出现提高了对数据的读写效率,其要结合流才可以使用,所以在创建缓冲区之前,必须先有流对象。它是在流的基础上对流的功能进行了增强,或者也可以说是对流对象的装饰。
缓冲区的对应类:BufferedWriter (后缀是父类,前缀是功能)
BufferedReader
缓冲区的原理:1、使用了底层流对象从具体设备上获取数据,并将数据存储到缓冲区的数组内。
2、通过缓冲区的read()方法从缓冲区获取具体的字符数据,这样就提高了效率。
3、如果用read方法读取字符数据,并存储到另一个容器中,直到读取到了换行符时,将另一个容器临时存储的数据转成字符串返回,就形成了readLine()功能。
1.3.1 字符流的缓冲区对象BufferedWriter
public class BufferedWriter extends Writer
(1)将文本写入字符输出流(一个数组中),缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
(2)可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
(3)该类在基类的基础上提供了 newLine() 方法,因为并非所有平台都使用新行符 (‘\r\n‘) 来终止各行。因此调用此方法来终止每个输出行,使代码具有跨平台性。
(4)通常 Writer 将其输出立即发送到底层字符或字节流。除非要求提示输出,否则建议用 BufferedWriter 包装所有其 write() 操作可能开销很高的 Writer(如 FileWriters 和 OutputStreamWriters)。例如,
PrintWriter out
= new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
(5)缓冲 PrintWriter 对文件的输出。如果没有缓冲,则每次调用 print() 方法会导致将字符转换为字节,然后立即写入到文件,而这是极其低效的。
【演示案例】:创建文件并写入内容。
1 import java.io.BufferedWriter; 2 import java.io.FileWriter; 3 import java.io.IOException; 4 5 public class BufferWeiterDemo { 6 public static void main(String[] args) throws IOException { 7 //创建一个字符写入流对象 8 FileWriter fw=new FileWriter("c:\\html\\demo.txt"); 9 //为了提高字符写入流的效率,加入缓冲技术。 10 //将需要提高效率的流对象作为参数提供给缓冲区的构造函数。 11 BufferedWriter buw=new BufferedWriter(fw); 12 13 for (int i = 0; i <5; i++) { 14 buw.write("aaa"+i); 15 buw.newLine();//作用等同于buw.write("\r\n");但是\r\n只是Windows系统的换行符,因此不具有跨平台性 16 buw.flush(); //写一次刷新一次,防止意外 17 } 18 buw.close(); 19 //关闭缓冲区就是在关闭缓冲区中的流对象 20 //因为真正实现写操作的是FileWriter对象,真正与文件相关联的也是FileWriter对象 21 } 22 }
1.3.2 字符流的缓冲区对象BufferedWriter
public class BufferedReader extends Reader
(1)从字符输入流(一个作为缓冲区的数组)中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
(2)可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
(3)在基类的基础上提供了readLine()方法(底层调用了read()方法),读取一个文本行,返回该行内容的字符串,不包括任何终止符。如果已到达流末尾,则返回null。
(4)通常,Reader 所作的每个读取请求都会导致对底层字符或字节流进行相应的读取请求。因此,建议用 BufferedReader 包装所有其 read() 操作可能开销很高的 Reader(如 FileReader 和 InputStreamReader)。例如,
BufferedReader in
= new BufferedReader(new FileReader("foo.in"));
(5)将缓冲指定文件的输入。如果没有缓冲,则每次调用 read() 或 readLine() 都会导致从文件中读取字节,并将其转换为字符后返回,而这是极其低效的。
【演示案例】:通过缓冲区从C盘复制文件到D盘。
1 import java.io.*; 2 3 public class BufferReaderDemo { 4 public static void main(String[] args) throws IOException { 5 //创建一个字符读取流对象 6 FileReader fr=new FileReader("c:\\html\\demo.txt"); 7 //创建一个字符写入流对象 8 FileWriter fw=new FileWriter("D:\\Demo\\demo.txt"); 9 //为了提高字符流的效率,加入缓冲技术。 10 //将需要提高效率的流对象作为参数提供给缓冲区的构造函数。 11 BufferedReader bur=new BufferedReader(fr); 12 BufferedWriter buw=new BufferedWriter(fw); 13 String str=null; 14 while ((str=bur.readLine())!=null){ 15 buw.write(str,0,str.length()); 16 buw.newLine();//因为readLine()方法读取的字符不包括换行符。 17 buw.flush(); 18 } 19 bur.close(); 20 buw.close(); 21 22 } 23 }
【演示案例】:模拟BufferedReader的底层代码
1 import java.io.FileReader; 2 import java.io.IOException; 3 import java.io.Reader; 4 5 class MyBufferedReaderDemo { 6 private Reader r=null; 7 public MyBufferedReaderDemo(Reader r){ 8 this.r=r; 9 } 10 public String myreadLine() throws IOException { 11 int str=0; 12 //定义一个临时容器,原BufferedReader中封装的是字符数组。 13 //但为了演示方便,此处定义了一个StringBuilder容器。 14 StringBuilder sb=new StringBuilder(); 15 while ((str=r.read())!=-1){ 16 if (str==‘\r‘) continue; 17 if (str==‘\n‘) return sb.toString(); 18 sb.append((char)str); 19 } 20 if (sb.length()!=0)return sb.toString(); 21 return null; 22 } 23 24 public void myclose() throws IOException { 25 r.close(); 26 } 27 } 28 public class MyBufferedReader{ 29 public static void main(String[] args) throws IOException{ 30 FileReader fr=new FileReader("c:\\html\\demo.txt"); 31 MyBufferedReaderDemo mbur=new MyBufferedReaderDemo(fr); 32 String str=null; 33 while ((str=mbur.myreadLine())!=null){ 34 System.out.println(new String(str)); 35 } 36 mbur.myclose(); 37 } 38 }
上述代码说明,1.BufferedReader中调用的read()方法是来自FileReader的。
2.只要关闭BufferedReader,就关闭了FileReader流对象,是因为在BufferedReader的close方法中,已经调用了FileReader的close方法。
3.BufferedReader就是FileReader流对象的装饰器,其实在BufferedReader中真正操作文件的还是FileReader。
1.3.3字符流的缓冲区对象BufferedWriter 的子类LineNumberReader
它是对缓冲区对象BufferedWriter的功能进行了增强, 是可以跟踪行号的缓冲字符输入流,此类定义了方法setLineNumber()和getLineNumber(),它们分别用于设置和获取当前行号。
setLineNumber()方法:设置当前行号。默认情况下是从0开始的。
getLineNumber()方法:获取当前行号。
【演示案例】:字符流的缓冲区对象BufferedWriter 的子类LineNumberReader
1 import java.io.FileReader; 2 import java.io.IOException; 3 import java.io.LineNumberReader; 4 5 public class LineNumberReaderDemo { 6 public static void main(String[] args) throws IOException { 7 FileReader fr=new FileReader("c:\\html\\demo.txt"); 8 LineNumberReader lnr=new LineNumberReader(fr); 9 String str=null; 10 lnr.setLineNumber(100); 11 while ((str=lnr.readLine())!=null){ 12 System.out.println(lnr.getLineNumber()+":"+str); 13 } 14 lnr.close(); 15 } 16 }
【演示案例】:模拟LineNumberReader的底层代码
1 import java.io.BufferedReader; 2 import java.io.FileReader; 3 import java.io.IOException; 4 import java.io.Reader; 5 6 class MyLineNumberReader extends BufferedReader{ 7 private int linenumber=0; 8 //private Reader r; 9 public MyLineNumberReader(Reader r){ 10 super(r); 11 } 12 public void setLinenumber(int i){ 13 this.linenumber=i; 14 } 15 public int getLinenumber(){ 16 return linenumber; 17 } 18 /*public void close() throws IOException { 19 super.close(); 20 }*///已被父类实现 21 public String readLine() throws IOException{ 22 linenumber++; 23 return super.readLine(); 24 } 25 } 26 public class MyLineNumberReaderDemo { 27 public static void main(String[] args) throws IOException{ 28 FileReader fr=new FileReader("c:\\html\\demo.txt"); 29 MyLineNumberReader mlnr=new MyLineNumberReader(fr); 30 String str=null; 31 mlnr.setLinenumber(100); 32 while ((str=mlnr.readLine())!=null){ 33 System.out.println(mlnr.getLinenumber()+":"+str); 34 } 35 mlnr.close(); 36 } 37 }
1.4字节流InputStream
public class FileInputStream extends InputStream
用于从文件系统中的某个文件中读取诸如图片,视频,音频之类数据的原始字节流,若要读取字符流,请考虑使用FileReader。
【演示案例】:使用字节流对象读取文件。
1 import java.io.FileInputStream; 2 import java.io.IOException; 3 4 public class FileInputStreamDemo { 5 public static void main(String[] args) throws IOException { 6 7 /** 8 *一次读取一个字节 9 */ 10 FileInputStream fis=new FileInputStream("c:\\html\\demo.txt"); 11 int num=0; 12 while ((num=fis.read())!=-1){ 13 System.out.print((char)num); 14 } 15 //因为字节流对象是读一个写一个,所以不存在刷新 16 fis.close(); 17 18 /** 19 * 一次读取多个字节:方法一 20 */ 21 FileInputStream fis=new FileInputStream("c:\\html\\demo.txt"); 22 byte[] buf=new byte[1024];//注意:字符流读入的是char[]数组,而字节流读入的是byte[]数组 23 int num=0; 24 while ((num=fis.read(buf))!=-1){ 25 System.out.println(new String(buf,0,num)); 26 } 27 //因为字节流对象是读一个写一个,所以不存在刷新 28 fis.close(); 29 30 /** 31 * 一次读取多个字节:方法一 32 */ 33 FileInputStream fis=new FileInputStream("c:\\html\\demo.txt"); 34 int num=fis.available();//返回字节的个数 35 byte[] buf=new byte[num];//注意:字符流读入的是char[]数组,而字节流读入的是byte[]数组 36 fis.read(buf); 37 System.out.println(new String(buf)); 38 //因为字节流对象是读一个写一个,所以不存在刷新 39 fis.close(); 40 } 41 } 42
【演示案例】:使用字节流对象复制图片。
1 import java.io.FileInputStream; 2 import java.io.FileOutputStream; 3 import java.io.IOException; 4 5 public class CopyPicture { 6 public static void main(String[] args) throws IOException { 7 FileInputStream fis=new FileInputStream("c:\\html\\picture.png"); 8 FileOutputStream fos=new FileOutputStream("D:\\demo\\picture.png"); 9 byte[] buf=new byte[1024]; 10 int len=0; 11 while ((len=fis.read(buf))!=-1){ 12 fos.write(buf,0,len); 13 } 14 fis.close(); 15 fos.close(); 16 17 } 18 }
public class BufferedInputStream extends FilterInputStream
该类为另一个输入流添加一些功能,即缓冲输入以及支持mark和reset方法的能力。在创建BufferedInputStream时会创建一个数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。mark操作记录输入流中的某个点,reset操作使得在从包含的输入流中获取新字节之前,在此读取自最后一次mark操作后读取的所有字节。
我们知道字节流对象一般读取到的都是一个字节,那为什么read()方法返回的为什么不是byte而是int呢?这是因为字节流对象读取的音频或图片文件,其中数据在底层都是以二进制的形式存储的,但是当字节流对象读取到的某个字节是11111111(8个1)时,转化成十进制就是-1,这与我们判断结束的条件是相同的(while ((num=bis.read(buf))!=-1){}),此时系统就会认为该文件内容已经读取完而停止继续读取,因而造成数据丢失。为了解决这种情况,就将需要返回的数据转化(提升)为int型数据(从一个字节提升为四个字节),并与上255,之后在返回。那为什么要与上255?这是因为byte型-1转化为int型后还是-1,但是与上255(或0xff)之后,数据大小没有变,且解决了-1的问题。
-1的问题解决了,那我们又不得不思考另一个问题,我们每次读取时,都读到的是一个字节,但是返回时返回的是四个字节,这样读取到的文件不就成原来文件的四倍了?所以为了解决这个问题,我们在调用写功能时,其底层又进行了强转(向下转型),因此就解决了文件扩大的问题。
【演示案例】:模拟BufferedInputStream底层代码。
1 import java.io.*; 2 class MyBufferedInputStream { 3 private InputStream ins; 4 private int pos=0; 5 private int count=0; 6 private byte[] buf=new byte[1024]; 7 public MyBufferedInputStream(InputStream in){ 8 this.ins=in; 9 } 10 public int read() throws IOException{ 11 if(count==0){ 12 count=ins.read(buf); 13 pos=0; 14 } 15 if(count<0) { 16 return -1; 17 } 18 byte b=buf[pos++]; 19 count--; 20 return b&255; 21 } 22 public void close()throws IOException{ 23 ins.close(); 24 } 25 } 26 27 public class FileOutputStreamDemo { 28 public static void main(String[] args) throws IOException { 29 FileOutputStream fos=new FileOutputStream("D:\\demo\\demo.txt");//写 30 FileInputStream fis=new FileInputStream("c:\\html\\demo.txt");//读 31 BufferedOutputStream bos=new BufferedOutputStream(fos); 32 MyBufferedInputStream bis=new MyBufferedInputStream(fis); 33 int buff=0; 34 while ((buff=bis.read())!=-1){ 35 bos.write(buff); 36 bos.flush(); 37 } 38 bis.close(); 39 bos.close(); 40 } 41 }
1.5.1字节流对象FileOutputStream
public class FileOutputStream extends OutputStream
用于将某个文件中诸如图片,视频,音频之类数据的原始字节流写入到另一个文件中。
1.5.2字节流缓冲对象BufferedOutputStream (装饰)
public class BufferedOutputStream extends FilterOutputStream
该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。
【演示案例】:使用字节流缓冲对象复制文件。
1 import java.io.*; 2 3 public class FileOutputStreamDemo { 4 public static void main(String[] args) throws IOException { 5 FileOutputStream fos=new FileOutputStream("D:\\demo\\demo.txt");//写 6 FileInputStream fis=new FileInputStream("c:\\html\\demo.txt");//读 7 BufferedOutputStream bos=new BufferedOutputStream(fos); 8 BufferedInputStream bis=new BufferedInputStream(fis); 9 byte[] buf=new byte[1024]; 10 int num=0; 11 while ((num=bis.read(buf))!=-1){ 12 bos.write(buf,0,num); 13 } 14 bis.close(); 15 bos.close(); 16 } 17 }
System类包含一些有用的类字短和方法。它不能被实例化。
字段in:“标准”输入流 。此流已打开并准备提供输入数据。通常,此流对应于键盘输入或有主机环境或用户指定的另一个输入源。
字段out:“标准”输出流。此流已打开棒准备接受输出数据。通常,此流对应于显示器输出或者由主机环境或用户指定的另一个输出目标。
方法:
setIn(InputStream in):重新分配标准输入流。
setout(PrintStream props):重新分配标准输出流。
【演示案例】:通过键盘录入数据。
public class SystemDemo { public static void main(String[] args)throws IOException { InputStream in=System.in;//in对象 int num=in.read();//read方法一次只接受一个字节 int num1=in.read(); int num2=in.read(); System.out.println(num); System.out.println(num1); System.out.println(num2); } }
注意:此处只输入了一个字母,却打印出三个数字,说明在windows系统中,换行符是存在的(\r \t)。
【演示案例】:setIn()和setOut()方法的使用。
1 import java.io.*; 2 public class SystemDemo { 3 public static void main(String[] args)throws IOException { 4 5 System.setIn(new FileInputStream("c:\\html\\demo.txt")); 6 System.setOut(new PrintStream("D:\\demo\\demo.txt")); 7 BufferedReader br=new BufferedReader(new InputStreamReader(System.in));//源为键盘录入 8 BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out)); 9 //目的为c盘文件 10 String str=null; 11 while ((str=br.readLine())!=null){ 12 if("over".equals(str)) 13 break; 14 bw.write(str); 15 bw.newLine();//换行 16 bw.flush(); 17 } 18 br.close(); 19 bw.close(); 20 } 21 }
1.7 转换流对象(键盘录入,转换编码表)
1.7.1 InputStreamReader是字节流通向字符流的桥梁:它使用指定的charset读取字节并将其解码为字符。
它使用的字符集可以由名称指定或显示给定,或者可以接受平台默认的字符集。
public class InputStreamReader extends Reader
【演示案例】:通过键盘录入数据(为编码简单,将字节流对象转化为字符流对象)。
1 import java.io.*; 2 3 public class SystemDemo { 4 public static void main(String[] args)throws IOException { 5 //获取键盘录入对象 6 InputStream in=System.in; 7 //将字节流对象转化为字符流对象,使用:InputStreamReader 8 //为了提高效率,使用字符缓冲对象。 9 BufferedReader br=new BufferedReader(new InputStreamReader(in)); //in取代了文件,之前是读取文件中的,现在是读取键盘输入的 10 String str=null; 11 while ((str=br.readLine())!=null){ 12 if ("over".equals(str)){ 13 break; 14 } 15 System.out.println(str); 16 } 17 } 18 }
1.7.2 OutputStreamWriter是字符流通向字节流的桥梁:它使用指定的charset将要写入流中的字符编码成字节。
public class OutputStreamWriter extends Writer
【演示案例】:通过控制台显示数据(为编码简单,将字符流对象转化为字节流对象)。
1 import java.io.*; 2 3 public class SystemDemo { 4 public static void main(String[] args)throws IOException { 5 6 //获取控制台显示对象 7 OutputStream out=System.out; 8 //将字符流对象转化为字字流对象,使用:OutputStreamWriter 9 //为了提高效率,使用字节缓冲对象。 10 BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(out));//之前是往文件里写,现在是往控制台写 11 String str=null; 12 bw.write("abcd"); 13 bw.flush();//因为是字符中,所以要刷新 14 bw.close(); 15 } 16 }
【演示案例】:将键盘录入的信息存储到指定文件中。
1 import java.io.*; 2 3 public class SystemDemo { 4 public static void main(String[] args)throws IOException { 5 6 BufferedReader br=new BufferedReader(new InputStreamReader(System.in));//源为键盘录入 7 BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("c:\\html\\demo.txt"),“utf-8")); 8 //目的为c盘文件 9 String str=null; 10 while ((str=br.readLine())!=null){ 11 if("over".equals(str)) 12 break; 13 bw.write(str); 14 bw.newLine();//换行 15 bw.flush(); 16 } 17 br.close(); 18 bw.close(); 19 } 20 }
注意:InputStreamReader可以自定义编码方式,但是它的子类FileReader中不可以自定义,默认为GBK。
【演示案例】:编写异常日志文件。
1 import java.io.*; 2 import java.util.Date; 3 4 public class IOExectionDemo { 5 public static void main(String[] args) { 6 try{ 7 int[] arr=new int[2]; 8 System.out.println(arr[3]);//此处数组越界 9 }catch (ArrayIndexOutOfBoundsException e){ 10 try{ 11 PrintStream ps=new PrintStream("C:\\html\\execption.txt"); 12 13 Date d=new Date() ; 14 //ps.println(d.toString());//同ps.write(d.toString().getBytes()); 15 16 System.setOut(ps); 17 //因为此处可能会出现找不到文件异常所以也要进行扑获 18 //setOut()方法指定输出流,此处指定为C盘的文本文件 19 e.printStackTrace(System.out); 20 //printStackTrace()方法的作用是将异常信息输出到指定的输出流中,默认为控制台 21 }catch (FileNotFoundException fe){ 22 throw new RuntimeException("日志文件创建失败"); 23 } 24 } 25 } 26 }
原文:https://www.cnblogs.com/ljl150/p/12321781.html