奋斗黑马程序员----Java之字节流小结


----------android培训java培训、期待与您交流! ----------
/**
 * Java之字节流小结:
 * 
 * 1 :IO之--字节流
 * 2 :拷贝图片
 * 3 :演示mp3的复制,通过缓冲区。
 * 4 :自定义流缓冲区及其原理讲解
 * 5 :读取键盘录入。以三种不同的方式:
 * 6  :流操作规律
 * 7 :改变标准输入输出设备
 * 8 :流异常信息
 * 9 :打印系统信息,并保存到文件中
 */

/** 1 :IO之--字节流
 * 
 * 我们学过的字符流有:字符流仅限于操作文本。
 * 	FileReader
 * 	FileWriter
 * 
 *  BufferedReader
 *  BufferedWriter
 *  
 *  如果我们想要操作一张图片的话,该怎么办呢?
 *  这时就需要用到字节流了:
 *   InputStream OutputStream
 *   
 *  需求:想要操作图片数据这时就要用到字节流。
 *  
 * public abstract class InputStream  extends Object  implements Closeable
 *    此抽象类是表示字节输入流的所有类的超类。 需要定义 InputStream 子类的应用程序
 * 必须总是提供返回下一个输入字节的方法。
 *  
 * public abstract class OutputStream  extends Object implements Closeable, Flushable
 *   此抽象类是表示输出字节流的所有类的超类。输出流接受输出字节并将这些字节发送到某个接收器。 
 *   需要定义 OutputStream 子类的应用程序必须始终提供至少一种可写入一个输出字节的方法。
 *   
 *    public class FileOutputStream extends OutputStream,文件输出流是用于将数据写入 File 
 *  或 FileDescriptor 的输出流。
 */
import java.io.*;
public class FileStream {
	public static void main(String[] args) throws IOException
	{
		//writerFile();
		//readFile_1();
		//readFile_2();
		readFile_3();
	}
	public static void writerFile() throws IOException 
	{
		FileOutputStream fos = new FileOutputStream("fos.txt");
		
		/*
		 * void write(byte[] b) 将 b.length 个字节从指定 byte 数组写入此文件输出流中。
		 */
		fos.write("adfjdi".getBytes());
		/*
		 * 但是为什么没有刷新呢:
		 *   字符流:其实是一样走的字节,但是需要把字节临时存起来。如果存中文的话,
		 * 一个汉字对应两个字节,如果存了一个字节,那么还需要一个字节,当两个字节
		 * 完成后,还需要去查表。
		 *  
		 *   如果直接使用字节流:如果没有直接指定缓冲区的话,是不需要刷新的。
		 */
		fos.close(); //这个需要写
	}
	public static void readFile_1() throws IOException
	{
		FileInputStream fis = new FileInputStream("fos.txt");
		int ch = 0;
		/* int read() 从此输入流中读取一个数据字节。
		 * 
		 * int read(byte[] b) 从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。 
		 */
		while((ch=fis.read())!=-1)
		{
			//这样的方式,无法输出汉语
			System.out.print((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.print(new String(buf,0,len)+":::");
		}
		fis.close();
	}
	
	public static void readFile_3() throws IOException
	{
		FileInputStream fis = new FileInputStream("fos.txt");
		//int num = fis.available();
		//System.out.println("num"+num); //字节数目
		
		byte[] buf = new byte[fis.available()];	
		/*定义一个刚刚好的缓冲区,不用再循环了。
		 * 
		 * 使用情况:当数据不是太大时,可以使用这种方法
		 * 由于java的初始内存是64mb的,所以对于一个电影来说,这种操作会发生内存溢出。
		 * 建议这种方法慎用。推荐使用固定大小:1024的整数倍。
		 */
		fis.read(buf);
		
		System.out.println(new String(buf));
		fis.close();
		
	}
}


/** 2 :拷贝图片
 * 
 * 拷贝一张图片
 * 思路:
 * 	1,用字节读取流对象和图片关联。
 * 	2,用字节写入流对象创建一个图片文件,用于存储获取到的图片数据。
 *  3,通过循环读写,完成数据的存储
 *  4,关闭资源。
 *  
 * 问题:用字符流可以复制么?
 * 	可以的。但是复制完的图片有可能打不开。字符流复制图片时会不断的去查编码表,如果找到了
 * 对应的编码,则可以,如果找不到对应的编码,就会以相似的编码替代。因此,新旧编码可能会
 * 变化,有可能会打不开。
 *  字符流是用于处理文字的。不能拿来处理媒体文件。谨记。
 * 
 */
import java.io.*;
public class CopyPic {
	public static void main(String[] args)
	{
		FileInputStream fis = null;  //将数据读入字节流
		FileOutputStream fos = null; //可以将读入到的字节流写到输出流中
		try
		{
			fos = new FileOutputStream("G:\\龟龟2.bmp");
			fis = new FileInputStream("G:\\龟.jpg");	//貌似还可以转换格式呢。
			
			byte[] buf = new byte[1024];
			int len = 0;
			while((len=fis.read(buf))!=-1)
			{
				fos.write(buf,0,len);
			}
			
		}
		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("写入关闭失败");
			}
		}
	}
}


