黑马程序员——Java基础IO(一)——IO流概述、字符流、字节流、流操作规律

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

黑马程序员——Java基础IO(一)——IO流概述、字符流、字节流、流操作规律

第一讲 IO概述

一、IO(Input Output)流

        1.IO流用来处理设备之间的数据传输

        2.Java对数据的操作是通过流的方式

        3.Java用于操作流的对象都在IO包中

        4.流按操作数据分为两种:字节流与字符流 

        5.流按流向分为:输入流,输出流。

二、IO流常用基类

        1.字节流的抽象基类:

                InputStream ,OutputStream。

        2.字符流的抽象基类:

                Reader ,Writer。

        注:由这四个类派生出来的子类名称都是 以其父类名作为子类名的后缀。

        如:InputStream的子类FileInputStream。

        如:Reader的子类FileReader。

三、IO流的继承体系

 黑马程序员——Java基础IO(一)——IO流概述、字符流、字节流、流操作规律_第1张图片

第二讲字符流

一、字符流读取文件

        1、建立一个流对象,将已存在的一个文件加载进流。如果文件不存在,或者它是一个目录,而不是一个常规文件,或者无法打开进行读取。会抛出FileNotFound异常。

FileReader fr = new FileReader(f);

        2.读取数据。

                1)读取单个字符。

                        int ch=0;

                        ch=fr.read();

                read()方法返回的是作为整数读取的字符,每调用一次read()方法就读取一个字符,如果达到流的末尾就返回-1。

                2)将字符读入数组。

                        创建一个临时存放数据的数组。

                                char[] buf = new char[1024];

                                int num=0;

                        调用流对象的读取方法将流中的数据读入到数组中

                                num=fr.read(buf);

                        此read方法返回实际读入到字符数组的字符个数,如果达到流的末尾就返回-1。

                        构建字符串,就可以打印出数据了。

                                System.out.println(new String(buf,0,num));

        3.加入缓冲技术,提高读取效率。

                BufferedReader bufr=new BufferedReader(fr);

                String line=null;

                while((line=bufr.readLine())!=null)

                {

                        System.out.println(line);

                }

                readLine()是缓冲流对象bufr的特有方法,返回读取的一行字符(不包括换行符),如果达到流的末尾就返回null。

                关闭缓冲,其实关闭缓冲区,就是关闭缓冲区中的流对象。就可以不用写fr.close();

                bufr.close();

        3.关闭资源。

                fr.close();

         注意:

        1.read方法配合while循环可以读取完文件所有的数据。

        2.readLine方法原理:无论是读一行。或者读取多个字符。其实最终都是在在硬盘上一个一个读取。所以最终使用的还是read方法一次读一个的方法。相对于read()方法,   降低了一个一个字符的读取时出错的概率。

        3.无论是read()、read(buf)、readLine()如果发生 I/O 错误,抛出IOException,关闭缓冲流对象bufr.close() bufw.close() 发生错误会抛出IOException。所以要对发生错误就会抛出异常的代码进行try{}catch{}处理。

二、字符流——写入数据至文件

        1.创建流对象,建立数据存放文件

                FileWriter fw = new FileWriter("Test.txt");

                如果存储位置有Test.txt文件,则创建一个空文本的Test.txt覆盖原文件。

                如果不想覆盖原文件,想进行续写则加上true属性。

                FileWriter fw=new FileWriter("Test.txt",true);

        2.写入数据。

                方式一:调用流对象的写入方法,将数据写入流

                        fw.write("text");

                方式二:加入缓冲区,提高写入效率。

                        将需要被提高效率的流对象作为参数传递给缓冲区的构造函数

                                BufferedWriter bufw=new BufferedWriter(fw);

                                bufw.write("我是数据");

                        根据需求是否写入跨平台的换行符

                                bufw.newLine();

                        只要用到缓冲区,就要记得刷新。(关闭流同样会刷新,但为了排除意外事故,保证数据存在,建议写入一次就刷新一次)

                                bufw.flush();

                        其实关闭缓冲区,就是在关闭缓冲区中的流对象。就可以不用写fw.close();

                                bufw.close();

        3.关闭流资源,并将流中的数据清空到文件中。就是先flush再关闭资源,不然文件里面没有数据

                fw.close();

        注意:定义文件路径时,可以用“/”或者“\\”。反之视为相对路径(如“Test.txt”)。

