Day 19 IO流

Day 19 IO流

IO(Input Output)流
IO流用来处理设备之间的数据传输
Java对数据的操作是通过流的方式
Java用于操作流的对象都在IO包中
流按操作数据分为两种:字节流与字符流
流按流向分为:输入流,输出流

IO流常用基类
字节流的抽象基类:InputStream、OutputDtream
字符流的抽象类:Reader、Writer
注:由这四个类攀升出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream
如:Reader的子类FileReader

字符流特点:
既然IO流是用于操作数据的,那么数据的最常见体现形式是:文件。
那么久先以操作文件为主来演示。
需求:在硬盘上,创建一个文件并写入一些文字数据。
找到有个专门用于操作文件的Writer子类对象,FileWriter。后缀名是父类名,前缀名是该流对象的功能。

FileWriter

import java.io.*;

class FileWriterDemo 
{
	public static void main(String[] args) throws IOException
	{
		//创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。
		//而且该文件会被创建到指定目录下。
		//如果该目录下已有同名文件,将被覆盖。
		//其实该步就是在明确数据要存放的目的地。
		FileWriter fw = new FileWriter("demo.txt");
		
		//调用write方法,将字符串写入到流中。
		fw.write("abcde");
		
		//刷新流对象中的缓冲中的数据,将数据刷到目的地中。
		//fw.flush();

		//fw.write("haha");
		//fw.flush();
		
		//关闭流资源,但是在关闭之前会刷新一次内部的缓冲中的数据。
		//将数据刷到目的地中。
		//和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。
		fw.close();
	}
}

IO异常处理方式

import java.io.*;

class FileWriterDemo2 
{
	public static void main(String[] args) 
	{
		//在外面建立引用,在try内部初始化
		FileWriter fw = null;
		try
		{
			fw = new FileWriter("demo.txt");
			fw.write("asdfgghh");
		}
		catch (IOException e)
		{
			System.out.println(e.toString());
		}
		finally
		{
			//finally中一定要对关闭的流对象进行非空判断
			//如果有多个流对象要跟别关和判断
			try
			{
				if(fw != null)
					fw.close();	
			}
			catch (IOException e)
			{
				System.out.println(e.toString());
			}	
			
		}
		
	}
}

文件的续写
演示对已有文件的数据续写。

import java.io.*;

class FileWriterDemo3 
{
	public static void main(String[] args) throws IOException
	{
		//传递一个true参数,代表不覆盖已有文件,
		//并在已有文件的末尾处进行数据续写。
		FileWriter dw = new FileWriter("demo.txt",true);
		fw.write("haha\r\nxiexie");
		fw.close();
		//Linux系统下\n,windows记事本不识别\r\n
		//应该是FileWriterDemo2中的try catch finally
	}
}

文本文件读取方式
方式一
read的close():关闭该流并释放与之关联的所有资源。(注意与write的close区别:不刷新)
在这里插入图片描述

import java.io.*;

class FileReaderDemo 
{
	public static void main(String[] args) throws IOException
	{
		//创建一个文件读取流文件,和指定名称的文件相关联。
		//要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException
		FileReader fr = new FileReader("demo.txt");

		//调用读取流对象的read方法
		//read():一次读一个字符,而且会自动往下读。
		
		int ch = 0;
		while ((ch = fe.read())!=-1)
		{
			System.out.println("ch = " + (char)ch);	
		}
		
		/*
		while (true)
		{
			int ch = fr.read();
			if (ch == -1)
				break;
			System.out.println("ch = " + (char)ch);		
		}
		*/
		fr.close();
	}
}

方式二
通过字符数组进行读取:读取的字符数,如果已到达流的末尾,则返回-1。
只打印有效部分
在这里插入图片描述

import java.io.*;

class FileReaderDemo2 
{
	public static void main(String[] args) throws IOException
	{
		FileReader fr = new FileReader("demo.txt");
		//定义一个字符数组,用于存储读到的字符。
		//该read(char[])返回的是读到的字符个数。
		char[] buf = new char[1024];

		int num = 0;
		while ((num = fr.read(buf))!=-1)
		{
			//从0开始取,取num个
			System.out.println(new String(buf,0,num));
		}		
		fr.close();
	}
}