/** 3 :演示mp3的复制,通过缓冲区。
 *  
 *BufferedinputStream
 *   public class BufferedInputStream extends FilterInputStream
 *   BufferedInputStream 为另一个输入流添加一些功能,即缓冲输入以及支持 mark 和 
 * reset 方法的能力。在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。
 * 在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一
 * 次填充多个字节。mark 操作记录输入流中的某个点,reset 操作使得在从包含的输入
 * 流中获取新字节之前,再次读取自最后一次 mark 操作后读取的所有字节。 
 * 
 *BufferedOutputStream
 *   public class BufferedOutputStream extends FilterOutputStream
 *   该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底
 * 层输出流中,而不必针对每次字节写入调用底层系统。
 * 
 * 
 */
import java.io.*;
public class CopyMp3 {
	public static void main(String[] args) throws IOException
	{
		long start = System.currentTimeMillis();
		//copy_1();
		copy_2();
		long end = System.currentTimeMillis();
		System.out.println((end-start)+":毫秒");
	}
	
	//通过字节流的缓冲区完成复制
	public static void copy_1() throws IOException 
	{ 
		BufferedInputStream bfis = new BufferedInputStream(new FileInputStream("G:\\不屑.mp3"));
		BufferedOutputStream bfos = new BufferedOutputStream(new FileOutputStream("G:\\很不屑.mp3"));
		/* FileInputStream("G:\\不屑.mp3")从硬盘中读取数据,放到缓冲区中。 
		 * BufferedInputStream从缓冲区中读取数据。 
		 */
		int by = 0;
		while((by=bfis.read())!=-1)
		{
			bfos.write(by);
		}
		bfos.close();
		bfis.close();
	}
	
	/**
	 * 问题:能不能自己定义一个缓冲区,来操作数据呢?
	 * 解决方法见下,工具类MyBufferedInputStream在第14讲:
	 */
	public static void copy_2() throws IOException 
	{ 
		MyBufferedInputStream bfis = new MyBufferedInputStream(new FileInputStream("G:\\不屑.mp3"));
		BufferedOutputStream bfos = new BufferedOutputStream(new FileOutputStream("G:\\很不屑.mp3"));
		/* FileInputStream("G:\\不屑.mp3")从硬盘中读取数据,放到缓冲区中。 
		 * BufferedInputStream从缓冲区中读取数据。 
		 */
		//System.out.println("第一次读到的是:"+bfis.myRead());
		int by = 0;
		while((by=bfis.myRead())!=-1)
		{
			bfos.write(by);
		}
		bfos.close();
		bfis.myClose();
	}
}


/** 4 :自定义流缓冲区及其原理讲解
*
*/
import java.io.*;
public class MyBufferedInputStream 
{
	