三、字符流的缓冲区

        1.缓冲区的出现提高了对数据的读写效率。需要先将需要缓冲的流对象初始化到构造函数中。

        2.对应类:

                BufferedWriter

                BufferedReader

        3.缓冲区要结合流才可以使用。

        4.在流的基础上对流的功能进行了增强

        5、BufferedWriter、BufferedReader内部封装了一个字符数组,默认大小8kb。

示例一:拷贝文本文件

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class TextFileCopy 
{
	public static void main(String[] args) throws IOException
	{
		//1.一个一个字符的拷贝
		textcopy_1();
		//2.每次拷贝指定大小的字符数组
		textcopy_2();	
	}
	public static void textcopy_1() throws IOException
	{
		//1.创建读取文件流对象,关联文件。
		FileWriter fw=new FileWriter("c:/zzz.java");
		//2.建立文件写入流对象,关联文件。
		FileReader fr=new FileReader("C:\\copy_1.java");
		
		//3.读取文件数据。
		int ch=0;
		while((ch=fr.read())!=-1)
		{
			fw.write(ch);	
		}
		
		//4.关闭资源。close方法会先flush在释放Windows资源。
		fw.close();
		fr.close();
	}
	public static void textcopy_2() 
	{
		//1.建立文件读取、写入流对象的引用。
		FileWriter fw=null;
		FileReader fr=null;
		//处理将会抛出异常的代码。
		try 
		{
			//2.文件实例化
			fw=new FileWriter("c:/zzz.java");
			fr=new FileReader("C:\\copy_2.java");
			//3.读取文件数据,写入到目的地。
			char[] buf=new char[1024];
			int len=0;
			while((len=fr.read(buf))!=-1)
			{
				fw.write(buf,0,len);
			}
		} 
		catch (IOException e) 
		{
			throw new RuntimeException("读写失败");
		}
		finally
		{
			//4.关闭资源。
			if(fr!=null)
			{
				try 
				{
					fr.close();
				} 
				catch (IOException e) 
				{
					throw new RuntimeException("读取文件流关闭失败");
				}
			}
			if(fw!=null)
			{
				try 
				{
					fw.close();
				} 
				catch (IOException e) 
				{
					throw new RuntimeException("写入文件流关闭失败");
				}
			}
		}
	}
}
示例二:带缓冲区复制文本文件

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Day19_03缓冲区复制文件 {
	public static void main(String[] args) 
	{
		//1.建立文件读取、写入流对象的引用,避免变量不能跨代码块使用。
		BufferedWriter bufw=null;
		BufferedReader bufr=null;
		try 
		{
			//2.实例化流对象,关联文件。
			bufr= new BufferedReader(new FileReader("C:\\java.txt"));
			bufw= new BufferedWriter(new FileWriter("C:\\javacopy.txt"));
			
			//3.读取文本数据。一次读取一行数据。
			//readLine方法的原理:无论是读一行,获取读取多个字符。其实最终都是在硬盘上一个一个读取。
			//所以最终使用的还是read方法一次读一个的方法。
			String line=null;
			while((line=bufr.readLine())!=null)
			{
				bufw.write(line);
				bufw.newLine();//写入换行符(跨平台)
				bufw.flush();//将缓冲区的数据刷新至输出流对象中,将数据写入到文件
			}	
		} 
		catch (IOException e) 
		{
			throw new RuntimeException("读写失败");
		}
		finally
		{
			//4.关闭资源。
			try 
			{
				if(bufr!=null)
				{
					bufr.close();
				}
			} 
			catch (IOException e) 
			{
				throw new RuntimeException("读取关闭失败");
			}
			try 
			{
				if(bufw!=null)
				{
					bufw.close();
				}
			} 
			catch (IOException e) 
			{
				throw new RuntimeException("写入关闭失败");
			}
		}
	}
}

第三讲 装饰设计模式

一、定义:当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。那么自定义的该类称为装饰类。

二、特点

        1、装饰类通常会通过构造方法接收被装饰的对象。

        2、并基于被装饰类的对象的功能,提供更强的功能。

三、装饰和继承的区别:

        1、装饰模式比继承要灵活。避免了继承体系的臃肿,且降低了类与类之间的关系。

        2、装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰类都必须所属同一个接口或者父类。

        3、从继承结构转为组合结构。