总结:方式二好
方式一:读一个打一个
方式二:读一个存一下最后全打

文本文件读取练习
练习1:读取一个java文件,并打印在控制台上。

import java.io.*;

class FileReaderTest 
{
	public static void main(String[] args) throws IOException
	{
		FileReader fr = new FileReader("DateDemo.java");
		char[] buf = new char[1024];
		int num = 0;
		while ((num = fr.read(buf))!=-1)
		{
			System.out.print(new String(buf,0,num));
	//如果在print后面+ln,如果数据大于1024,1024满了之后会先被打印一次
	//读到哪打到哪,可能会出现在等号位置回车,在不该换行处换行了,数据显示不舒服
		}
		fr.close();
	}
}

练习2:将C盘一个文本文件复制到D盘
复制原理:将C盘下的文件数据存储到D盘的一个文件中。
步骤:
1.在D盘创建一个文件,用于存储C盘文件中的数据。
2.定义读取流和C盘文件关联。
3.通过不断的读写完成数据存储。
4.关闭资源。

import java.io.*;

class CopyTest 
{
	public static void main(String[] args) throws IOException
	{
		copy_2();
	}

	//从C盘读取一个字符,就往D盘写一个字符,不推荐
	public static void copy_1() throws IOException
	{
		//创建目的地
		FileWriter fw = new FileWriter("RuntimeDemo_copy.txt");
		
		//与已有文件关联
		FileReader fr = new FileReader("RuntimeDemo.java");
		
		int ch = 0;

		while ((ch = fr.read())!=-1)
		{
			fw.write(ch);
		}
		fw.close();
		fr.close();
	}

	public static void copy_2()
	{
		FileWriter fw = null;
		FileReader fr = null;
		try
		{
			fw = new FileWriter("SystemDemo_copy.txt");
			fr = new FileReader("SystemDemo.java");

			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
		{
			if (fw!=null)
				try
				{
					fw.close();
				}
				catch (IOException e)
				{
				}
		}
	}
}

拷贝文本文件图例
在这里插入图片描述字符流的缓冲区
缓冲区的出现提高了对数据的读写效率
对应类:BufferedWriter,BufferedReader
缓冲区要结合流才可以使用
在流的基础上对流的功能进行了增强

缓冲区的出现时为了提高流的操作效率而出现的,所以在创建缓冲区之前必须要现有流对象。
该缓冲区提供了一个跨平台的换行符:newLine();

BufferedWriter
BufferedWriter(Write out):创建一个使用默认大小输出缓冲区的缓冲字符输出流
BufferedWriter(Write out,int sz):创建一个使用给定大小输出新缓冲区的缓冲字符输出流

import java.io.*;

class BufferedWriterDemo 
{
	public static void main(String[] args) throws IOException
	{
		//创建一个字符写入流对象
		FileWriter fw = new FileWriter("buf.txt");
		
		//为了提高字符写入流效率,加入了缓冲技术
		//只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。
		BufferedWriter bufw = new BufferedWriter(fw);
		/*
		bufw.write("abcde");
		//newLine 写入一个行分隔符,跨平台
		bufw.newLine();
		*/
		for (int x = 1; x<5; x++)
		{
			bufw.write("abcd" + x);
			bufw.newLine();
			bufw.flush();
		//写一次刷一次,如果丢你存到缓冲区最后刷,停电了缓冲区内的内容释放了
		}

		//记住,只要用到缓冲区就要刷新
		//bufw.flush();

		//关闭缓冲区,就是在关闭缓冲区的流对象
		//缓冲区为了提高效率而存在,提高new FileWriter的效率,还有进行写操作,和文件相关联,真正调用底层资源
		//缓冲区关闭的就是它所提高效率的流对象,不需要fw.close();
		bufw.close();
	}
}

BufferedReader
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
BufferedReader(Reader in)创建一个使用默认大小缓冲区的缓冲字符输入流。
BufferedReader(Reader in,int sz )创建一个使用指定大小输入缓冲区的缓冲字符输入流。
readLine 读取一个行文本。返回该行内容的字符串,不包含任何终止符,如果已到达流末尾,则返回 null。

字符读取流缓冲区:该缓冲区提供了一个一次读一行的方法 readLine,方便于对文本数据的获取。当返回null时,表示读到文件末尾。
readLine方法返回的时候只返回回车符之前的数据内容,并不返回回车符。

import java.io.*;

class BufferedReaderDemo 
{
	public static void main(String[] args) throws IOException
	{
		//创建一个读取流对象和文件相关联
		FileReader fr = new FileReader("buf.txt");

		//为了提高效率,加入缓冲技术,将字符读取流对象作为参数传递给缓冲区对象的构造函数。
		BufferedReader bufr = new BufferedReader(fr);

		String line = null;
		while ((line = bufr.readLine())!=null)
		{
			System.out.println(line);
		}
		/*
		//readLine 读取一个行文本
		String s1 = bufr.readLine();
		System.out.println("s1 : " + s1);
		*/
		bufr.close();
	}
}

通过缓冲区复制文本文件
通过缓冲区复制一个.java文件。

import java.io.*;

class CopyTextByBuf 
{
	public static void main(String[] args) 
	{
		BufferedReader bufr = null;
		BufferedWriter bufw = null;

		try
		{
			bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java"));
			bufw = new BufferedWriter(new FileWriter("bufWriter_Copy.txt"));

			String line = null;//两个流之间中转站

			while ((line = bufr.readLine())!=null)
			{
				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("读取关闭失败");
			}

			try
			{
				if(bufw!=null)
					bufw.close();
			}
			catch (IOException e)
			{
				throw new RuntimeException("写入关闭失败");
			}
		}
	}
}

readLine的原理图例
在这里插入图片描述MyBufferedReader
明白了BufferedReader类中特有方法readLine的原理后,可以自定义一个类中包含一个功能和readLine一致的方法,来模拟一下BufferedReader。

import java.io.*;

class MyBufferedReader 
{
	private FileReader r;
	MyBufferedReader(FileReader r)
	{
		this.r = r;
	}
	