	private InputStream in;
	private byte[] buf = new byte[1024];
	private int pos = 0,count = 0;
	/**
	 * pos是标识位置的,他和count(计数器)搭配使用,
	 * 当向一个缓冲区数组中填入数据后,count的值就是该数组的长度,
	 * 那么当向外去数据的时候,每取一次,那么缓冲区数组的长度就会减1,
	 * 那也就代表着还可以取的次数就会少一次。直到缓冲区数组的长度为0(此时,
	 * count也为0,表示数组空了,要从新向里面插入数据了。
	 */
	MyBufferedInputStream(InputStream in) //构造函数。传入一个参数。
	{
		this.in = in;
	}
	
	
	//一次读一个字节,从缓冲区中(字节数组)读取
	public int myRead() throws IOException
	/**问题:
	 * return b;中的b是byte类型的,那么该方法的返回值类型为什么不是byte类型呢?
	 */
	{
		//通过in对象读取硬盘上的数据,并存储到buf中。
		if(count==0) 
			/*当count==0时,表示数据取光了。要重新向缓冲区中添加数据
			 * 其实,当count==0时,数组为空,添加完数据后,在该if语句里,就
			 * 只取了一次数据,即0角标的数据,之后count就不为0,会进入到
			 * else if语句里,知道该块搞完,此时count再次为0,又到这个if
			 * 语句取数据,知道数据被取完。
			 */
		{			
			count = in.read(buf); //read方法会将读到的数据放到数组buf中,并返回读取到字节数。
			if(count<0)	//数据取完了。
				return -1;
			
			pos = 0;	//装完数据后,pos要归0;
			byte b = buf[pos]; 	//取数据,首先会取到0角标元素。
			
			count--; //你敢取一次,我就少一次
			pos++;  //下一次取就是接着的数据
			
			return b&255;
		}
		else if(count>0)
			/*
			 * 该代码块就是在取数据
			 */
		{
			byte b = buf[pos]; 	//取数据,首次会取到1角标元素。
			
			count--;
			pos++;
			
			return b&0xff;//(16进制的255)
		}
		return -1;
	}
	public  void myClose() throws IOException 
	{
		in.close();
	}
}
/*
* 问题:为什么返回值是int,而不是byte?
*   Mp3的数据都是二进制的数据,即都是由1,0组成的。所以在MP3的二进制字节中,会存在11111111
* 和00000000的情况,也就是说,MP3的二进制里会出现-1,这和判断文件结束的标记“-1”冲突,
* 那怎么解决呢?
* 	 byte在内存中占用1个字节即8位,由于我们知道,-1的二进制是1取反再加1,也就是11111111.
* 如果我们按照byte类型返回的话,那么还是-1,还是会冲突。那么我们怎么保证如果取到的值是
* -1,又能正常返回,而又不和结束标记冲突呢?
* 	 将其转为int类型,int类型在内存中占4个字节,32位,如果取到的值是-1,我们在其前3位补0
* 那么结果就得以保存,而又不冲突。
* 
*   因为myRead的返回值是int类型的,当b取到了11111111后,以int(32位)类型返回,类型提升,
* 就成了 11111111 11111111 11111111 11111111
* 而write方法,内部会进行强转,仅仅取得返回值的后8位,仍旧是-1,此时,程序就会结束。
* 
* byte类型   -1  ==  11111111    
* 
* byte类型   -1  --转成--> int类型的   -1 == 11111111 11111111 11111111 11111111
* 
* 00000000 00000000 00000000 11111111 	== 255 ,就不是-1了。
* 
*    那么就有一种假设:如果在byte转成int类型是,将前面的24位补成0,而不是1,就会保留
* 原数据,那么就会避免-1的出现了。那么怎么实现这种操作呢?
* 
* **异或操作。
*  
*  11111111 ---》提升了一个int类型,那不还是-1么? 是-1的原因是因为在8个1前面
* 补的是1导致的。那么我只要在前面补0,既可以保留原字节数据不变,又可以避免-1的出现。
* 
* 那么怎么补0呢?
*   11111111 11111111 11111111 11111111	
* & 00000000 00000000 00000000 11111111
* --------------------------------------
*   00000000 00000000 00000000 11111111
*/
/**问题:类型提升过后,是不是就由1个字节变成了4个字节??
* 	那就是说,读1个字节,得到4个字节。那么再往回写的时候,不是要扩大4倍么?
*  write方法其实在做一个强转动作。 write仅仅把最低的8位写入。
*  
*  read方法在做提升。而write在做强转。
*/



/** 5 :读取键盘录入。以三种不同的方式:
 * 
 * 字符流:4个
 * FileWriter
 * FileReader
 * BufferedReader
 * BufferedWriter
 * 
 * 字节流:4个
 * FileInputStream
 * FileOutputStream
 * BufferedInputStream
 * BufferedOutputStream
 * 
 * InputStreamReader:字节流通向字符流的桥梁
 * OutputStreamWriter:字符流通向字节流的桥梁
 * 
 * 读取键盘录入:
 * 	System.out:标准的输出设备,控制台
 *  System.in: 标准的输入设备,键盘。
 *  
 *  需求: 通过键盘录入数据,当录入一行数据后,就将该行数据打印,如果录入的数据
 * 是over的话,就停止打印。
 * 
 *   通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。也就
 * 是readLine()方法。
 *  
 * 那么能不能直接使用readLine方法来完成键盘录入一行数据的读取呢?
 * 
 * readLine()是BufferedReader类中的方法,而键盘录入的read方法是字节流InputStream的方法。
 * 那么能不能将字节流转成字符流再使用字符流缓冲区中的readLine方法呢?
 */