注:1、在定义类的时候,不要以继承为主;可通过装饰设计模式进行增强类功能。灵活性较强,当装饰类中的功能不适合,可再使用被装饰类的功能。

        2、BufferedWriter、BufferedReader也是装饰类。

示例三:MyBufferedReader的例子就是最好的装饰设计模式的例子。

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
class MyBufferedReader extends Reader//Reader里面有抽象方法必须覆盖
{
	//1.将FileReader对象传入,基于已有的功能,并提供加强功能。
	private FileReader r;
	MyBufferedReader(FileReader r)
	{
		this.r=r;
	}
	//2.一次读一行数据。
	public String myReadLine() throws IOException
	{
		//定义一个临时容器。原BufferReader封装的是字符数组。
		//3.为了演示方便。定义一个StringBuilder容器。因为最终还是要将数据变成字符串。
		StringBuilder sb = new StringBuilder();
		int num=0;
		while((num=r.read())!=-1)
		{
			//识别换行符。Windows换行 \r\n
			if (num=='\r') 
			{
				continue;
			} 
			else if(num=='\n')
			{
				return sb.toString();		
			}
			else
				sb.append((char)num);
		}
		if(sb.length() != 0)
			return sb.toString();
		return null;
	}
	public void myClose() throws IOException
	{
		r.close();	
	}
	//4.覆盖Reader类中的抽象方法。
	public void close() throws IOException
	{
		r.close();
	}
	public  int read(char[] cbuf, int off, int len)  throws IOException
	{
		return r.read(cbuf,  off,  len);
	}
}
public class Day19_05MybufferedReader 
{
	public static void main(String[] args)  throws IOException
	{
		//1.建立读取流对象,关联文件。
		FileReader fr=new FileReader("buf.txt");
		//2.加入自定义的缓冲包装读取流对象。
		MyBufferedReader myBuf=new MyBufferedReader(fr);
		//3.读取数据并,打印在控制台上。
		String line=null;	
		while((line=myBuf.myReadLine()) !=null)
		{
			System.out.println(line);
		}
		//4.关闭资源。
		myBuf.myClose();
	}
}

四、行号LineNumberReader

LineNumberReader:

        1、跟踪行号的缓冲字符输入流。此类定义了方法 setLineNumber(int) 和 getLineNumber(),它们可分别用于设置和获取当前行号。
        2、默认情况下,行编号从 0 开始。该行号随数据读取在每个行结束符处递增,并且可以通过调用 setLineNumber(int) 更改行号。但要注意的是,setLineNumber(int) 不会实际更改流中的当前位置;它只更改将由 getLineNumber() 返回的值。 
        3、可认为行在遇到以下符号之一时结束:换行符('\n')、回车符('\r')、回车后紧跟换行符。
示例四:行号
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
public class Day19_09LineNumberReader 
{
	public static void main(String[] args) throws IOException
	{
		//1.建立读取文件流对象。
		FileReader fr=new FileReader("copy.txt");
		LineNumberReader lnr=new LineNumberReader(fr);
		String line=null;
		//lnr.setLineNumber(100);//起始值从100开始
		while((line=lnr.readLine())!= null)
		{
			System.out.println(lnr.getLineNumber()+":"+line);
		}
		lnr.close();
	}
}

第四讲 字节流

一、字节流与字符流的不同

        1.基本操作与字符流类相同,但它不仅可以操作字符文件,还可以操作其他媒体文件。

        2.由于媒体文件数据中都是以字节存储的,所以,字节流对象可直接对媒体文件的数据写入到文件中,而可以不用再进行刷流flush动作。

二、字节流复制媒体文件步骤:

1、建立一个流对象,将已存在的一个文件加载进流。

        FileInputStream fis = new FileInputStream("山水间.mp3");

2、建立流对象,关联数据存放文件。

        FileOutputStream fos = new FileOutputStream("c:\\山水间copy.mp3");

加上true属性续写文件。

        FileOutputStream fos = new FileOutputStream("c:\\山水间copy.mp3",true);

注意:1、2步会抛出异常:

        FileNotFound - 如果文件不存在,或者它是一个目录,而不是一个常规文件,或者无法打开进行读取。

        SecurityException - 如果存在安全管理器,且其 checkRead 方法拒绝对文件进行读取访问。

