day19(下)_IO流4(InputStreamReader,OutputStreamWriter,流操作规律总结)
1.键盘录入与控制台输出:
/* 读取键盘录入 System.out:对应的是标准字节输出流,控制台 public static final PrintStream out //PrintStream extends FilterOutputStream “标准”输出流。此流已打开并准备接受输出数据。 通常,此流对应于显示器输出或者由主机环境或用户指定的另一个输出目标(System.setOut(PrintStream out))。 System.in:对应的是标准字节输入流,键盘 public static final InputStream in “标准”输入流。此流已打开并准备提供输入数据。 通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。(System.setOut(PrintStream out)) 也就是说之前通过字节读取流关联文件,这个关联的是键盘PrintStream:
为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。PrintStream
PrintStream
打印的所有字符都使用平台的默认字符编码转换为字节。*/
/* 需求: 通过键盘录入数据 当录入一行数据后,就将该行数据进行打印 如果录入的数据是over,那么停止录入 */ package standardin; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.nio.charset.Charset; class ReadIn{ public static void main(String[] args)throws IOException{ InputStream in=System.in;//in指向标准读取流对象 /* int b1=in.read(); int b2=in.read(); int b3=in.read(); System.out.println(b1+"\n"+b2+"\n"+b3);//测试回车 a\r\n 97 10 13 */ //由于读取个数不确定,那么不再定义缓冲区,使用StringBuilder StringBuilder sb=new StringBuilder(); while(true){ int aByte=in.read();//堵塞方法,会等待用户从键盘录入 if(aByte=='\r') continue; else if(aByte=='\n'){ String str=sb.toString(); if(str.equals("over")) break; else{ System.out.println(str); sb.delete(0,sb.length());//使用delete方法清容器中的字符序列 //不然下次输出含有上一行字符串 } } else sb.append((char)aByte); } //in.close();//可以不用close,键盘读取结束,会自动关闭该流对象 } }
注意:不能读取汉字,每次读一个字节,汉字使用的GBK编码为:2byte,无法解析.
2.转换流(InputStreamReader与InputStreamWriter)
/* 一.通过键盘录入一行数据打印 写的就是readLine方法的实现原理 readLine为BufferedReader类中的方法 键盘录入的read方法是字节流InputStream方法 1.为了使用readLine方法,是否能把字节流转换成字符流? InputStreamReader InputStreamReader 是字节流通向字符流的桥梁: 它使用指定的字符集(charset)读取字节并将其解码为字符。 它使用的字符集(GBK,utf-8,ASCII...)可以由名称指定或显式给定,或者可以接受平台默认的字符集。 2.为什么转换流定义在字符流体系中? 因为只有字节流的话根本不需要转换,出现了字符流 才需要转换. 3.每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。
在windows中文版默认为GBK编码,可以读取中文.*/ package transstream; import java.io.InputStreamReader; import java.io.BufferedReader; import java.io.IOException; import java.io.OutputStreamWriter; class InputStreamReaderDemo{ public static void main(String[] args)throws IOException{ //字节输入流->字符输入流(个人理解:在键盘敲入的字符,在计算机内部依然为字节,将字节通过字符集转换成相应字符) /* InputStream in=System.in;//获取键盘录入对象 InputStreamReader inr=new InputStreamReader(in);//创建一个使用默认字符集的 InputStreamReader BufferedReader bufr=new BufferedReader(inr);//为了提高效率,对转换流对象使用缓冲区技术->BufferedReader */ //简写为: BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in)); for(String line=null;(line=bufr.readLine())!=null;) if(line.equals("over")) break; else System.out.println(line.toUpperCase()); bufr.close(); } }
/* 二. 字符写入(输出)流->字节输出(写入)流 OutputStreamWriter: OutputStreamWriter 是字符流通向字节流的桥梁: 可使用指定的 charset 将要写入流中的字符编码成字节。 它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。 每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。 在写入底层输出流之前,得到的这些字节将在缓冲区中累积。 其实我们在将字符(汉字等)录入文件中,最终是以字节形式存储在磁盘上 而字节读取流->字符读取流从文件中读取的是字节,而使人们看到是 转换而来的字符(汉字等)... */ package transstream; import java.io.OutputStreamWriter; import java.io.InputStreamReader; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; class OutputStreamWriterDemo{ public static void main(String[] args){ //字符写入流->字节写入流 BufferedReader bufr=null; BufferedWriter bufw=null; try{ bufr=new BufferedReader(new InputStreamReader(System.in)); bufw=new BufferedWriter(new OutputStreamWriter(System.out)); for(String line=null;(line=bufr.readLine())!=null;) if(line.equals("over")) break; else{ bufw.write(line.toUpperCase()); bufw.newLine();//为了跨平台使用newLine写入一个行分隔符 bufw.flush();//字符流内部用的是字节流缓冲区,需要flush } } catch(IOException e){ e.printStackTrace(); } finally{ try{ if(bufr!=null) bufr.close(); } catch(IOException e){ e.printStackTrace(); } try{ if(bufw!=null){ bufw.close(); } } catch(IOException e){ e.printStackTrace(); } } } }
3.※IO流操作规律:
/* 流操作规律总结: 1.操作的数据时否是纯文本 是:字符流 否:字节流 2.明确源和目的 源:输入流:InputStream Reader 目的:输出流:OutputStream Writer 3.当体系明确后,在明确要使用那个具体对象 通过设备来进行区分 源设备:内存,硬盘,键盘 目的设备:内存,硬盘,控制台 */
/* 需求分析例子: 1.将一个文本文件中的数据存储到另一个文件中 源:InputStream/Reader 是不是操作文本文件: 是->Reader(明确体系) 接着使用体系中的那个对象? 明确设备:硬盘 Reader体系中可以操作文件的对象 FileReader 是否需要提高输入流效率?->是->BufferedReader BufferedReader bufr=new BufferedReader(new FileReader("test.txt")); 目的:OutputStream Writer 是否是纯文本 是->Writer 设备:硬盘上一个文件. Writer体系中可以操作的文件对象FileWriter. 是否需要提高输出流效率?->是->BufferedWriter BufferedWriter bufw=new BufferedWriter(new FileWriter("copy_test.txt")); */
/* 2.需求: 将键盘录入的数据保存到一个文件中. 这个需求中有源和目的都存在. 那么分别分析 源:InputStream Reader 是不是纯文本?是! Reader 设备:键盘.对应的对象System.in 为了操作键盘的文本数据方便. 字节流转成字符流按照字符串的操作是最方便的 使用Reader体系中的转换流,InputStreamReader 需要提高效率吗?->是->BufferedReader BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in)); 目的:OutputStream Writer 是否是纯文本? 是->Writer 设备:硬盘上的一个文件->FileWriter 需要提高效率->BufferedWriter BufferedWirter bufw=new BufferedWriter(new FileWriter("test.txt")); */
/* 扩展: 想要把录入的数据按照指定的编码表(例如:utf-8),将数据存到文件中 目的:OutputStream Writer 是否是纯文本? 是->Writer 设备:硬盘上的一个文件->FileWriter 需要提高效率->BufferedWriter 但是FileWriter使用的默认编码表GBK 但是在存储时,需要加入指定的编码表.而指定的编码表只有转换流可以指定 所以需要使用的对象是OutputStreamWriter 而该转换流对象要接收一个字节输出流,而且可以操作的文件的字节输出流->FileOutputStream OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("test.txt"),"UTF-8");osw.write(“abcd”);
数据进入转换流->把文本数据通过制定字符集转换为字节->写入字节流对象->写入关联文本中.
需要高效->BufferedWriter bufw=new BufferedWriter(osw); 转换流是字符和字节之间的桥梁,通常涉及到字符编码转换时,需要用到转换流 */对于以上代码示例:
package transstream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.FileOutputStream; class IOTrans{ public static void main(String[] args) throws IOException{ //操作数据:文本,源:Reader,设备:键盘,使用缓冲区 BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in)); //操作数据:文本,目的:Writer,设备:硬盘上一个文件,使用缓冲区 //需要用指定字符集,使用转换流. BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("Utf-8.txt"),"utf-8")); String line; while((line=bufr.readLine())!=null){ if(line.equals("over")) break; else bufw.write(line); bufw.newLine(); bufw.flush(); } bufr.close(); bufw.close() } }/* 分析了一下以上流的走向: bufr.readLine(),bufw.write(line);bufw.flush(); 从键盘录入数据---->标准字节输入流对象System.in->转换流对象->使用了默认字符集 将字节流转换成字符流-->字符流中数据读入缓冲区中-->在从缓冲区读取一行 -->将该行写入了输出缓冲区-->将缓冲区中的内容刷新到转换流中--> -->将字符流使用指定字符集转换成字节流->刷新到文件中 */
最后注意几点:
/* 使用转换流不指定字符集,使用平台默认的字符集(windows 7 中文->GBK) 分别向使用GBK和UTF-8的文件中写入数据时,由于编码不同 导致文件大小不同. FileReader只能使用系统默认编码表(GBK),将字节流->字符流 因此可以通过父类InputStream来指定编码表. */ /* public static void setIn(InputStream in) 重新分配“标准”输入流。 public static void setOut(PrintStream out) 重新分配“标准”输出流。 例如: System.setIn(new FileInputStream("read.txt"));//把源改为一个字节读取流 System.setOut(new PrintStream("write.txt"));//把目的改为一个字节写入流 那么程序中的System.in就代表了new FileInputStream("read.txt") System.out代表了new PrintStream("write.txt") */
4.异常日志信息建立(也就是把异常信息写入到.log文件中):
package exceptionmessage; import java.io.PrintStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.Calendar; import static java.util.Calendar.*; class ExceptionMessage{ public static void main(String[] args){ try{ int[] arr=new int[3]; System.out.println(arr[3]); } catch(Exception e){ PrintStream ps=null; OutputStreamWriter osw=null; try{ ps=new PrintStream("throw.txt"); //加上创建日期的时间利用Calendar Calendar cal=getInstance(); osw=new OutputStreamWriter(ps); String date=cal.get(YEAR)+"-"+(cal.get(MONTH)+1)+"-" +cal.get(DAY_OF_MONTH)+" "+cal.get(HOUR_OF_DAY) +":"+cal.get(MINUTE)+":"+cal.get(SECOND); osw.write(date+"\r\n"); osw.flush(); //写入异常信息 //e.printStackTrace();//输出到控制台上//相当于e.printStackTrace(System.out); e.printStackTrace(ps);//其上有异常声明 //将异常信息写入throw.txt /* //或者改变标准输出流 System.setOut(new PrintStream("throw.txt")); e.printStackTrace(System.out); */ } catch(Exception ex){ throw new RuntimeException("日志文件创建失败"); } finally{ try{ if(ps!=null) ps.close(); } catch(Exception e1){ e.printStackTrace(); } try{ if(osw!=null) osw.close(); } catch(Exception e2){ e.printStackTrace(); } } } } } /* 对于上面的日期也可以采用Date Date d=new Date(); SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//需要指定日期的格式 String date=sdf.format(d); ps.write(date.getBytes());//或 ps.println(date);//向文件中写入date并且有换行 */ /* 建立java日志信息:工具包log4j */
5.两个重要的系统信息:
package sysinfo; import java.util.Properties; import java.util.Map; import java.io.IOException; import java.io.PrintStream; class SystemInfo{ public static void main(String[] args)throws IOException{ Properties prop=System.getProperties(); /* //在System中写过,遍历系统信息 for(Map.Entry<Object,Object>me : prop.entrySet()) System.out.println(me.getKey()+"="+me.getValue()); */ //更简单方法 prop.list(System.out);//以一个列表的形式打印 //如果想把这些系统信息保存到文件中,更改输出流 PrintStream ps=new PrintStream("SysInfo.txt"); prop.list(ps); ps.close(); /* 注意到系统信息中的: sun.jnu.encoding=GBK//文件名称的编码 file.encoding=GBK//文件内容的编码 */ } }