import java.io.*;
public class TransStreamDemo {
	public static void main(String[] args) throws IOException
	{
		// method_1(); 
		//method_2();	
		method_3();	
	}
	//第一种方式:
	public static void method_1() throws IOException
	{
		InputStream in = System.in;	 //System.in的返回类型是InputStream
		
		//System.out.println('\r'+0); // \r = 13
		//System.out.println('\n'+0); // \n = 10
		
		//int by = in.read(); 	//read()方法是一个阻塞式方法。		
		//int by1 = in.read(); 	//读取一个字节。
		//int by2 = in.read(); 	//读取一个字节。
		
		//System.out.println(by);
		//System.out.println(by1);
		//System.out.println(by2);
		/*
		 * 当读入的数据少于要打印的数据时,就会以回车符代替。
		 * 比如:上面有三次输出,如果只读入一个字符,如a,那么后面两个就会以回车符替代。
		 */
		StringBuilder sb = new StringBuilder(); 	//临时缓冲区。
		while(true)
		{
			int ch = in.read();//一次读一个字符
			if(ch=='\r')
				continue;
			if(ch=='\n')
				/*如果换行就到结尾了
				 * 然后将输入的数据转成String,然后可以判断
				 */
			{
				String s = sb.toString();
				if("over".equals(s))
					break;
				System.out.println(s.toUpperCase());
				
				//sb = new StringBuilder(); //清空缓冲区。利于判断。但是new一个对象占内存
				sb.delete(0, sb.length());	//清空缓冲区,否则每一次添加的长度都在增长。
			}
			else
				sb.append((char)ch);
		}
		
		in.close();	//不关也可以,因为程序结束后,就停止了。
	}
	
	//第二种方式:第一次效率提高。
	public static void method_2() throws IOException
	{
		/*
		 * public class InputStreamReader extends Reader
		 *    InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节
		 * 并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默
		 * 认的字符集。 
		 *    每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一
		 * 个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,
		 * 使其超过满足当前读取操作所需的字节。 
		 *    为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。例如: 
		 *  BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		 *  
		 *  InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader。
		 */
		//1,获取键盘录入对象
		InputStream in = System.in;
		//2,将字节流对象转成字符流对象。 使用转换流InputStreamReader
		InputStreamReader isr = new InputStreamReader(in);
		//3,为了提高效率,将字符流进行缓冲区技术高效操作。使用 BufferedReader
		BufferedReader bufr = new BufferedReader(isr);
		
		String line = null;
		while((line=bufr.readLine())!=null)
		{
			if("over".equalsIgnoreCase(line)){ //判断结束。
				break;
			}
			System.out.println(line.toUpperCase());
		}
		bufr.close();
	}
	
	/**写入转换流
	 * 字符通向字节的桥梁:OutputStreamWriter
	 * 第三种方式: 
	 */
	public static void method_3() throws IOException
	{
		//1,获取键盘录入对象
		//InputStream in = System.in;
		//2,将字节流对象转成字符流对象。 使用转换流InputStreamReader
		//InputStreamReader isr = new InputStreamReader(in);
		//3,为了提高效率,将字符流进行缓冲区技术高效操作。使用 BufferedReader
		//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);
		/*
		 * public class OutputStreamWriter extends Writer
		 *   OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要
		 * 写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将
		 * 接受平台默认的字符集。(详情参考文档) 
		 */
		BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
		//***以后凡是键盘输出都用这种写法。
			
		String line = null;
		while((line=bufr.readLine())!=null)
		{
			if("over".equals(line)) //判断结束。
				break;
			//System.out.println(line.toUpperCase()); 替换为
			//osw.write(line.toUpperCase()+"\r\n");  替换为:
			bufw.write(line.toUpperCase());
			bufw.newLine();
			/*只写这个没有显示输出。OutputStream内部使用了缓冲区,数据都被缓冲了。
			 * 因此要刷新
			 * 
			 * 添加上了换行操作符,但是这只能让windows识别。所以还要改。
			 * 那么能不能使用newLine()方法呢?
			 */
			//osw.flush();	//但是只加上刷新输出和输入数据界面看着不爽,所以还要改。  
			//替换为:
			bufw.flush();
		}
		bufw.close();
	}
}