3、读取数据、写入数据。

        1)方式一:读、写单个字节

                读取: int num = fis.read();

                写入: fos.write(num);

        2)方式二:读取、写入规定大小的字节数组

                读取: byte[] buf=new byte[1024];

                int len=0;

                len=fis.read(buf);//返回的是实际读取的字节数量

                写入:fos.write(buf,0,len);

        3)方式三:读取、写入文件大小的字节数组。

                byte[] buf=new byte[fis.available()];//定义一个刚刚好的缓冲区,不用在循环了

                读取: fis.read(buf);

                写入: fos.write(buf);

注意:可以利用此方法来指定读取方式中传入数组的长度,从而省去循环判断。但是如果文件较大,而虚拟机启动分配的默认内存一般为64M。当文件过大时,此数组长度所占内存空间就会溢出。所以,此方法慎用,当文件不大时,可以使用。

        4)方式四:加入缓冲区提高读取数据的效率。

                缓冲读取流:BufferedInputStream bufis=new BufferedInputStream(fis);

                缓冲输出流:BufferedOutputStream bufos=new BufferedOutputStream(fos);

                        byte[] buf=new byte[1024];

                        int len=0;

                        len=bufis.read(buf);

                        fos.write(buf,0,len);

                        bufis.close();

                        bufos.close();

注意关闭了缓冲流对象,也就关闭了fis.close(); fos.close();

4、关闭资源

        fis.close();

        fos.close();

注意:字节流的Read()、write()方法

对于读取字节文件,当读取的字节是11111111是即-1,此时read方法会默认数据读取至流末,就结束了读取导致文件残缺,为了避免这种情况发生:

        1)read()方法返回的是4字节的int类型,API规定了这个方法会把读取的字节的高字节位置补零3个字节,因此如果读到数据,返回值必然在0到255之间,如果未读到返回-1;

        2)write(int)的参数是4个字节的int类型,实现类在写入时会强转为1个字节的byte类型,这个强转会发生去掉溢出的3个字节,比如write(256),实际写入的是0x00,也就等效于write(0);

示例五:复制图片

/*
复制一个图片
思路:
1.用字节读取流对象和图片关联。
2.用字节写入流对象创建一个图片文件。用于存储获取到的图片数据。
3.通过循环读写,

图片读一段会查表,字符流别拷贝媒体文件。
 * */
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class PicCopy
{
	public static void main(String[] args) 
	{
		//1.建立字节流对象引用。
		FileOutputStream fos=null;
		FileInputStream fis=null;
		//处理会抛异常的代码
		try 
		{
			//2.流对象实例化。
			fos=new FileOutputStream("c:\\copy.png");
			fis=new FileInputStream("c:\\1.png");
			//3.读取字节数组数据
			byte [] buf=new byte[1024];
			int len=0;
			while((len=fis.read(buf))!=-1)
			{
				//4.写入字节数组数据。
				fos.write(buf,0,len);
			}
		} 
		catch (IOException e) 
		{
			throw new RuntimeException("复制文件失败");
		}
		finally
		{
			//5.关闭资源。
			try 
			{
				if(fis!=null)
					fis.close();
			} 
			catch (IOException e1) 
			{
				throw new RuntimeException("写入文件失败");
			}
			try 
			{
				if(fos!=null)
					fos.close();
			} 
			catch (IOException e2) 
			{
				throw new RuntimeException("读取文件失败");
			}
		}
	}
}



三、字节流缓冲区

1、基本操作与字符流类相同

但它不仅可以操作字符,还可以操作其他 媒体文件

示例六:字节流缓冲区复制mp3

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Mp3Copy 
{
	public static void main(String[] args) throws IOException 
	{
		//计算复制文件的时间
		long start=System.currentTimeMillis();
		piccopy();
		long end=System.currentTimeMillis();
		System.out.println((end-start)+"毫秒");
	}
	public static void piccopy() throws IOException
	{
		//1.建立文件读取、写入流对象,关联文件。
		BufferedInputStream bufis=new BufferedInputStream(new FileInputStream("D:\\时间煮雨.mp3"));
		BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("D:\\时间煮雨copy.mp3"));
		
		int by=0;
		byte [] buf=new byte[1024];
		//2.读取数据
		while((by=bufis.read(buf)) !=-1)
		{
			//3.写入数据。
			bufos.write(buf,0,by);
		}
		//4.关闭资源。
		bufos.close();
		bufis.close();	
	}
}