	//定义的功能,抛出问题让对方知道出现的问题
	//可以一次读一行数据的方法
	public String myReadLine() throws IOException
	{
		//定义一个临时容器,原BufferedReader封装的是字符数组
		//为了演示方便,定义一个StringBulilder容器,因为最终还是要将数据变成字符串
		StringBuilder sb = new StringBuilder();

		int ch = 0;
		while ((ch = r.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
	{
		r.close();
	}
}

class MyBufferedReaderDemo
{
	public static void main(String[] args) throws IOException
	{
		FileReader fr = new FileReader("buf.txt");
		
		MyBufferedReader myBuf = new MyBufferedReader(fr);
		
		String line = null;
		
		while ((line = myBuf.myReadLine())!=null)
		{
			System.out.println(line);
		}
		myBuf.myClose();
	}
}

装饰设计模式
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。那么自定义的该类称为装饰类。基于原有的类优化。
装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。

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("开胃酒");
		//System.out.println("吃饭");
		p.chifan();
		System.out.println("喝粥");
		System.out.println("甜点");
	}
}
class PersonDemo 
{
	public static void main(String[] args) 
	{
		Person p = new Person();
		//p.chifan();
		SuperPerson sp = new SuperPerson(p);
		sp.superChifan();
	}
}

装饰和继承的区别
MyReader//专门用于读取数据的类
|–MyTextReader
|–MyBufferTextReader
|–MyMediaReader
|–MyBufferMediaReader
|–MyDataReader
|–MyBufferDataReader
class MyBufferReader
{
MyBufferReader(MyTextReader text)
{}
MyBufferReader(MyMediaReader media)
{}
}
上面这个类扩展性很差,找到其参数的共同类型,通过多态的形式,可以提高扩展性。
class MyBufferReader extends MyReader
{
private MyReader r;
MyBufferReader(MyReader r)
{}
}
—>装饰
MyReader//专门用于读取数据的类
|–MyTextReader
|–MyMediaReader
|–MyDataReader
|–MyBufferReader
装饰模式比继承要灵活,避免了继承体系的臃肿,而且降低了类与类之间的关系。
装饰类因为是增强已有对象,具备的功能和已有对象是相同的,只不过提供了更强的功能,所以装饰类和被装饰类通常是都属于一个体系中的。
从继承结构变成组合结构。
继承要写功能抽取出来的,继承不要写的过多,不要以继承为主,如果仅仅为了其中某几个功能而产生子类,体系过于臃肿,可以通过装饰来扩展这些类的功能。灵活性在于:有一个对象一年前建立了,后期不满意可以自己写个类把对象传进来就可以了。当我写的功能有问题时,直接去掉用你写的功能就可以了。

自定义装饰类

import java.io.*;

class MyBufferedReader extends Reader
{
	private Reader r;
	MyBufferedReader(Reader r)
	{
		this.r = r;
	}
	
