黑马程序员——java基础——IO流(续)

来源:互联网 发布:win32 sdk编程 编辑:程序博客网 时间:2024/06/07 18:30

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------


一、IO流(续)

1、转换流

1)、转换流概要

        在IO字符流Reader与Writer子类中,还有两个常用的流InputStreamReader与OutputStreamWriter,称为转换流,它们是字节流通向字符流的桥梁。参看其构造方法可知,在创建其对象时,需要传入一个字节流对象,同时还可传入编码表字符串参数。其实我们常用的FileReader与FileWriter里面封装的是GBK码表,这里转换流提供了人为指定编码表的字符流对象,也就是说,转换流比常用的字符流更灵活,它提供了可选编码方式的功能。除了默认的GBK编码外,还可以选定ISO8859-1与UTF-8等编码表。

        从继承关系结构中可知,转换流是字符流的子类。因为转换流的出现就是针对字符的编码与解码问题的,所以从功能上来区分,其也应该隶属于字符流家庭。

2)、转换流的常用方法

        由于转换流隶属于字符流,所以其常用方法与字符流中的方法类似。

        下面的一段程序表示将文本文件数据显示在控制台,因为标准输出流对应的System.out是PrintStream类,该类是OutputStream流的子类,如果直接用字节流进行输出的话,就会出现乱码现象,所以这里采用了转换流的方式将其进行转换,参看如下代码:


import java.io.*;class TransStream {public static void main(String[] args) {BufferedReader bufr=null;BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));try{bufr=new BufferedReader(new InputStreamReader(new FileInputStream("E:\\1.txt")));String line=null;while((line=bufr.readLine())!=null){if("over".equals(line))break;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("读取流关闭失败!");}}}}


        下面的代码是将从键盘上输入的文本,一行一行写入到文件中,即按下回车,文本数据就写入到了文件中。由于这种读写方式是按行进行写入的,而标准的键盘录入System.in是InputStream字节流,没有按行读取的概念,只有BufferedReader中才具备readLine方法,而BufferedReader是用于增强字符流的,所以这里要用到转换流。参见下面的代码:


import java.io.*;class TransStream {public static void main(String[] args) {BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));BufferedWriter bufw=null;try{bufw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("1.txt")));String line=null;while((line=bufr.readLine())!=null){if("over".equals(line))break;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("读取流关闭失败!");}}}}

        下面的代码是将从键盘输入的字母转换为大写形式输出在控制台上,原理是一样的:


import java.io.*;class ReadIn {public static void main(String[] args) {try{InputStream is=System.in;InputStreamReader isr=new InputStreamReader(is);BufferedReader br=new BufferedReader(isr);String line=null;while((line=br.readLine())!=null){if("over".equals(line))break;System.out.println(line.toUpperCase());}}catch (IOException e){throw new RuntimeException("键盘读取失败!");}}}


import java.io.*;class ReadIn {public static void main(String[] args) {BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));String line=null;try{while((line=bufr.readLine())!=null){if("over".equals(line))break;bufw.write(line.toUpperCase());bufw.newLine();bufw.flush();}}catch (IOException e){throw new RuntimeException("键盘读取失败!");}}}


2、LineNumberReader

        缓冲流BufferedReader还有一个子类LineNumberReader,该类可以在读取文本数据时,可以按行设置初始行号,并获取行号。由于继承自BufferedReader自然有readLine方法,通过方法其void setLineNumber(int num)与int getLineNumber()可以设置和获取行号。该类比较简单,参看下面的代码:


import java.io.*;class LineNumberReaderDemo {public static void main(String[] args) {LineNumberReader lnr=null;try{lnr=new LineNumberReader(new FileReader("E:\\1.txt"));String line=null;lnr.setLineNumber(100);while((line=lnr.readLine())!=null){System.out.println(lnr.getLineNumber()+"   "+line);}}catch (IOException e){throw new RuntimeException("文件读取失败!");}finally{try{if(lnr!=null)lnr.close();}catch (IOException e){throw new RuntimeException("输入流关闭失败!");}}}}