示例七:自定义缓冲区复制MP3

import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
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
	{
		//byte型&0xff向上转成int型
		if(count==0)
		{
			count=in.read(buf);
			if(count<0)
				return -1;
			pos=0;
			byte b= buf[pos];
			count--;
			pos++;
			return b&0xff;
		}
		else if(count>0)
		{
			byte b=buf[pos];
			count--;
			pos++;
			return b&255;	
		}
		return -1;	
	}
	public void myClose() throws IOException
	{
		in.close();
	}
}
public class MyBuffer 
{
	public static void main(String[] args) throws IOException
	{
		//计算复制时间。
		long start=System.currentTimeMillis();
		mp3_copy();
		long end=System.currentTimeMillis();
		System.out.println((end-start)+"毫秒");
	}
	public static void mp3_copy() throws IOException
	{
		//1.建立文件读取、写入流对象。
		MyBufferedInputStream bufis=new MyBufferedInputStream(new FileInputStream("D:\\小时代 - 时间煮雨.mp3"));
		BufferedOutputStream bufos=new BufferedOutputStream(new FileOutputStream("D:\\小时代 - 时间煮雨copy.mp3"));
		//2.读取数据
		int by=0;	
		while((by=bufis.myRead()) !=-1)//read在提升
		{
			//3.写入数据。
			bufos.write(by);//write在强转 保证原数据不变 避免-1的发生。
		}
		//4.关闭资源。
		bufos.close();
		bufis.myClose();
	}
	
}

四、补充:

一、核心功能实现类:所谓的核心功能实现类,也就是实现了最基础的写入功能——实现了原子操作write(int)和read()。ByteArrayOutputStream实现内存字节流的写入。

ByteArrayInputStream实现内存字节流的读取。

1、内存读写已经保证了多线程安全,但是文件读写没有保证;

2、内存读写不需要调用close方法;而文件读写使用文件系统,必须调用close方法释放文件资源;

3、字节流核心写入类都不带缓存功能,因此直接使用时无需调用flush方法;

4、FileOutputStream对象在创建时,就会执行一个native的open操作,如果是覆盖模式,此操作会立刻清除原文件内容,因此创建覆盖模式的FileOutputStream对象要非常谨慎,就算我们没做任何写入操作,文件内容也会被覆盖。

5、ByteArrayInputStream支持标记和重置功能,FileInputStream不支持;

6、ByteArrayInputStream的mark(int)方法中,参数无意义,随便传。

二、装饰功能——缓存读写BufferedOutputStream、BufferedInputStream:

FilterOutputStream在close方法中默认调用flush方法,这样在使用字节流写入的装饰子类时,无需在关闭前调用flush方法了。

五、注意事项:

1、缓存读写的装饰类都额外保证了读写操作的多线程安全性;

2、缓存读写的缓存大小默认都是8KB,可以通过构造方法指定,但读取操作的缓存是可变的,使用中大小可能发生变化;

3、缓存读取还附带实现了标记和重置功能,不同于ByteArrayInputStream的标记重置功能,BufferedInputStream读取提供的mark(int)的参数有意义,指定了标记在多少个字节内是起效的。

第五讲流操作规律

一、System类中的标准流

1、“标准”输入流

        static InputStream in 

2、“标准”输出流

        static PrintStream out

        PrintStream的父类是FilterOutputStream。

3、通过System类的setIn,setOut方法可以对默认设备进行改变

         将标准输入改成文件。

                System.setIn(newFileInputStream(“Demo.java”));

        将目的改成文件

                 System.setOut(newFileOutputStream(“info.txt”));

示例八:流改变标准输入输出设备

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintStream;

public class TransStreamDemo
{
	public static void main(String[] args) throws IOException
	{
		//System.setIn(new FileInputStream("Demo.java"));
		//1.将标准输出流目的地改为文件。
		System.setOut(new PrintStream("zzz.txt"));
		
		//2.建立带缓冲功能的键盘输入流、输出流、文件输出流对象。
		BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));
		BufferedWriter bufile=new 
				BufferedWriter(new OutputStreamWriter(new FileOutputStream("UTF.txt"),"UTF-8"));
		//3.读取键盘数据。
		String line=null;
		while((line=bufr.readLine())!=null)
		{
			if("over".equals(line))
				break;
			//4.将数据写入到zzz.txt
			bufw.write(line.toUpperCase());
			//5.将数据按照UTF-8编码表,写入到UTF.txt中
			bufile.write(line);
			//刷流。
			bufile.newLine();
			bufile.flush();
			bufw.newLine();
			bufw.flush();
			
		}
		//6.关闭资源。
		bufr.close();
		bufw.close();
	}
}