	//定义的功能,抛出问题让对方知道出现的问题
	//可以一次读一行数据的方法
	public String myReadLine() throws IOException
	{
		//定义一个临时容器,原BufferedReader封装的是字符数组
		//为了演示方便,定义一个StringBulilder容器,因为最终还是要将数据变成字符串
		StringBuilder sb = new StringBuilder();

		int ch = 0;
		while ((ch = r.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;
	}
	
	//覆盖Reader类中的抽象方法
	public int read(char[] cbuf,int off,int len) throws IOException
	{
		return r.read(cbuf,off,len);
	}

	public void close() throws IOException
	{
		r.close();
	}
	public void myClose() throws IOException
	{
		r.close();
	}
}

class MyBufferedReaderDemo
{
	public static void main(String[] args) throws IOException
	{
		FileReader fr = new FileReader("buf.txt");
		
		MyBufferedReader myBuf = new MyBufferedReader(fr);
		
		String line = null;
		
		while ((line = myBuf.myReadLine())!=null)
		{
			System.out.println(line);
		}
		myBuf.myClose();
	}
}

LineNumberReader
跟踪行号的缓冲字符输入流。
setLineNumber(int),getLineNumber():分别可分别用于设置和获取当前行号。默认情况下,行编号从0开始。

import java.io.*;

class LineNumberReaderDemo 
{
	public static void main(String[] args) throws IOException
	{
		FileReader fr = new FileReader("PersonDemo.java");
		LineNumberReader lnr = new LineNumberReader(fr);
		String line = null;
		lnr.setLineNumber(100);
		while ((line = lnr.readLine())!=null)
		{
			System.out.println(lnr.getLineNumber() + ":" + line);
		}
		lnr.close();
	}
}

练习:模拟一个带行号的缓冲区对象。

import java.io.*;
class MyLineNumberReader extends MyBufferedReader
{
	private int lineNumber;
	//父类已经有传值进来的动作
	MyLineNumberReader(Reader r)
	{
		super(r);
	}
	public String myReadLine() throws IOException
	{
		lineNumber++;
		return super.myReader();
	}

	public void setLineNumber(int lineNumber)
	{
		this.lineNumber = lineNumber;
	}
	public int getLineNumber()
	{
		return lineNumber;
	}
	
}

/*
class MyLineNumberReader 
{
	private Reader r;
	private int lineNumber;
	//在构造函数中将被包装的对象传递进来
	MyLineNumberReader(Reader r)
	{
		this.r = r;
	}
	public String myReadLine() throws IOException
	{
		lineNumber++;
		StringBuilder sb = new StringBuilder();
		int ch = 0;
		while ((ch = r.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 setLineNumber(int lineNumber)
	{
		this.lineNumber = lineNumber;
	}
	public int getLineNumber()
	{
		return lineNumber;
	}
	public void myClose() throws IOException
	{
		r.close();
	}
}
*/
class MyLineNumberReaderDemo
{
	public static void main(String[] args) throws IOException
	{
		FileReader fr = new FileReader("copyTextReader.java");
		MyLineNumberReader mylnr = new MyLineNumberReader(fr);
		String line = null;
		mylnr.setLineNumber(100);
		while ((line = mylnr.myReadLine())!=null)
		{
			System.out.println(mylnr.getLineNumber() + ":" + line);
		}
		mylnr.myClose();
	}
}

字符流:FileReader,FileWriter,BufferedReader,BufferedWriter
字节流:InputStream,OutputStream

字节流File读写操作
需求:想要操作图片数据,这是就要用到字节流。
字节流特有 available():返回次输入下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。

import java.io.*;

class FileStream 
{
	public static void main(String[] args) throws IOException
	{
		//writeFiles();
		//readFile_1();
		//readFile_2();
		readFile_3();
	}

	public static void readFile_3() throws IOException
	{
		FileInputStream fis = new FileInputStream("fos.txt");
		//int num = fis.available();
		
		byte[] buf = new byte[fis.availble()];
		//定义一个刚刚好的缓冲区,不用再循环了
		//数据没有太大,可以使用这种方法,如果太大不建议使用
		//使用方法2,1024的整数倍
		
		fis.read(buf);

		//System.out.println("num = " + num);
		System.out.println(new String(buf));
		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.println(new String(buf,0,len));
		}
		fis.close();
	}

	public static void readFile_1() throws IOException
	{
		FileInputStream fis = new FileInputStream("fos.txt");
		int ch = 0;
		while ((ch=fis.read())!=-1)
		{
			System.out.println((char)ch);
		}
		fis.close();
	}

	public static void writeFiles() throws IOException
	{
		FileOutputStream fos = new FileOutputStream("fos.txt");
		
		fos.write("abcde".getBytes());

		fos.close();
	}
}

拷贝图片
复制一个图片。
思路:
1.用字节读取流对象和图片关联
2.用字节写入流对象创建一个图片文件,用于存储获取到得图片数据。
3.通过循环读写,完成数据的村到户。
4.关闭资源。

import java.io.*;

class CopyPic 
{
	public static void main(String[] args) 
	{
		FileOutputStream fos = null;
		FileInputStream fis = null;
		try
		{
			fos = new FileOutputStream("c:\\2.bmp");
			fis = new FileInputStream("c:\\1.bmp");

			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("写入关闭失败");
			}
		}
	}
}

字节流的缓冲区
演示MP3的复制,通过缓冲区。
BufferedOutputStream
BufferedInputStream

import java.io.*;

class CopyMp3 
{
	public static void main(String[] args) throws IOException
	{
		long start = System.currentTimeMillis();
		copy_1();
		long end = System.currentTimeMillis();
		System.out.println((end-start) + "毫秒");
	}