3、Properties

        该类是java.util包中的一个工具类,并且是Hashtable类的子类,所以它有集合的性质,里面存储的元素也是以键值对的方式存在的,但键值对的元素类型仅限于String。另外这个类能关联IO流,也就是说,它可以将里面记录有键值对的文件加载到集合中,只需指定好输入流即可,非常方便。同时也可将内存中进行操作后的集合中的键值对存储到文件中,只需指定好输出流就行。该类可以说是集合与IO的桥梁。

        常用方法如下:

        String getProperty(String key) 用指定的键在此属性列表中搜索属性。

        Object setProperty(String key,String key) 调用 Hashtable 的方法 put

        void list(PrintStream out) 将属性列表输出到指定的输出流。

        void load(InputStream is) 从输入流中读取属性列表(键和元素对)。

        下面一个例子用来体现Properties类的作用,其中除了对其常用方法的掌握外,还实现了load方法原理的内部实现:


import java.util.*;import java.io.*;class PropertiesDemo {public static void main(String[] args) {//load的原理/*Properties prop=new Properties();BufferedReader bufr=null;try{bufr=new BufferedReader(new FileReader("E:\\info.txt"));//info文件中存储着键值对,如:张三=25String line=null;while((line=bufr.readLine())!=null){String[] info=line.split("=");prop.setProperty(info[0],info[1]);}System.out.println(prop);}catch (IOException e){throw new RuntimeException("文件关联失败!");}finally{try{if(bufr!=null)bufr.close();}catch (IOException e){throw new RuntimeException("读取流关闭失败!");}}*/Properties prop=new Properties();FileInputStream fis=null;FileOutputStream fos=null;try{fis=new FileInputStream("E:\\info.txt");prop.load(fis);prop.list(System.out);//打印在控制台上prop.setProperty("lisi","25");prop.list(System.out);fos=new FileOutputStream("E:\\info.txt");prop.store(fos,"lisi  modified");}catch (IOException e){throw new RuntimeException("文件关联失败!");}finally{try{if(fis!=null)fis.close();}catch (IOException e){throw new RuntimeException("读取流关闭失败!");}try{if(fos!=null)fos.close();}catch (IOException e){throw new RuntimeException("写出流关闭失败!");}}}}


        下面是利用Properties类进行软件次数的限制的模拟:


import java.io.*;import java.util.*;class RunCount {public static void main(String[] args) {File conf=new File("count.ini");//文件里面记录为如count=2FileInputStream fis=null;FileOutputStream fos=null;try{if(!conf.exists())conf.createNewFile();fis=new FileInputStream(conf);Properties prop=new Properties();prop.load(fis);int count=0;String value=prop.getProperty("count");if(value!=null){count=Integer.parseInt(value);if(count>=5){System.out.println("您好!使用次数已到,请充值!");return;}}count++;prop.setProperty("count",count+"");fos=new FileOutputStream(conf);prop.store(fos,"");}catch (IOException e){throw new RuntimeException("文件创建失败!");}finally{try{if(fos!=null)fos.close();}catch (IOException e){throw new RuntimeException("写出流关闭失败!");}try{if(fis!=null)fis.close();}catch (IOException e){throw new RuntimeException("读取流关闭失败!");}}}}


        System类中有一个Properties getProperties()方法来获取系统信息,也是键值对的表现形式:


import java.io.*;import java.util.*;class SysInfo {public static void main(String[] args) {Properties prop=System.getProperties();//记录了一些系统信息prop.list(System.out);/*try{prop.list(new PrintStream("SysInfo.txt"));//输出到一个文本文档中}catch (IOException e){throw new RuntimeException("文件创建失败!");}*/}}



4、合并流(序列流)

        在InputStream子类中,有一个合并流,也称序列流SequenceInputStream,其API中的一句话,SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。

        这里所说的输入流的有序集合,就是元素类型为输入流的集合。它在两个构造方法:

        SequenceInputStream(InputStream s1, InputStream s2)

        SequenceInputStream(Enumeration<? extends InputStream> e)

        其中前者是后者的一种情况之一罢了,Enumeration类提供了获取流对象的途径。Enumeration是一个接口,类似于Iterator,它的获取可以通过Vector中的Enumeration elements()方法,也可以通过自定义来实现,当然是借助了Iterator类。

        下面是一个将图片进行分割后合成的例子:


import java.io.*;import java.util.*;class SplitFile {public static void main(String[] args) {/*图片分割代码FileInputStream fis=null;FileOutputStream fos=null;try{fis=new FileInputStream("1.jpg");byte[] buf=new byte[1024*20];//每个碎片文件的大小为20Kint len=0;int count=0;while((len=fis.read(buf))!=-1){fos=new FileOutputStream(count+".fragment");//文件名为1.fragment、2.fragment等count++;fos.write(buf,0,len);fos.close();}}catch (IOException e){throw new RuntimeException("文件读写失败!");}finally{try{if(fis!=null)fis.close();}catch (IOException e){throw new RuntimeException("读取流关闭失败!");}try{if(fos!=null)fos.close();}catch (IOException e){throw new RuntimeException("写出流关闭失败!");}}*///下面是图片合成的代码List<FileInputStream> list=new ArrayList<FileInputStream>();try{list.add(new FileInputStream("0.fragment"));list.add(new FileInputStream("1.fragment"));list.add(new FileInputStream("2.fragment"));list.add(new FileInputStream("3.fragment"));}catch (IOException e){throw new RuntimeException("文件关联失败!");}final Iterator<FileInputStream> it=list.iterator();Enumeration<FileInputStream> en=new Enumeration<FileInputStream>(){//自定义Enumeration类,这里借助了Iteratorpublic boolean hasMoreElements(){return it.hasNext();}public FileInputStream nextElement(){return it.next();}};SequenceInputStream sis=null;FileOutputStream fos=null;try{sis=new SequenceInputStream(en);fos=new FileOutputStream("compound.jpg");byte[] buf=new byte[1024];int len=0;while((len=sis.read(buf))!=-1){fos.write(buf,0,len);fos.flush();}}catch (IOException e){throw new RuntimeException("文件读写失败!");}finally{try{if(fos!=null)fos.close();}catch (IOException e){throw new RuntimeException("写出流关闭失败!");}try{if(sis!=null)sis.close();}catch (IOException e){throw new RuntimeException("读取流关闭失败!");}}}}


5、管道流

        管道流常用于在两线程中进行数据的传输。同样分为管道字节流与管道字符流,比如,将数据写入管道输出流中后,可在管道输入流中进行数据的读取,前提是这两个管道流进行的连接。管道输入输出流的连接操作可在构造方法中传入对方(这种方法不常用),也可以用空参数的构造方法创建管道输入输出流之后,用void connect(PipedStream)方法连接对方。

        下面的例子很好的说明了这一现象:


import java.io.*;class Read implements Runnable{private PipedInputStream pis;public Read(PipedInputStream pis){this.pis=pis;}public void run(){byte[] buf=new byte[1024];int len=0;System.out.println("开始读取数据!");try{len=pis.read(buf);}catch (IOException e){throw new RuntimeException("读取数据失败!");}System.out.println("数据读取完毕!");System.out.println(new String(buf,0,len));}}class Write implements Runnable{private PipedOutputStream pos;public Write(PipedOutputStream pos){this.pos=pos;}public void run(){System.out.println("5秒后写入数据,进入阻塞!");try{Thread.sleep(5000);}catch (InterruptedException e){e.getMessage();}try{pos.write("hehehe".getBytes());}catch (IOException e){throw new RuntimeException("数据写出失败!");}System.out.println("数据写入完毕,解除阻塞!");}}class PipedStreamDemo{public static void main(String[] args) {PipedInputStream pis=null;PipedOutputStream pos=null;try{pis=new PipedInputStream();pos=new PipedOutputStream();pos.connect(pis);}catch (IOException e){throw new RuntimeException("管道连接失败!");}new Thread(new Write(pos)).start();new Thread(new Read(pis)).start();}}


6、打印流

        打印流PrintWriter是Writer的一个非常有用的子类,用于对数据进行输出,在其构造方法中可以传入文件对象,也可以传入路径名,而且既可包装字符流,也可包装字节流。其中可写入的数据类型除字符串外,还可写入基本数据类型。其最常用的特性就是在构造方法初始化对象时,可以设置自动刷新功能,打印一行自动进行刷新操作,免除了flush方法的麻烦,而且其println方法可以打印并自动写一个换行符,也免除了newLine方法的麻烦。

import java.io.*;class PrintWriterDemo {public static void main(String[] args) {BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));PrintWriter pw=new PrintWriter(System.out,true);//自动刷新String line=null;try{while((line=bufr.readLine())!=null){if("over".equals(line))break;pw.println(line.toUpperCase());//pw.flush();}}catch (IOException e){throw new RuntimeException("数据读写失败!");}//finally//{//}}}





0 0
原创粉丝点击