二、转换流InputStreamReader,OutputStreamWriter

 一、转换流的由来

         InputStreamReader 是字节流通向字符流的桥梁。

         OutputStreamWriter 是字符流通向字节流的桥梁。

方便了字符流与字节流之间的操作

二、转换流的应用

        字节流中的数据都是字符时,转成字符流操作更高效。

        例如:InputStreamReader将字节流通向字符流

                1)、获取键盘录入对象。

                        InputStream in = System.in;

                2)、将字节流对象转成字符流对象,使用转换流。

                        InputStreamReader isr = new InputStreamReader(in);

                3)、为了提高效率,将字符串进行缓冲区技术高效操作,使用BufferedReade这样就可以调用readLine方法。

                        BufferedReader bufr = new BufferedReader(isr);

三、键盘录入最常见写法

        BufferedReader bufi = new BufferedReader(new InputStreamReader(System.in));

        打印到控制台的常见写法

        BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));

示例九:键盘录入数据将其小写字母变成大写字母打印到控制台上

/*读取键盘录入
System.out:对应的是标准输出设备,控制台
System.in:对应的是标准输入设备:键盘

需求:通过键盘录入数据。
当录入一行数据后,就将该行数据进行打印。
如果录入的数据是over,那么就停止录入。

通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。
也就是readLine方法。

能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?

readLine方法时字符流BufferedReader类中的方法。
而键盘录入的read方法是字节流InputStream的方法。
那么能不能将字节流转成字符流在使用字符流缓冲区的readLine方法呢?
*/
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class Day19_15IO读取键盘录入 
{
	public static void main(String[] args) throws IOException
	{
//		//1.获取键盘录入对象
//		InputStream in=System.in;
//		//将字节流对象转成字符流对象,使用转换流。InputStreamReader
//		InputStreamReader isr=new InputStreamReader(in);
//		//为了提高效率,将字符串进行缓冲区技术高效操作。使用BufferedReader
//		BufferedReader bufr=new BufferedReader(isr);
		//3句合并   键盘录入最常见写法。
		BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
	
//		OutputStream out=System.out;
//		OutputStreamWriter osw=new OutputStreamWriter(out);
//		BufferedWriter bufw=new BufferedWriter(osw);	
		//建立控制台流对象。加入缓冲。
		BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));
		
		//2.每次读取一行字符串。
		String line=null;
		while((line=bufr.readLine())!=null)
		{
			if("over".equals(line))
				break;
			//3.打印数据到控制台上
			bufw.write(line.toUpperCase());
			bufw.newLine();
			bufw.flush();	
		}
		//4.关闭资源。
		bufr.close();
		
/*	第二种方式	
		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);
		}
*/
	}
}

三、流操作规律

流操作的基本规律,通过三个步骤来完成。

        1.明确源和目的。

                源:输入流。InputStream Reader

                目的:输出流。OutputStream Writer

        2.操作的数据是否是纯文本。

                是:字符流。

                不是:字节流。

        3.当体系明确后,在明确要使用哪个具体的对象。

                通过设备来进行区分:

                源设备:内存、硬盘、键盘

                目的设备:内存、硬盘、控制台。