	//通过字节流的缓冲区完成复制
	public static void copy_1() throws IOException
	{
		BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("c:\\0.mp3"));
		BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
		
		int by = 0;
		while ((by = bufis.read())!=-1)
		{
			bufos.write(by);
		}
		bufos.close();
		bufis.close();
	}
}

自定义字节流的缓冲区-read和write的特点
抓一批数据进来,进内存一个一个取,取光了再抓一批。
在这里插入图片描述将byte类型提升为int类型:读取到8为二进制8个1,为了避免-1和判断结束标志-1相同,在保留原8个1的基础上转成int类型在前面补0,不补1。
在这里插入图片描述byte提升为int,1个字节提升为4个字节;读一个字节数据,返回来4个字节,往外写的时候是按照int往外写,应该是原来数据的4倍。read方法在向上提升,往前面补0,保证不是-1这种情况的发生,write做强转,把最低8位写出去,剩下的不要,写出有效数据。read方法在提升,write方法做强制转换,保证原数据不变化。
write(int b):将制定的字节写入此缓冲的输入流。

import java.io.*;

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 bufis = new BufferedInputStream(new FileInputStream("c:\\0.mp3"));
		BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
		
		int by = 0;
		while ((by = bufis.read())!=-1)
		{
			bufos.write(by);
		}
		bufos.close();
		bufis.close();
	}
	
	//自定义字节流的缓冲区
	public static void copy_2() throws IOException
	{
		MyBufferedInputStream bufis = new MyBufferedInputStream(new FileInputStream("c:\\0.mp3"));
		BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\2.mp3"));
		
		int by = 0;
		
	//	System.out.println("第一个字节:" + bufis.myRead());

		while ((by = bufis.myRead())!=-1)
		{
			bufos.write(by);
		}
		bufos.close();
		bufis.myClose();
	}	
}
/

import java.io.*;