/** 6  :流操作规律
 * 1,
 *  源:键盘录入
 *	目的:控制台。
 * 2,需求:想把键盘录入的数据存储到一个文件中。
 *  源:键盘
 *  目的:文件
 * 
 * 3,需求:想要将一个文件的数据打印在控制台上。
 *  源:文件
 *  目的:控制台。
 * 
 * 流操作的基本规律:
 * 	最痛苦的就是:流对象有很多,不知道该用哪一个?
 * 通过三个明确来完成:
 * 1,明确:源和目的。
 * 	源:输入流  InputStream Reader
 *  目的:输出流  OutputStream Writer
 * 2,明确:操作的数据是否是纯文本?
 *  是:用字符流
 *  不是:用字节流
 * 3,当体系明确后,再明确要使用哪个具体的对象。通过设备来进行区分。
 * 	源设备:内存,硬盘,键盘
 *  目的设备:内存,控制台,硬盘(文件)
 * 
 * 第1个需求:将一个文本文件中的数据存储到另一个文件中:复制文件 
 *  源:因为是源,所以使用读取流。InputStream 和 Reader。
 *  是不是操作文本文件??
 *   是:这是就可以选择Reader。这样体系就明确了。接下来明确要使用该体系中哪个对象。
 *  明确设备:硬盘上的一个文件。Reader体系中可以操作文件的对象是FileReader
 *  
 *  是否需要提高效率??
 *   是:加入Reader体系中的缓冲区。BufferedReader
 *  
 *  FileReader fr = new FileReader("a.txt");
 *  BufferedReader bufr = new BufferedReader(fr);
 *  
 *  
 *  目的:OutputStream 和 Writer
 *   目的是否是纯文本呢?
 *    是:Writer。设备:硬盘上的一个文件。Writer体系中可以操作文件的对象时FileWriter
 *   是否需要提高效率???
 *   是:加入Writer体系中的缓冲区,BufferedWriter
 *   
 *  FileWriter fw = new FileWriter("b.txt");
 *  BufferedWriter bufw = new BufferedWriter(fw);
 *  
 * 练习:将一个图片文件中数据存储到另一个 文件中。复制文件,要按照上面格式自己完成三个明确。
 * 2.需求:将键盘录入的数据保存到一个文件中。这个需求中有源和目的都存在。那么分别分析:
 *  源:InputStream Reader
 *  是不是纯文本?是:Reader
 *  
 *  设备:键盘,对应的对象时System.in,不是选择Reader么?System.in对应的不是字节流么?
 *     为了操作键盘的文本数据方便,可以转成字符流.按照字符串操作最方便.所以既然明确了Reader,
 *  就将System.in转成Reader,用到了Reader体系中的转换流,InputStreamReader
 *  
 *   InputStreamReader isr = new InputStreamReader(System.in);
 *   需要提高效率么?
 *   需要:用BufferedReader
 *   BufferedReader bufr = new BufferedReader(isr);
 *   
 *  
 *  目的:OutputStream Writer
 *  是否是纯文本:
 *   是:用字符流,Writer
 *   设备:硬盘,一个文件。使用FileWriter
 *   FileWriter fw = new FileWriter("c.txt");
 *   需要提高效率么?需要:BufferedWriter
 *   BufferedWriter bufw = new BufferedWriter(fw); 
 *   
 *** 扩展一下:想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。
 *
 *  目的: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);
 *  
 *     所以,记住,转换流什么时候使用呢?字符和字节之间的桥梁,通常,涉及到字符编码
 *  转换时,需要用到转换流。
 *  
 *  练习:将一个文本数据打印在控制台上。要按照上面格式自己完成三个明确。
 */


import java.io.*;
public class TransStreamDemo2 {
	public static void main(String[] args) throws IOException
	{
		//need_1();
		need_1();
	}
	/**
	 * 对应需求2
	 */
	public static void need_1() throws IOException
	{
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		//***以后凡是键盘录入都用这种写法。
		
		//BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
		//BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("stream.txt",true)));
		
		//BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("stm.txt"))); 
		/*
		 * 第一次
		 */
		//BufferedWriter bufw1 = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("stm.txt"),"GBK"));
		/*
		 * 第二次
		 */
		BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("stm.txt"),"UTF-8"));
		/*
		 * 第三次。
		 */      
		/**以后凡是键盘输出都用这种写法。
		 * 写的目的地换成文件了。
		 */
			
		String line = null;
		while((line=bufr.readLine())!=null)
		{
			if("over".equals(line)) //判断结束。
				break;
			bufw.write(line.toUpperCase());
			bufw.newLine();
			bufw.flush(); 
		}
		bufw.close();

	}
	/**
	 * 对应需求3
	 */
	public static void need_2() throws IOException
	{
	
		BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("buf.txt")));
		//***以后凡是键盘录入都用这种写法。
		
		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(); 
		}
		bufw.close();

	}
}