示例分析:

        1.将一个文本文件中数据存储到另一个文件中。复制文件。

                1)源:因为是源,所以使用读取流。InputStream Reader

                        是不是操作文本文件。

                        是!这时就可以选择Reader

                        这样体系就明确了。

                2)接下来明确使用该体系中的哪个对象。

                        明确设备:硬盘。上一个文件。

                        Reader体系中可以操作文件的对象时FileReader

                                FileReader fr=new FileReader("a.txt");

                                BufferedReader bufr=new BufferedReader(fr);

                        是否需要提高效率:是!  加入Reader体系中的缓冲区BufferedReader

                        目的:OutputStream Writer

                        是否是纯文本。

                        是!Writer

                        设备:硬盘,一个文件

                        Writer体系中可以操作文件的对象FileWriter。

                        是否需要提高效率:是!  加入Writer体系中的缓冲区BufferedWriter

                                FileWriter fw=new FileWriter("a.txt");

                                BufferedWriter bufw=new BufferedWriter(fr);


        2.需求:将键盘录入的数据保存到一个文件中。

                1)这个需求中有源和目的存在。

                        那么分别分析

                        源:InputStream Reader

                        是不是纯文本?是!Reader

                2)设备:键盘。对应额是System.in.

                        不是选择Reader吗?System.in对应的不是字节流吗?

                        为了操作键盘的文本数据方便。转成字符流按照字符串操作时最方便的。

                        所以既然明确了Reader,那么就将System.in转换成Reader。

                        用了Reader体系中转换流,InputStreamReader

                                InputStreamReader isr=new InputStreamReader(System.in);

                        需要提高效率吗?需要!BufferedReader

                                BufferedReader bufr=new BufferedReader(isr);

                3)目的:OutputStream Writer

                        是否是纯文本? 是! Writer。

                        设备:硬盘。一个文件。 使用FileWriter。

                                FileWriter fw=new FileWriter("c.txt");

                        需要提高效率吗?需要。

                                BufferedWriter bufw=new BufferedWriter(fw);

        3、把录入的数据按照指定的编码表(utf-8),将数据存到文件中。

                1)目的:OutputStream Writer

                        是否是纯文本? 是! Writer。

                        设备:硬盘。一个文件。 使用FileWriter。

                2)但是FileWriter是使用默认编码表。GBK。

                        但是存储时,需要加入指定编码表。而指定的编码表只有转换流可以指定。

                        所以要使用的对象时OutputStreamWriter。

                        而该转换流对象要接收一个字节输出流。而且还可以操作的文件的字节输出流。FileOutputStream

                                OutputStreamWriter osw= new OutputStreamWriter(new FileOutputStream("d.txt"), "UTF-8") 

                3)需要提高效率吗?需要。

                                BufferedWriter bufw=new BufferedWriter(osw);

                        所以记住。转换流什么使用。字符和字节之间的桥梁,通常涉及到字符编码转换时,需要用到转换流。

                        FileReader使用的默认编码GBK

                                OutputStreamWriter(OutputStream out, String charsetName) 

                                创建使用指定字符集的 OutputStreamWriter。

见示例八

第六讲系统信息与异常的日志信息

一、异常的日志信息

        当程序在执行过程中的时候,try代码块中的语句可能会抛出的异常,被catch语句捕捉到将抛出的错误信息以日志的形式存储起来,形成异常的日志信息。方便程序员分析错误。

示例十:异常的日志信息

import java.io.*;
import java.text.*;
import java.util.*;
class  ExceptionInfo
{
	public static void main(String[] args) 
	{
		try
		{
			int[] arr =new int[2];
			System.out.println(arr[3]);

		}
		catch (Exception e)
		{
			try
			{
				Date d=new Date();
			
				SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
				String s=sdf.format(d);

				PrintStream ps=new PrintStream("info.log");
				System.setOut(ps);//修改输出流设备
				ps.println(s);//输出时间
				
			}
			catch (IOException ex)
			{
				throw new RuntimeException("文件创建失败");
			}
			e.printStackTrace(System.out);//将异常信息数据写入到info.log
		}
	}
}

二、系统信息

        1.获取系统信息:

                Properties getProperties()

        2.将信息输出到指定输出流中

                 void list(PrintStream out)

        3.将输出流中数据存入指定文件中

                new PrintStream("info.txt")

示例一十一:系统信息

import java.util.*;  
import java.io.*;  
class SystemInfo   
{  
   public static void main(String[] args)   
   {   
       PrintStream ps = null;  
       try  
       {  
          //获取系统信息对象  
          Properties pop = System.getProperties();  
          //创建输出流对象,将输出流中数据存入指定文件中  
          ps = new PrintStream("info.txt");  
          //将属性列表输出到指定的输出流  
          pop.list(ps);  
       }  
       catch (Exception e)  
       {  
 			throw new RuntimeException("获取系统信息失败。");  
       }  
    }  
}

你可能感兴趣的:(JAVA基础博客)