class MyBufferedInputStream 
{
	private InputStream in;
	private byte[] buf = new byte[1024*4];
	private int pos = 0,count = 0;
	
	MyBufferedInputStream(InputStream in)//装饰
	{
		this.in = in;
	}
	
	//从缓冲区(字节数组)获取,一次读一个字节
	public int myRead() throws IOException
	{
		//通过in对象读取硬盘上的数据,并存储buf中。
		if (count == 0)
		{
			count = in.read(buf);
			
			if(count<0)
				return -1;

			pos = 0;

			byte b = buf[pos];
			count--;
			pos++;
			return b & oxff;//保留4位,&15;保留8位,&255;
		}
		else if (count > 0)
		{
			byte b = buf[pos];
			count--;
			pos++;
			return b;
		}
		return -1;
	}
	public void myClose() throws IOException
	{
		in.close();
	}
}

读取键盘录入
字符流:FileReader,FileWritwe;BufferedReader,BufferedWriter
字节流:FileInputStream,FileOutStream;BufferedInputStream,BufferedOutputStream

读取键盘录入。
System.out:对应的是标准输出设备,控制台。
System.in:对应的是标准的输入设备,键盘。
需求:通过键盘录入数据。当录入一行数据后,就将该行数据进行打印。如果录入的数据是over,那么停止录入。

import java.io.*;

class Readin
{
	public static void main(String[] args) throws IOException
	{
		InputStream in = System.in;
		
		//int by = in.read();
		//System.out.println(by);
		
		//录入一堆,一下输出,敲回车打印,定义缓冲区
		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);
		}

		/*
		//一个字节一个字节录入
		int ch = 0;
		while ((ch = in.read())!=-1)
		{
			System.out.println(ch);
		}
		*/
		in.close();
		//不关也没事,因为程序结束键盘录入也结束。	
	}
}

读取转换流
通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理,也就是readLine方法。能不能直接使用readLine方法来完成键盘录入一行数据的读取呢?
readLine方法是字符流BufferedReader类中的方法,而键盘录入的read方法是字节流InputStream的方法。
那么能不能将字节流转换成字符流再使用字符流缓冲区的readLine方法呢?
InputStreamReader:是字节流桐乡字符流的桥梁,它使用指定的charset读取字节并将其解码为字符,它使用的字符集可以由名称指定货显式给定,或者可以接收平台默认的字符集。

import java.io.*;

class  TransStreamDemo
{
	public static void main(String[] args) throws IOException
	{
		//获取键盘录入对象
		InputStream in = System.in;

		//将字节流对象装成字符流对象,使用转换流,InputStreamReader
		InputStreamReader isr = new InputStreamReader(in);

		//为了提高效率,将字符串进行缓冲区技术高效操作,使用BufferedReader
		BufferedReader bufr = new BufferedReader(isr);

		String line = null;
		while ((line = bufr.readLine())!= null)
		{
			if ("over".equals(line))
				break;
			System.out.println(line.toUpperCase());
		}
		bufr.close();
	}
}

写入转换流
OutputStreamWriter:是字符流通向字节流的桥梁:可使用指定的charset将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接收平台默认的字符集。

字符到字节:本身有一些熟悉的文字,写入文件中,文件以字节形式在硬盘上存在,往里录入的都是字符。

import java.io.*;

class  TransStreamDemo
{
	public static void main(String[] args) throws IOException
	{
		/*
		//获取键盘录入对象
		InputStream in = System.in;

		//将字节流对象装成字符流对象,使用转换流,InputStreamReader
		InputStreamReader isr = new InputStreamReader(in);

		//为了提高效率,将字符串进行缓冲区技术高效操作,使用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);
		三句话变成一句话
		*/
		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());
		//	bufw.write(line.toUpperCase() + "\r\n");
			bufw.write(line.toUpperCase());
			bufw.newLine();
			
			//字符输出流内部有缓冲区,刷新
			bufw.flush();
		}
		bufr.close();
	}
}