/** 7 :改变标准输入输出设备。
 */
import java.io.*;
public class TransStreamDemo22 {
	public static void main(String[] args) throws IOException
	{
		/**setOut和setIn能将默认的System.in的源地址和System.out的目的地址给改成
		 * 自己定义的文件。
		 * 
		 * static void setOut(PrintStream out) 重新分配“标准”输出流。
		 *   能讲输出的目的给改了。
		 * static void setIn(InputStream in) 重新分配“标准”输入流。
		 * 	 能将输入的源地址给改了
		 * 
		 *public class PrintStream  extends FilterOutputStream implements Appendable, Closeable
		 *   PrintStream 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
		 * 它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;
		 * 而是,异常情况仅设置可通过 checkError 方法测试的内部标志。另外,为了自动刷新,
		 * 可以创建一个 PrintStream;这意味着可在写入 byte 数组之后自动调用 flush 方法,
		 * 可调用其中一个 println 方法,或写入一个换行符或字节 ('\n')。 
		 *   PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字
		 * 符而不是写入字节的情况下,应该使用 PrintWriter 类。 
		 */
		
		/*将源给改了。
		 */
		//System.setIn(new FileInputStream("TransStreamDemo.java"));
		
		/*将目的给该了
		 */
		System.setOut(new PrintStream("haha.html"));
		
		/**
		 * 如果将以上2者结合起来,就是文件的复制了。
		 */
		
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		//***以后凡是键盘录入都用这种写法。
		
		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(); 
		}
		bufw.close();
	}
}


/** 8 :流异常信息
 *    自己编写的打印日志格式的异常并不好看,网上有一个log4j包,
 * 专门用来处理日志的,而且格式还好看。
 */
import java.io.*;
import java.util.*;
import java.text.*;
public class ExceptionInfo {
	public static void main(String[] args) throws IOException
	{
		try{
			int[] arr = new int[2];
			System.out.println(arr[3]);
		}
		catch(Exception e)
		{
			/*e.printStackTrace(); //异常信息打印到控制台上没有什么意义,
			 * e.printStackTrace(new PrintStream("error.txt"));
			 * 
			 * public StringBuffer format(Date date,StringBuffer toAppendTo,FieldPosition pos)
			 * 将给定的 Date 格式化为日期/时间字符串,并将结果添加到给定的 StringBuffer。
			 * 下面怎么可以返回String类型呢? 
			 */
			try{				
				Date t = new Date();
				SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd,HH-mm-ss");
				String s = sdf.format(t);
				/*该format在系统类中的体现
				public final String format(Date date)
			    {
			        return format(date, new StringBuffer(),
			                      DontCareFieldPosition.INSTANCE).toString();
			    }    
			    */
				//System.setOut(new PrintStream("exception.log"));
				PrintStream ps = new PrintStream("exception.log");
				ps.println(s);
				System.setOut(ps);
			}
			catch(IOException ex)
			{
				throw new RuntimeException("日志文件创建失败"); 
			}
			e.printStackTrace(System.out);
		}
	}
}

/** 9 :打印系统信息,并保存到文件中
 */
import java.io.*;
import java.util.*;
public class SystemInfo {
	public static void main(String[] args) throws IOException
	{
		Properties prop = System.getProperties();
		//System.out.println(prop); //打印太乱。
		//prop.list(System.out);	//系统信息打印在了控制台,但是我想把这些信息保存在文件中。
		
		/*
		 *  void list(PrintStream out) 将属性列表输出到指定的输出流。 
		 */
		prop.list(new PrintStream("systeminfo.txt"));
		
	}
}


/**小结:
 * 1,IO字节流介绍。
 * 2,练习:拷贝一张图片(字符流还是字节流?)
 * 3,MP3文件的复制。
 * 4,缓冲区原理讲解
 * 5,流的操作规律介绍。
 * 6,改变标准输入输出设备
 * 7,实现将流异常信息放到文件中。
 * 8,将系统信息放到文件中。
 * 
 * 注意:
 *    流在使用时,一定要先区分源是什么,目的是什么,这样,
 * 我们才能选用合适的流对象来操作数据。
 * 
 */


----------android培训java培训、期待与您交流!----------

  详细请查看:http://edu.csdn.net/heima/

你可能感兴趣的:(奋斗黑马程序员)