天天看点

Java基础之IO流知识点总结二

字节流的缓冲区
缓冲区的出现提高了对流的操作效率。
原理:其实就是将数组进行封装。
对应的对象:
   BufferedWriter:
      特有方法:newLine():跨平台的换行符。
   BufferedReader:
        特有方法:readLine():一次读取一行,到行标记时,将行标记之前的字符数据作为字符串返回。当读到末尾时,返回full。
在使用缓冲区对象时,要明确,缓冲的存在是为了增强流的功能而存在,所以在建立缓冲区对象时,要先有流对象的存在。
其实缓冲区内部就是在使用流对象的方法,只不过加入了数组对数据进行了临时存储,为了提高操作数据的效率。
代码上的体现:
写入缓冲区对象。
//建立缓冲区对象必须把流对象作为参数传递给缓冲区的构造函数。
BufferedWriter bw = new BufferedWriter(newFileWriter(“buf.txt”));
//将数据写入到了缓冲区
bw.writer(“itheima”);
//对缓冲区的数据进行刷新,将数据刷到目的地
bw.flush();
//关闭缓冲区,其实是关闭了被包装在内部的流对象。
bw.close();      
例子1:利用字节流的缓冲区将数据写入到一个文本文件中。      
package cn.itheima.day03;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
/**
 * 缓冲区的出现时为了提高流的操作效率而出现的。
 * 所以,在创建缓冲区是必须先有流对象。
 * @author wl-pc
*/
public class BufferedWriterDemo {
	public static void main(String[] args) {
		FileWriter fw=null;
		BufferedWriter bw=null;
		try {
			//1.创建一个字符写入流对象
		    fw = new FileWriter("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\buf.txt");
			//为了提高字符的写入流效率,加入了缓冲技术,只要将需要提
			//高效率的流对象作为参数传递给缓冲区的构造函数即可
			bw = new BufferedWriter(fw);
			for(int x = 0; x < 5; x++ ){
				bw.write("itheima"+x+",helloworld!");
				bw.newLine();   //跨平台的换行
				//记住:只要用到缓冲区就需要刷新
				bw.flush();
			}	
		} catch (IOException e) {
			System.out.println(e.toString());
		} finally{
			if(bw!=null){
				try {
					//关闭缓冲区的流对象其实关闭的是缓冲区中的写入流对象
					//所以在这里只需要关闭缓冲区流即可
					fw.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
例子2:利用字符读取流的缓冲区读取一个.java的文件显示到控制台上。      
package cn.itheima.day03;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
 * 字符读取流的缓冲区
 * 该缓冲区提供了一次读取一行的方法,方便了对文本数据的获取。
 * readLine()方法,当返回空时,表示读到了文件的末尾
 * @author wl-pc
*/
public class BufferedReaderDemo {
	public static void main(String[] args) {
		FileReader fr=null;
		BufferedReader br=null;
		try {
			//创建一个读取流对象,和文件相关联
			fr = new FileReader("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\BufferedWriterDemo.java");
	        //为了提高效率,加入了缓冲技术,将字符读取流对象传递给缓冲对象的构造函数。
			br = new BufferedReader(fr);
			String line=null;
			try {
				while((line = br.readLine())!=null){    //readLine一行一行的读取数据
					System.out.println(line);
				}
			} catch (IOException e) {
				System.out.println(e.toString());
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		}finally{
			if(br!=null){
				try {
					br.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
例子3:通过缓冲区的方式,对文本文件进行拷贝。      
package cn.itheima.day03;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
 * 通过缓冲区复制一个*.java的文件
 * @author wl-pc
 * readLine()方法返回的时候,只返回回车符之前的数据内容,并不返回回车符。
 */
public class CopyTextByBuf {
	public static void main(String[] args) {
		BufferedReader bufr = null;
		BufferedWriter bufw = null;
			try {
			bufr=new BufferedReader(new FileReader("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\BufferedWriterDemo.java"));
		     bufw=new BufferedWriter(new FileWriter("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\BufferedWriter_copy.txt"));
			    String line = null;   //临时数据的中转站
			    while((line = bufr.readLine())!=null){
			    	bufw.write(line);
			    	bufw.newLine();   //跨平台换行
			    }	
			} catch (FileNotFoundException e) {
				System.out.println(e.toString());
			} catch (IOException e) {
				System.out.println(e.toString());
			}finally{
				if(bufr!=null){
					try {
						bufr.close();
					} catch (IOException e) {
						System.out.println("close:"+e.toString());
					}
				}
				if(bufw!=null){
					try {
						bufw.close();
					} catch (IOException e) {
						System.out.println("close:"+e.toString());
					}
				}
			}
	  }
}
           
readLine()方法的原理:
其实缓冲区中的readLine()方法,用的还是与缓冲区关联的流对象的read()方法。只不过,每一次读到一个字符,先不进行具体的操作,先进行临时存储。当读到回车标记时,将临时容器中存储的数据一次性的返回。
既然明确了原理,我们也可以实现一个类似的功能方法。      
例子4:自定义一个类中包含一个功能和readLine()一致的方法来模拟一下BufferedReader      
package cn.itheima.day03;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
 * 明白了BufferedReader类中特有的方法readLine()的原理后,
 * 可以自定义一个类中包含一个功能和readLine()一致的方法
 * 来模拟一下BufferedReader
 */
class MyBufferedReader{
	private FileReader fr;
	public MyBufferedReader(FileReader fr) {
		this.fr = fr;
	}
	//可以一次读一行数据的方法
	public String myReaderLine() throws IOException{
        //定义一个临时容器,原BufferedReader封装的是字符数组,
		//为了演示方便,定义了一个StringBuilder容器,因为最终还是要将数据变成字符串
		StringBuilder sb = new StringBuilder(); 
		int ch = 0;
			while((ch=fr.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;
	}
	//定义我的关闭流的方法
	public void myClose() throws IOException{	
	    fr.close();
	}
}
//主函数入口点
public class MyBufferedReaderDemo {
	public static void main(String[] args) {
		FileReader fileReader=null;
		MyBufferedReader mbr=null;
		try {
			fileReader = new FileReader("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\buf.txt");
			mbr = new MyBufferedReader(fileReader);
			String line = null;
			try {
				while((line=mbr.myReaderLine())!=null){
					System.out.println(line);
				}
			} catch (IOException e) {
				System.out.println(e.toString());
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} finally{
			if(mbr!=null){
				try {
					mbr.myClose();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
由例子4可以看出:readLine()方法的出现实际上是在增强read()方法的功能,增强的方式是把被增强的对象传给增强类。这也是一种设计模式:装饰设计模式。
装饰设计模式:当想要对已有的对象进行功能增强时,可以定义类,将已有的对象传入,基于已有的功能,并提供加强功能,那么自定义的这个类就叫装饰类。即:对一组对象的功能进行增强时,就可以使用该模式进行问题的解决。装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。      
例子5:定义一个装饰类的实现      
package cn.itheima.day03;
class Person{
	public void 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("甜点");
		System.out.println("来一根烟");
	}
}
public class PersonDemo {
	public static void main(String[] args) {
		Person p = new Person();
		SuperPerson sp = new SuperPerson(p);
		sp.superChifan();
	}
}
           
装饰和继承都能实现一样的特点:进行功能的扩展增强,但是装饰比继承灵活,装饰的特点:装饰类和被装饰类都必须所属同一个接口或者父类。
下面举一个例子:
      Writer
          |--MediaWriter
          |--TextWriter
(注意:MediaWriter和TextWriter两个类在JDK中并不存在,为了是更形象举例说明而“创建”的,在这里不要误解)
需求:想要对数据的操作提高效率,就用到了缓冲技术。
通过所学习的继承特性。可以建立子类复写父类中的write方法。即可
 
Witer(注:不要误解,以下的两个对象在JDK中是不存在的,只为举例说明)
  |-- MediaWriter
         |--BufferedMediaWriter
  |-- TextWriter
         |--BufferedTextWriter
当Writer中子类对象过多,那么为了提高每一个对象效率,每一个对象都有一个自己的子类Buffered。
虽然可以实现,但是继承体系变的很臃肿。
 
那么是否可以对其进行一下优化呢?
其实子类都是在使用缓冲技术。
可不可以对缓冲技术进行描述,将需要增强的对象传递给缓冲区即可。
classBufferdWriter{
      BufferedWriter(MediaWritermw){ } 
      BufferedWriter(TextWritermw){ } 
}
但是发现该方法缺点:该类虽然完成了对已有两个对象的增强。
但是当有新的对象出现时,还要继续在该类中添加构造函数。这样不利于扩展和维护。
还有一个方法就是:将对这些对象父类型进行操作即可。这就是多态,提高了程序的扩展性。同时BufferedWriter中一样具体write方法,只不过是增强后的write。所以BuferedWriter也应该是Writer中的一个子类。
classBufferedWriter extends Writer{
     private Writer w;
     BufferedWriter(Writer w){
         this.w = w;
     }
}
 
即体系变成如下格式:(变化:从继承结构变为组合结构)
Writer
     |--MediaWriter
     |--TextWriter
     |--BufferedWriter
这样就会发现装饰设计模式,优化增强功能的部分。比继承要灵活很多。而且降低了类与类之间的关系。
但是要注意:装饰类因为增强了已有对象,具备的功能和已有的功能是相同的,只不过提供了更强的功能,所以,装饰类可被装饰类通常是都属于一个体系中的。      
例子6:利用装饰类定义一个功能readLine()一致的方法来模拟一下BufferedReader      
package cn.itheima.day03;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
/**
 * 明白了BufferedReader类中特有的方法readLine()的原理后,
 * 可以自定义一个类中包含一个功能和readLine()一致的方法
 * 来模拟一下BufferedReader
 */
class MyBufferedReader2 extends Reader{
	private Reader fr;
	public MyBufferedReader2(Reader fr) {
		this.fr = fr;
	}
	//可以一次读一行数据的方法
	public String myReaderLine() throws IOException{
        //定义一个临时容器,原BufferedReader封装的是字符数组,
		//为了演示方便,定义了一个StringBuilder容器,因为最终还是要将数据变成字符串
		StringBuilder sb = new StringBuilder(); 
		int ch = 0;
			while((ch=fr.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;
	}
	//定义我的关闭流的方法
	public void myClose() throws IOException{	
	    fr.close();
	}
	@Override
	public void close() throws IOException {
		fr.close();
	}
	@Override
	public int read(char[] cbuf, int off, int len) throws IOException {
		return fr.read(cbuf,off,len);
	}
}
//主函数入口点
public class MyBufferedReaderDemo2 {
	public static void main(String[] args) {
		FileReader fileReader=null;
		MyBufferedReader2 mbr=null;
		try {
			fileReader = new FileReader("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\buf.txt");
			mbr = new MyBufferedReader2(fileReader);
			String line = null;
			try {
				while((line=mbr.myReaderLine())!=null){
					System.out.println(line);
				}
			} catch (IOException e) {
				System.out.println(e.toString());
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} finally{
			if(mbr!=null){
				try {
					mbr.myClose();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
例子7:利用LineNumberReader的 getLineNumber()方法可以的带行号的输出文本内容。      
package cn.itheima.day03;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
public class LineNumberReaderDemo {
	public static void main(String[] args) {
		FileReader fr=null;
		LineNumberReader inr=null;
		try {
			fr = new FileReader("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\PersonDemo.java");
			inr = new LineNumberReader(fr);
			String line = null;
			try {
				while((line=inr.readLine())!=null){
					 //LineNumberReader getLineNumber()方法可以的带行号的输出
					System.out.println(inr.getLineNumber()+"::"+line);  
				}
			} catch (IOException e) {
				System.out.println(e.toString());
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} finally{
			if(inr!=null){
				try {
					inr.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
例子8:利用自定义的MyLineNumberReader的 getLineNumber()方法可以的带行号的输出      
package cn.itheima.day03;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
//直接继承父类,可以复用myReaderLine()方法和myClose()方法。
class MyLineNumberReader extends MyBufferedReader{  
	private int lineNumber;
	public MyLineNumberReader(FileReader fr) {
		super(fr);
	}
	public int getLineNumber() {
		return lineNumber;
	}
	public void setLineNumber(int lineNumber) {
		this.lineNumber = lineNumber;
	}
	public String myReaderLine() throws IOException{
		lineNumber++;
		return super.myReaderLine();
	}
}
public class MyLineNumberReaderDemo {
	public static void main(String[] args) {
		MyLineNumberReader mylnr=null;
		try {
			FileReader fr = new FileReader("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\BufferedWriterDemo.java");
			mylnr = new MyLineNumberReader(fr);
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		}
		String line = null;
		try {
			while((line=mylnr.myReaderLine())!=null){
				System.out.println(mylnr.getLineNumber()+"::"+line);
			}
		} catch (IOException e) {
			System.out.println(e.toString());
		}finally{
			if(mylnr!=null){
				try {
					mylnr.myClose();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
目前学习的流对象:
    字符流:
        FileReader
        FileWriter
 
        BufferedReader
        BufferedWriter
 
那么,我们还要学习字节流
    字节流:
        FileInputStream
        FileOutputStream
 
        BufferedInputStream
        BufferedOutputStream
字节流:
抽象基类: InputStream  OutputStream
字节流可以操作任何数据。
注意:字符流使用的数组是字符数组。char[] chs
字节流使用的数组是字节数组。byte [] bt
主要代码模式:
FileOutputStreamfos = new FileOutputStream(“a.txt”);
fos.write(“abcdef”);  //直接将数据写入到了目的地
fos.close();  //只关闭资源
 
FileInputStreamfis = new FileInputStream("a.txt");
//fis.available();//获取关联的文件的字节数。
//如果文件体积不是很大。
//可以这样操作。
byte[]buf = new byte[fis.available()];//创建一个刚刚好的缓冲区。
//但是这有一个弊端,就是文件过大,大小超出jvm的内容空间时,会内存溢出。
fis.read(buf);
System.out.println(newString(buf));      
例子9:利用字节流读取或写入文本内容到控制台或者文本文件中      
package cn.itheima.day03;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileStream {
	//读文件(一个一个的读,读一个存一个)
	public static void readFile_1(){
		FileInputStream fis=null;
		try {
			fis = new FileInputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\fos.txt");
			int ch = 0;
			try {
				while((ch=fis.read())!=-1){
					System.out.print((char)ch);
				}
			} catch (IOException e) {
				System.out.println(e.toString());
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		}finally{
			if(fis!=null){
				try {
					fis.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
	//读方法2(读完之后,一起存起来)
	public static void readFile_2(){
		FileInputStream fis = null;
		try {
			fis = new FileInputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\fos.txt");
			byte[] buf = new byte[1024];
			int len = 0;
			while((len=fis.read(buf))!=-1){
				System.out.println(new String(buf,0,len));
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} catch (IOException e) {
			System.out.println(e.toString());
		}finally{
			if(fis!=null){
				try {
					fis.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
	//读文件
	public static void readFile_3(){
		FileInputStream fis = null;
	    try {
			fis = new FileInputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\fos.txt");
			int num = fis.available();  //获得内容的长度大小
			byte[] buf = new byte[num];  //可以定义一个刚刚好的byte数组(即:刚刚好的缓冲区),它的长度就是num
			int len =fis.read(buf);   //在这里不用循环了
			System.out.println(new String(buf,0,len));
		
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} catch (IOException e) {
			System.err.println(e.toString());
		}finally{
			if(fis!=null){
				try {
					fis.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
	//写文件
	public static void writeFile(){
		FileOutputStream fos=null;
		try {
			fos = new FileOutputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\fos.txt");
			fos.write("itheima,helloworld!".getBytes());   //字节流不需要刷新的,但需要关闭资源
			
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} catch (IOException e) {
			System.out.println(e.toString());
		}finally{
			if(fos!=null){
				try {
					fos.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
	public static void main(String[] args) {
		//writeFile();
		//readFile_1();
		//readFile_2();
		readFile_3();
	}
           
例子10:想要操作图片数据,copy一个图片到指定位置      
package cn.itheima.day03;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
 * 演示:复制一张图片
 * 思路:
 *     1.用字节读取流对象和图片关联
 *     2.用字节写入流对象创建一个图片文件,用于存储获取到的图片数据
 *     3.通过循环读写,完成数据的存储
 *     4.关闭资源
 * @author wl-pc
*/
public class CopyPic {
	public static void main(String[] args) {
		FileOutputStream fos =null;
		FileInputStream fis = null;
		try {
			fos = new FileOutputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\2.jpg");
			fis = new FileInputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\1.jpg");
			byte[] buf = new byte[1024*4];
			int len = 0;
			while((len=fis.read(buf))!=-1){
				fos.write(buf,0,len);
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} catch (IOException e) {
			System.out.println(e.toString());
		}finally{
			if(fos!=null){
				try {
					fos.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
			if(fis!=null){
				try {
					fis.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
例子11:演示:mp3复制,通过缓冲区      
package cn.itheima.day03;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
 * 演示:mp3复制,通过缓冲区
 * BufferedOuputStream缓冲输出流
 * BufferedInputStream缓冲输入流
 * @author wl-pc
 */
public class CopyMP3 {
	//通过字节流的缓冲区完成复制
	public static void copy_1(){
		BufferedInputStream bufis=null;
		BufferedOutputStream bufos=null;
		try {
			bufis = new BufferedInputStream(new FileInputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\0.mp3"));
			bufos = new BufferedOutputStream(new FileOutputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\1.mp3"));
			int by = 0;
			while((by=bufis.read())!=-1){
				bufos.write(by);
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} catch (IOException e) {
			System.out.println(e.toString());
		}finally{
			if(bufis!=null){
				try {
					bufis.close();
				} catch (IOException e) {
					System.out.println(e.toString());
				}
			}
			if(bufos!=null){
				try {
					bufos.close();
				} catch (IOException e) {
					System.out.println(e.toString());
				}
			}
		}
	}
	//利用自己定义的缓冲区拷贝mp3文件
	public static void copy_2(){
		MyBufferedInputStream bufis=null;
		BufferedOutputStream bufos=null;
		try {
			bufis=new MyBufferedInputStream(new FileInputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\0.mp3"));
			bufos=new BufferedOutputStream(new FileOutputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\2.mp3"));
			int by = 0;
			while((by=bufis.myRead())!=-1){
				bufos.write(by);
			}
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		} catch (IOException e) {
			System.out.println(e.toString());
		}finally{
			if(bufis!=null){
				try {
					bufis.myClose();
				} catch (IOException e) {
					System.out.println(e.toString());
				}
			}
			if(bufos!=null){
				try {
					bufos.close();
				} catch (IOException e) {
					System.out.println(e.toString());
				}
			}
		}
	}
	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		//copy_1();
		copy_2();
		long end = System.currentTimeMillis();
		System.out.println((end-start)+"毫秒");
	}
}
           
自定义的读取mp3的缓冲区代码:      
package cn.itheima.day03;
import java.io.IOException;
import java.io.InputStream;
class MyBufferedInputStream {
    private InputStream in;
    private byte[] buf = new byte[1024];
    private int pos = 0,count = 0;
    MyBufferedInputStream(InputStream in) {
		this.in = in;
	}
    //一次读取一个字节,从缓冲区中(字节数组中读取)获取
    public int myRead() throws IOException{
    	if(count==0){
    		//通过in对象读取硬盘上的数据存储到buf中
    		count = in.read(buf);
    		if(count<0){
    			return -1;
    		}
    		pos=0;
    		byte b = buf[pos];
    		count--;
    		pos++;
    		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();
    }
}
           
注意:字节流的read()方法读取一个字节。为什么返回的不是byte类型的,而是int 类型的呢?
因为read方法读到末尾时返回的是-1.而在所操作的数据中的很容易出现连续多个1的情况,而连续读到8个1,就是-1.导致读取会提前停止。
所以将读到的一个字节给提升为一个int类型的数值,但是只保留原字节,并在剩余二进制位补0.
具体操作是:byte&255  or  byte&0xff    
对于write方法,可以一次写入一个字节,但接收的是一个int类型数值。只写入该int类型的数值的最低一个字节(8位)。即对于write()方法实际上进行了强制转化的动作。
简单说:read方法对读到的数据进行提升。write对操作的数据进行转换。      
例子12:读取键盘录入      
package cn.itheima.day03;
import java.io.IOException;
import java.io.InputStream;
/**
 * 演示:读取键盘录入
 * System.out对应的是标准的输出设备,控制台
 * System.in对应的是标准的输入设备,键盘
 * @author wl-pc
 *  需求:通过键盘录入数据,当录入一行的数据后,就
 *        将数据进行打印,如果录入的数据是over,那么停止录入
 */
public class ReadIn {
	public static void main(String[] args) throws IOException {
		/*System.out.println('\r'+0);
		System.out.println('\n'+0);
        InputStream in = System.in;
        int by = in.read();   //read()方法是一个堵塞时方法,没有读到数据,它就会等
        System.out.println(by);*/
		InputStream in = System.in;
		StringBuilder sb= new StringBuilder();
		while(true){
			int ch =in.read();
			if(ch=='\r')
				continue;
			if(ch=='\n'){
			    String s = sb.toString();
			    if("over".equals(s)){
			    	break;
			    }
			    System.out.println(s.toUpperCase());
			    sb.delete(0, sb.length());  //清空缓冲区的内容
			}else{
			    sb.append((char)ch);
			}
		}
	}
}
           
通过刚才的键盘录入数据并打印大写字母,发现其实就是读一行数据的原理。也就是readLine()的方法。
考虑一个问题:能不能直接使用readLine()方法来完成键盘录入的一行数据的读取呢?这样高效些。
readLine()方法是字符流BufferesReader类的方法而键盘录入的方法read()是字节流InputStream类中的方法
考虑:能不能将字节流转成字节流,再使用字符流缓冲区的readLine()方法呢?
字符流中有一个这样的转换流InputStreamReader()方法,可以将字节流转换成字符流
转换流:
   特点:
      1,是字节流和字符流之间的桥梁。
      2,该流对象中可以对读取到的字节数据进行指定编码表的编码转换。
什么时候使用呢?
     1,当字节和字符之间有转换动作时。
     2,流操作的数据需要进行编码表的指定时。
具体的对象体现:这两个流对象是字符流体系中的成员。
     1,InputStreamReader:字节到字符的桥梁。
     2,OutputStreamWriter:字符到字节的桥梁。
这两个流对象是字符流体系中的成员。那么它们有转换作用,而本身又是字符流。所以在构造的时候,需要传入字节流对象进来。
构造函数:
      InputStreamReader(InputStream):通过该构造函数初始化,使用的是本系统默认的编码表GBK。
      InputStreamReader(InputStream,StringcharSet):通过该构造函数初始化,可以指定编码表。
      OutputStreamWriter(OutputStream):通过该构造函数初始化,使用的是本系统默认的编码表GBK。
      OutputStreamWriter(OutputStream,StringcharSet):通过该构造函数初始化,可以指定编码表。
操作文件的字符流对象是转换流的子类。
Reader
  |--InputStreamReader
        |--FileReader
Writer    
  |--OutputStreamWriter
        |--FileWriter
转换流中的read()方法,已经融入了编码表中。在底层调用字节流的read方法时将获取的一个或者多个字节数据进行临时存储,并去查指定的编码表,如果编码表没有指定,查的是默认码表。那么转流的read方法就可以返回一个字符比如中文。转换流已经完成了编码转换的动作,对于直接操作的文本文件的FileReaer而言,就不用在重新定义了,只要继承该转换流,获取其方法,就可以直接操作文本文件中的字符数据了。
注意:
在使用FileReader操作文本数据时,该对象使用的是默认的编码表。如果要使用指定编码表时,必须使用转换流。
FileReaderfr = new FileReader(“a.txt”);   //操作a.txt中的数据,使用的是本系统默认的编码方式GBK。
//操作a.txt中的数据使用的也是本系统默认的编码方式GBK。
InputStreamReaderisr = new InputStreamReader(new FileInputStream(“a.txt“));
这两句的代码意义相同。
但是:如果a.txt中的文件中的字符数据是通过utf-8的形式编码。那么在读取时,就必须指定编码表。那么转换流必须使用。
InputStreamReader isr = new InputStreamReader(newFileInputStream(“a.txt”),”UTF-8”);      
例子13:将字节流转成字符流,再使用字符流缓冲区的readLine()方法读取一行信息显示出来。      
package cn.itheima.day03;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
/**
 * 通过刚才的键盘录入数据并打印大写字母,发现其实就是读一行数据的原理。
 * 也就是readLine()的方法
 * 考虑一个问题:能不能直接使用readLine()方法来完成键盘录入的一行数据的读取呢?这样高效些。
 * readLine()方法是字符流BufferesReader类的方法
 * 而键盘录入的方法read()是字节流InputStream类中的方法
 * 考虑:能不能将字节流转成字节流,再使用字符流缓冲区的readLine()方法呢?
 * 字符流中有一个这样的转换流InputStreamReader()方法,可以将字节流转换成字符流
 * @author wl-pc
*/
public class TransStreamDemo {
	public static void main(String[] args) {
		//为了提高效率,将字符串进行缓冲区技术高效操作,使用BufferedReader类中的方法
		BufferedReader bufr=null;
		try {
			//1.获取键盘录入对象
			//InputStream in = System.in;
			//2.将字节流对象转换成字符流对象,使用转换流InputStreamReader()方法
			//InputStreamReader isr = new InputStreamReader(in);  //得到字符流in
			//bufr = new BufferedReader(isr);
			
			//键盘录入最常见写法:以上三句话变为一句话(如下:)
			bufr = new BufferedReader(new InputStreamReader(System.in));
				
			//2.将字符流对象转换成字节流对象,使用转换流OutputStreamWriter()方法
			//OutputStream out = System.out;   //得到输出流
			//OutputStreamWriter osw = new OutputStreamWriter(out);
			//装饰类,用来装饰转化流OutputStreamWriter类的。
			//可以调用bufferedWriter中的newLine()方法,夸平台换行
			//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();
			}
		} catch (IOException e) {
			System.out.println(e.toString());
		} finally{
			if(bufr!=null){
				try {
					bufr.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
例子14:关于流操作的基本规律,演示例子      
package cn.itheima.day03;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
/**
 * 1.
 *   源:键盘录入
 *   目的:控制台
 * @author wl-pc
 * 2.改变需求:想把键盘录入的数据存储到一个文件中
 *   源:键盘
 *   目的:文件
 *   
 * 3.改变需求:想要将一个文件数据打印到控制上
 *   源:文件
 *   目的:控制台
 *   
 *   ######################流操作的基本规律:##########################
 *     最痛苦的就是流对象有很多,不知道该用哪一个?                                    
 *      通过三个明确来完成:                                                            
 *        1.明确源和目的                                                           
 *           源:输入流.    InputStream    Reader                                                  
 *         目的:输出流.   OutputStream    Writer                                                      
 *        2.明确操作的数据是否是存文本   
 *           是纯文本:用字符流
 *         不是纯文本:用字节流    
 *        3.当体系明确后,再明确要使用哪个具体的对象
 *           通过设备来进行区分:
 *              源设备:内存、硬盘、键盘
 *            目的设备:内存、硬盘(文件)、控制台            
 *   ----------------------3个需求之一----------------------------------      
 *     1.将一个文本文件中的数据存储到另一个文件中  ,也就是复制文件
 *          源:因为是源,所以使用读取流:InputStream     Reader
 *              a.是不是操作文本文件?
 *                   是:这就可以选择Reader
 *                 不是:可以选择InputStream
 *             这样下来,所属体系就明确了。
 *             
 *             b.接下来就要明确要使用体系中的哪个对象?
 *               明确设备:硬盘上的一个文件
 *               Reader体系中可以操作文件的对象是FileReader
 *             c.是否需要提高效率?
 *                需要:加入Reader体系的缓冲区:BufferedReader
 *               
 *       接下来就是: 1) FileReader fr = new FileReader("a.txt");        
 *                    2) BufferedReader br = new BufferedReader(fr);
 *             
 *             
 *          目的:文件 OutputStream    Writer
 *             a.目的是否是纯文本的?
 *                是:Writer
 *              不是:OutputStream 
 *             b.明确设备:硬盘上的一个文件
 *                Writer体系中可以操作一个文件的对象是FileWriter
 *                
 *             c.是否需要提高效率?
 *                 需要:加入Writer体系的缓冲区:BufferedWriter
 *             
 *       接下来就是: 1) FileWriter fw = new FileWriter("b.txt");
 *                    2) BufferedWriter bw = new BufferedWriter(fw); 
 *                 
 *     练习: 将一个图片文件中的数据存储到另一个图片中 ,即为copy图片,要按照以上的格式去写                                       
 *          源(是图片):因为是源, 所以使用读取流:InputStream    Reader
 *                a.是不是操作的纯文本文件?
 *                 不是:这就可以选择InputStream
 *                   是:这就可以选择 Reader   
 *                b.接下来就要明确要使用体系中的哪个对象?   
 *                   明确设备:硬盘上的一个图片
 *                   InputStream体系中可以操作图片的对象时FileInputStream
 *                c.是否需要提高效率?
 *                   需要:加入InputStream体系的缓冲区:BufferedInputStream
 *        
 *         接下来就是:FileInputStream fis = new FileInputStream("1.jpg");
 *                     BufferedInputStream bis = new BufferedInputStream(fis);
 *                    
 *           目的:文件  OutputStream      Writer
 *                 a.是否是纯文本的文件?
 *                    不是:OutputStream 
 *                      是:writer
 *                 b.明确设备:硬盘上的一个图片
 *                     OutputStream体系中可以操作一个文件的对象是FileOutputStream
 *                 c.是否需要提高效率?
 *                 需要:加入OutputStream体系的缓冲区:BufferedOutputStream    
 *                                                
 *         接下来就是: FileOutputStream fos = new FileOutputStream("2.jpg");
 *                      BufferedOutputStream bos = new BufferedOutputStream(fos);                                        
 *                                                                 
 *   #################################################################
 */
public class TransStreamDemo2 {
	public static void main(String[] args) {
		//为了提高效率,将字符串进行缓冲区技术高效操作,使用BufferedReader类中的方法
		BufferedReader bufr=null;
		try {
			/*需求2的实现
			 * bufr = new BufferedReader(new InputStreamReader(System.in));
			BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\out.txt")));
*/
			//需求3的实现
			bufr=new BufferedReader(new InputStreamReader(new FileInputStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\CopyPic.java")));
			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();
			}
		} catch (IOException e) {
			System.out.println(e.toString());
		} finally{
			if(bufr!=null){
				try {
					bufr.close();
				} catch (IOException e) {
					System.out.println("close:"+e.toString());
				}
			}
		}
	}
}
           
例子15:将系统出现的异常信息存储到文件中      
package cn.itheima.day03;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * 将系统出现的异常信息存储到文件中
 * @author wl-pc
 */
public class ExceptionInfo {
	public static void main(String[] args) {
		try {
			int [] arr = new int[2];
			System.out.println(arr[3]);
		} catch (Exception e) {
			try {
				PrintStream ps= new PrintStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\exceptioninfo.txt"); 
				Date d = new Date();
				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				String s = sdf.format(d); 
				ps.println(s.toString());
				e.printStackTrace(ps);
			} catch (FileNotFoundException e1) {
				e1.printStackTrace();
			}
		}
	}
}
           
例子16:打印系统信息到硬盘上的一个文件中      
package cn.itheima.day03;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.util.Properties;
public class SystemInfo {
	public static void main(String[] args) {
		Properties properties = System.getProperties();
		//System.out.println(properties);
        //properties.list(System.out);
        try {
			properties.list(new PrintStream("F:\\Javajichu\\JavaLianXi\\src\\cn\\itheima\\day03\\sysinfo.txt"));
		} catch (FileNotFoundException e) {
			System.out.println(e.toString());
		}
	}
}