流操作规律
1.
源:键盘录入。
目的:控制台。
2.需求:想把键盘录入的数据存储到一个文件中。
源:键盘。
目的:文件。
2.需求:想要将一个文件的数据打印在控制台上。
源:文件。
目的:控制台
流操作的基本规律:
最痛苦的就是流对象有很多,不知道该用哪一个。通过两个明确来完成。
1.明确源和目的。
源:输入流。InputStream Reader
目的:输出流。OutputStream Writer
2.当体系明确后,在明确要使用哪个具体的对象。通过设备类进行区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台

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 buwr = new BufferedWriter(fw);

练习:将一个图片文件中数据存储到另一个文件中,复制文件。
Buffered字节流的缓冲区。

2.需求:将键盘录入的数据保存到一个文件中。
这个需求中有源和目的都存在。那么分别分析。
源:InputStream Reader
是不是纯文本?是。Reader。
设备:键盘。对应的对象是System.in
不是选择Reader吗?System.in对应的不是字节流吗?为了操作键盘的文本数据方便,转成字符流,按照字符串操作最方便。所以既然明确了Reader,那么就将System.in转换成Reader。用到了Reader体系中的转换流,InputStreamReader。
InputStreamReader isr = new InputStreamReader(System.in);
是否需要提高效率:是。加入Reader体系中缓冲区 BufferedReader。
BufferedReader bufr = new BufferedReader(isr);
目的:OutputStream Writer
是否是纯文件:是。Writer。
设备:硬盘,一个文件。Writer体系中可以操作文件的对象是 FileWriter。
FileWriter fw = new FileWriter(“c.txt”);
是否需要提高效率:是。加入Writer体系中缓冲区 BufferedWriter。
BufferedWriter buwr = new BufferedWriter(fw);

扩展:想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。
OutputStreamWriter(OutputStream out,String charsetName)
创建使用指定字符集的OutputStreamWriter。
目的:OutputStream Writer
是否是纯文件:是。Writer。
设备:硬盘,一个文件。Writer体系中可以操作文件的对象是 FileWriter。
但是FileWriter是使用的默认编码表 GBK。
但是存储时,需要加入指定编码表 utf-8,而指定的编码表只有转换流可以指定。所以要使用的对象是OutputStreamWriter。而该转换流对象要接收一个字节输出流,而且还可以操作文件的字节输出流 FileOutputStream。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStreram(“d.txt”),“UTH-8”);
是否需要提高效率:是。加入Writer体系中缓冲区 BufferedWriter。
BufferedWriter buwr = new BufferedWriter(osw);

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

import java.io.*;

class  TransStreamDemo3
{
	public static void main(String[] args) throws IOException
	{
		BufferedReader bufr = 
			new BufferedReader(new InputStreamReader(System.in));
		
		BufferedWriter bufw = 
			new BufferedWriter(new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8"));
		
		String line = null;
		while ((line = bufr.readLine())!= null)
		{
			if ("over".equals(line))
				break;
			bufw.write(line.toUpperCase());
			bufw.newLine();
			bufw.flush();
		}
		bufr.close();
	}
}

练习:讲一个文本数据打印在控制台上。
System.out

改变标准输入输出设备
setIn(InputStream in):重新分配“标准”输入流。
setOut(PrintStream out):重新分配“标准”输出流。

import java.io.*;

class  TransStreamDemo3
{
	public static void main(String[] args) throws IOException
	{
		//源是一个文件,目的是一个文件,复制
		System.serIn(new FileInputStream("PersonDemo.java"));
		
		System.setOut(new PrintStream("zzz.txt"));

		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();
		}
		bufr.close();
	}
}

异常的日志信息
log4j——专门完成日志信息的建立

import java.io.*;
import java.util.*;
import java.text.*;

class ExceptionInfo 
{
	public static void main(String[] args) throws IOException
	{
		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("execption.log");
			//	ps.weite(d.toString().getBytes());
				ps.println(s);
				System.setOut(ps);
			}
			catch (IOException ex)
			{
				throw new RuntimeException("日志文件创建失败");
			}
			e.printStackTrace(System.out);	
		}
	}
}

系统信息

import java.util.*;
import java.io.*;

class SystemInfo 
{
	public static void main(String[] args) throws IOException
	{
		Properties prop = System.getProperties();
	//	System.out.println(prop);
	//	prop.list(System.out);

		prop.list(new PrintStream("sysinfo.txt"));
	}
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值