黑马程序员_IO流

 ----------------- android培训java培训、期待与您交流! ----------
字符流的由来:
  • 以前处理数据都是字节数据,使用字节流技术就可以完成了。
  • 因为后期编码表的不断出现,识别某一文字的码表不唯一。比如中文,GBK,unicode都可以识别。就出出现了编码问题。
  • 中文字节数据 gbk --> 流处理--->gbk解析可以了。 
后期:容器出现这样的问题:
  • 中文字节数据gbk --> 流处理 unicode来处理-->数据错误。
  • 为了处理文字数据,就需要通过 字节流技术+编码表 相结合来完成。注意:只有文字是这样的,因为文字涉及编码问题。
  • 其他数据比如dvd mp3 图片等是不涉及这个问题的。
  • 虽然字节流+编码表可以解决文字数据处理问题,但是较为麻烦。为了便于使用,将字节流和编码表进行了封装,就出现了便于文字操作的流技术:字符流。
  • 其实字符流就是:字节流+编码表。
IO的体系:
字节流两个基类:
InputStream(字节输入流)  OutputStream(字节输出流)
字符流两个基类:
Reader(字符输入流) Writer(字符输出流)

学习io流体系:看顶层(父类共性功能),用底层(子类具体对象)。
该体系的一个好处就是:
每个子类的后缀名都是所属体系的父类的名称,很容易区分所属的体系。而且每一个子类前缀名都是该子类对象的功能体现。这样我们在使用io体系中的对象时,就非常容易查找了。

需求:将一个段文字数据写入到硬盘上.
思路:
  • 一段文字就是字符串数据。
  • 写到硬盘上,从哪到哪呢?字符串数据在内存中,写到硬盘上,哎呦!这不是将内存中的数据搞到硬盘上,这就涉及到了设备之间的数据处理。就要用到IO技术。既然是从内存到硬盘,应该是输出流。
  • 对于文字而言,io中提供了便捷的操作,比如字符流。
  • 结合两者,需要输出流,需要字符流,可是使用字符输出流。Writer
  • 具体用哪个子类对象呢?硬盘上用于存储数据的体现:文件。希望可以在Writer体系中知道可以操作文件的Writer对象。 找到了具体的对象FileWriter.
两个写入流往一个文件写入数据,就如同,两个人在同时往一张纸写字一样。都是从头开始写,第二人写的会将第一个人的文字覆盖掉。

演示代码:

package com.itheima.IO;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;

public class FileWriterDemo
{
	private static final String LINE_SPARATOR = System.getProperty("line.separator");

	public static void main(String[] args) throws IOException
	{
		printProperty();
		
		FileWriter fw = new FileWriter("demo", true);
		fw.write("hello,there!"+LINE_SPARATOR+"Damon");
		fw.flush();
		fw.close();
	}

	private static void printProperty()
	{
		Properties prop = System.getProperties();
		Set<String> nameSet = prop.stringPropertyNames();
		for(String name : nameSet)
		{
			String value = prop.getProperty(name);
			System.out.println(name+"::"+value);
		}
	}
}

标准IO异常处理代码:

FileWriter fw = null;
try
{
	fw = new FileWriter("k:\\demo3.txt");
	fw.write("abcde");
	fw.flush();
}
catch(IOException e)
{
	System.out.println(e.toString());
}
finally
{
	if (fw != null)
		try
		{
			fw.close();
		}
		catch (IOException e)
		{
			// 相关的代码处理。比如说,将关闭失败的信息记录到日志文件中。
			throw new RuntimeException("关闭失败");
		}
}


需求:读取一个硬盘上的文本文件,将数据打印到控制台上。 
思路:
  • 读取无非就是将硬盘的数据弄到内存中。要使用到输入流。 
  • 既然是文字,可以使用字符流,一综合使用字符输入流,该体系时Reader.
  • 既然要读取一个文本文件。可以使用 FileReader:用于读取字符文件的便捷类。

字符流的缓冲区。
BufferedReader
BufferedWriter

缓冲区给给流的操作动作(读写)提高效率.所以缓冲区的对象建立必须要有流对象。

代码演示:

package com.itheima.IO;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderDemo
{
	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException
	{
		demo_1();
		demo_2();
	}

	private static void demo_2() throws FileNotFoundException, IOException
	{
		FileReader fr = new FileReader("demo");
		char[] buf = new char[100];
		int len = 0;
		while ((len=fr.read(buf)) != -1)
		{
			System.out.println(new String(buf, 0, len));
		}
	}

	private static void demo_1() throws FileNotFoundException, IOException
	{
		FileReader fr = new FileReader("demo");
/*		int ch = fr.read();
		System.out.println("ch="+ch);
*/
		int ch = 0;
		while ((ch=fr.read()) != -1)
		{
			System.out.print((char)ch);
		}
		fr.close();
	}
}

复制文本文件代码演示:

package com.itheima.IO;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyTxtDemo
{

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException
	{
		methed_1();
		method_2();
		System.out.println("OK!");
	}

	private static void method_2() throws FileNotFoundException, IOException
	{
		FileReader fr = new FileReader("demo");
		FileWriter fw = new FileWriter("cptxtfile2");
		
		char[] cbuf = new char[1024];
		int len = 0;
		while ((len=fr.read(cbuf)) != -1)
		{
			fw.write(cbuf, 0, len);
		}
		
		fr.close();
		fw.close();
	}

	private static void methed_1() throws FileNotFoundException, IOException
	{
		FileReader fr = new FileReader("demo");
		FileWriter fw = new FileWriter("cptxtfile");
		
		int ch = 0;
		while ((ch=fr.read()) != -1)
		{
			fw.write(ch);
		}
		
		fr.close();
		fw.close();
	}

}

标准写法,异常处理:

package com.itheima.IO;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CopyOfCopyTxtDemo2
{
	/**
	 * @param args
	 */
	public static void main(String[] args) 
	{
		FileReader fr = null;
		FileWriter fw = null;
		char[] cbuf = new char[1024];
		int len = 0;
		
		try
		{
			fr = new FileReader("demo");
			fw = new FileWriter("cptxtfile3");
	
			while ((len=fr.read(cbuf)) != -1)
			{
				fw.write(cbuf, 0, len);
			}
		}
		catch (Exception e)
		{
			System.out.println(e.toString());
		}
		finally
		{
			if (fw != null)
				try
				{
					fw.close();
				}
				catch (IOException e2)
				{
					throw new RuntimeException("写入关闭失败");
				}
				
			if (fr != null)
				try
				{
					fr.close();
				}
				catch (IOException e2)
				{
					e2.printStackTrace();
				}
		}
	}
}





代码演示:

package cn.itcast.io.p5.mybuffer;

import java.io.IOException;
import java.io.Reader;

public class MyBufferedReader extends Reader{

	/*
	 * 缓冲区在定义时,必须有被缓冲的流对象。
	 * 该流对象是通过构造函数传递的。 
	 * 
	 * 缓冲区最大的特点就是可以提高效率,
	 * 原因在于对数据进行是临时存储。
	 * 所以需要定义个容器(数组)。
	 * 
	 * 
	 * 
	 */
	private Reader r;
	
	private char[] buf = new char[1024];
	//用于记录存储到缓冲区中字符个数的变量
	private int count = 0;
	
	//用于操作数组中的元素的角标。
	private int pos = 0;

	public MyBufferedReader(Reader r) {
		super();
		this.r = r;
	}
	
	/*
	 * 定义一个读取方法,从缓冲区中读取一个字符。
	 * 实现原理:
	 * 1,先通过具体的流对象的read([])方法,从目的中读取一批数据存储到缓冲数组中。
	 * 
	 */
	public int myRead() throws IOException{
		
		//读取一批数据到缓冲数组buf中。 
		//当count为0时,就从目的中取一批数据到缓冲数组。
		if(count==0){
			count = r.read(buf);
			pos = 0;	
		}
		
		if(count<0)
			return -1;	
			
		char ch = buf[pos];
		count--;
		pos++;
		
		return ch;
		
	}
	
	/*
	 * 自定义一个读取一行的方法。
	 * 原理:
	 * 1,通过myRead方法从缓冲区中读取字符,并进行存储,
	 * 当读取到的字符时换行终止符时,就将存储的数据作为字符串返回。
	 */
	public String myReadLine() throws IOException{
		
		//1,定义容器。最终要变成字符串。可以使用StringBuilder
		StringBuilder sb = new StringBuilder();
		
		int ch = 0;
		while((ch=myRead())!=-1){
			
			if(ch=='\r')
				continue;
			if(ch=='\n')
				return sb.toString();
			
			sb.append((char)ch);
		}
		
		if(sb.length()!=0)
			return sb.toString();
		
		return null;
		
	}
	
	
	/*
	 * 关闭缓冲区。
	 */
	public  void  myClose() throws IOException{
		r.close();
	}

	@Override
	public void close() throws IOException {
	}

	@Override
	public int read(char[] cbuf, int off, int len) throws IOException {
		
		return 0;
	}
}

package cn.itcast.io.p5.mybuffer.demo;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import cn.itcast.io.p5.mybuffer.MyBufferedReader;

public class MyBufferedReaderDemo {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {

//		buffferDemo();
//		myBufferDemo();
		readLineDemo();
		myReadLineDemo();
		
		
	}
	
	private static void myReadLineDemo() throws IOException {
		
		FileReader fr = new FileReader("buf.txt");
		MyBufferedReader myBufr = new MyBufferedReader(fr);
		
		String line = null;
		while((line=myBufr.myReadLine())!=null){
			System.out.println("mybuffer:"+line);
		}
		
		myBufr.myClose();
	}

	public static void readLineDemo() throws IOException{
		FileReader fr = new FileReader("buf.txt");
		
		BufferedReader bufr = new BufferedReader(fr);
		
		String line = null;
		while((line=bufr.readLine())!=null){
			System.out.println("buffer:"+line);
		}
		
		bufr.close();
	}
	
	private static void myBufferDemo() throws IOException{
		
		FileReader fr = new FileReader("demo.txt");
		MyBufferedReader myBufr = new MyBufferedReader(fr);
		
		int ch = 0;
		while((ch=myBufr.myRead())!=-1){
			System.out.println((char)ch);
		}
		
		myBufr.myClose();
	}

	private static void buffferDemo() throws FileNotFoundException, IOException {
		FileReader fr = new FileReader("demo.txt");
		
		BufferedReader bufr = new BufferedReader(fr);
		
		int ch = 0;
		//使用了缓冲区的一次读一个方法,从缓冲区中读取字符。
		while((ch=bufr.read())!=-1){
			System.out.println((char)ch);
		}
		
		bufr.close();
	}

}

高效复制文本文件方法:

package com.itheima.io;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class CpyTxtByBufferDemo
{

	public static void main(String[] args)
	{
		cpyTxtBufferedDemo();
	}

	private static void cpyTxtBufferedDemo()
	{
		BufferedReader bfr = null;
		BufferedWriter bfw = null;
		
		try
		{
			bfr = new BufferedReader(new FileReader("buf.txt"));
			bfw = new BufferedWriter(new FileWriter("cpy.txt"));
			
			String line = null;	
			for(;(line=bfr.readLine()) != null;)
			{
				bfw.write(line);
				bfw.newLine();
				bfw.flush();
			}
		} 
		catch (Exception e)
		{
			e.printStackTrace();
		}
		finally
		{
			if (bfw != null)
				try
				{
					bfw.close();
				}
				catch (Exception e)
				{
					throw new RuntimeException("写入关闭失败");
				}
				
			if (bfr != null)
				try
				{
					bfr.close();
				}
				catch (Exception e)
				{
					throw new RuntimeException("读取关闭失败");
				}				
		}
	}
}

IO流体系:


字符流:
Reader
|--BufferedReader:
|--LineNumberReader
|--CharArrayReader
|--StringReader
|--InputStreamReaer
|--FileReader

Writer
|--BufferedWriter
|--CharArrayWriter
|--StringWriter
|--OutputStreamWriter
|--FileWriter
|--PrintWriter

字节流:
InputStream
|--FileInputStream:
|--FilterInputStream
|--BufferedInputStream
|--DataInputStream
|--ByteArrayInputStream
|--ObjectInputStream
|--SequenceInputStream
|--PipedInputStream

OutputStream
|--FileOutputStream
|--FilterOutputStream
|--BufferedOutputStream
|--DataOutputStream
|--ByteArrayOutputStream
|--ObjectOutputStream
|--PipedOutputStream
|--PrintStream

RandomAccessFile:

打印流:
 PrintStream:
  • 使它们能够方便地打印各种数据值表示形式.
  • 提供了一系列的打印功能.可以打印任何数据。 
  • 它的特有的方法不抛出异常。 
 
 构造方法:
 该流是一个处理目的的流对象。 
 目的:
  • File对象。   可以指定字符集
  • 字符串路径。可以指定字符集
  • 字节输出流。可以对println方法进行自动刷新。

使用PrintStream继承的方法。write。
out.write(866); //write将接收到整数的最后一个字节写入到流。
使用PrintStream的特有方法。print.
out.print(865);//print方法,可以将参数的数据表现形式打印到目的中。原理是将97转成字符串,在write到目的。 

print方法打印各种数据都会将其变成字符串。所以可以保证数据的原有表现形式。


一般不用PrintWriter定义指定的编码表。为啥呢?
 因为要操作编码表有专用的对象。转换流。
 而且转换流不仅可以设置写的编码表,还可以设置读的编码表

练习:
package com.itheima.io;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;

public class StudentInfoTool
{
	/**
	 * 通过键盘录入获取信息,并将信息封装成学生对象,存到集合中。  
	 * @throws IOException 
	 */
	
	public static Set<Student> getStudentSet() throws IOException
	{ 
		return getStudentSet(null);
	}

	public static Set<Student> getStudentSet(Comparator<Student> comp) throws IOException
	{
		BufferedReader br = null;
		Set<Student> stuSet = null;
		if (comp != null)
			stuSet = new TreeSet<Student>(comp);
		else
			stuSet = new TreeSet<Student>();
		try 
		{
			br = new BufferedReader(new InputStreamReader(System.in));
			String line = null;
			for (;(line=br.readLine()) != null;)
			{
				if ("over".equals(line))
					break;
				else
				{
					String[] arr = line.split(",");
					Student stu = new Student(arr[0], Double.parseDouble(arr[1]), 
							Double.parseDouble(arr[2]), Double.parseDouble(arr[3 ]));
					stuSet.add(stu);
				}
			}
		}
		finally
		{
			if (br != null)
			{
				try
				{
					br.close();
				}
				catch (IOException e)
				{
 					throw new RuntimeException("关闭键盘录入失败!");
				}
			}
		}
		return stuSet;
	}
	
	// 将数据写入文件
	public static void write2File(Set<Student> setStu, File dest) throws IOException
	{
		BufferedWriter bufw = null;
		try 
		{
			bufw = new BufferedWriter(new FileWriter(dest));
			bufw.write("name"+"\t"+"sum"+"\t"+"cn"+"\t"+"en"+"\t"+"ma");
			bufw.newLine();
			for (Student stu : setStu)
			{
				bufw.write(stu.getName()+"\t"+stu.getSum()+"\t"+stu.getCn()
						+"\t"+stu.getEn()+"\t"+stu.getMa());
				bufw.newLine();
				bufw.flush();
			}
		}
		finally
		{
			if (bufw != null) try
			{
				bufw.close();
			}
			catch (IOException e)
			{
				throw new RuntimeException("写入关闭失败");
			}
		}
	}
}

package com.itheima.io;
public class Student implements Comparable<Student>
{
	private String name;
	private double ma,cn,en;
	private double sum;
	public Student()
	{
		super();
	}
	
	public Student(String name, double ma, double cn, double en)
	{
		super();
		this.name = name;
		this.ma = ma;
		this.cn = cn;
		this.en = en;
		this.sum = ma + cn + en;
	}
	
	public String getName()
	{
		return name;
	}
	public void setName(String name)
	{
		this.name = name;
	}
	public double getMa()
	{
		return ma;
	}
	public void setMa(double ma)
	{
		this.ma = ma;
	}
	public double getCn()
	{
		return cn;
	}
	public void setCn(double cn)
	{
		this.cn = cn;
	}
	public double getEn()
	{
		return en;
	}
	public void setEn(double en)
	{
		this.en = en;
	}
	public double getSum()
	{
		return sum;
	}
	public void setSum(double sum)
	{
		this.sum = sum;
	}


	// 总分从小到大排序
	@Override
	public int compareTo(Student o)
	{
		double tmp = this.sum - o.sum;
		return (int) (tmp==0 ? this.name.compareTo(o.getName()) : tmp);
	}
}
package com.itheima.io;
import java.util.Comparator;
public class OrderByMath implements Comparator<Student>
{
	public int compare(Student o1, Student o2)
	{
		int tmp = (int) (o1.getMa() - o2.getMa());
		return tmp==0 ? o1.getName().compareTo(o2.getName()) : tmp;
	}
}

package com.itheima.io;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.Set;

public class Test1
{
	public static void main(String[] args) throws IOException
	{
//		Comparator<Student> comp = Collections.reverseOrder();
		Comparator<Student> comp = Collections.reverseOrder(comp = new OrderByMath());
		
		Set<Student> set = StudentInfoTool.getStudentSet(comp);
		File dir = new File("TempFile");
		if (!dir.exists())
			dir.mkdir();
		File dest = new File(dir, "stuinfo");
		
		StudentInfoTool.write2File(set, dest);
	}
 }


File中构造时,指定的路径可以是存在的,也可以是不存在的。 
//将c盘下的demo.txt封装成file对象。
File f1 = new File("c:\\demo.txt");
//将c盘下的abc文件夹封装成file对象。
File f2 = new File("c:\\abc");

1,获取文件信息。

  •   获取名称,
  •   获取路径。
  •   获取大小。
  •   获取时间。
2,判断。
  •   是只读的不?
  •   是隐藏的不?
3,文件的创建和删除以及该文件是否存在,文件对象自己最清楚。
  •   具体创建,删除,是否存在等功能。

FileDemo:

package com.itheima.io;
import java.io.File;
import java.io.IOException;

public class FileDemo
{
	private static final String FILE_SEPARATOR = System.getProperty("file.separator");
	private static final String PATH_SEPARATOR = System.getProperty("path.separator");
	private static final String LINE_SEPARATOR = System.getProperty("line.separator");
	public static void main(String[] args) throws IOException
	{
		 
		 System.out.println(FILE_SEPARATOR);
		 System.out.println(PATH_SEPARATOR);
		 System.out.println(LINE_SEPARATOR);
		 
		 fileConsDemo();
	}
	private static void fileConsDemo() throws IOException
	{
		File f1 = new File(FILE_SEPARATOR+"User"+FILE_SEPARATOR+"mskv"+FILE_SEPARATOR+"file.demo");
		System.out.println(f1); // 构造时File类封装的对象可以存在或者不存在
		
		// File类给出了路径分隔符和名称分割符的字段
		File f2 = new File(File.separator+"User"+File.separator+"mskv"+File.separator+"file.demo");
		System.out.println(f2);
		
		//创建
		//不存在,创建;存在,不创建。不覆盖。输出流会覆盖,若不覆盖,在构造函数中如true参数,续写
		File f = new File("TempFile/FileDemo"); 
		boolean b = f.createNewFile();
		System.out.println(b);
		
		// 删除
		boolean b1 = f.delete();
		System.out.println(b1);
		 
		//是否存在
		boolean b2 = f.exists();
		System.out.println(b2);
		
		File[] roots = File.listRoots();
		for (File root : roots)
		{
			System.out.println(root);
		}
	}
}

package com.itheima.io;
import java.io.File;
public class FileDemo2
{
	public static void main(String[] args)
	{
		demo();
	}
	
	private static void demo()
	{
		File f = new File("TempFile");
		String[] lists = f.list();
		for (String list : lists)
		{
			System.out.println(list);
		}
		
		File file = new File("TempFile");
		File[] fs = file.listFiles();
		for (File ff : fs)
		{
			System.out.println(ff);
		}
	}
}

FileTest:
package com.itheima.io;
import java.io.File;
public class FileTest
{
	public static void main(String[] args)
	{
		File dir = new File(File.separator+"Users"+File.separator+"mskv"+File.separator+"workspace");
		showDir(dir, 0);
	}

	private static void showDir(File dir, int count)
	{
		System.out.println(getSeparator(count)+"DIR:"+dir);
		count++;
		File[] files = dir.listFiles();
		if (files !=null)
			for (File ff : files)
			{
				if (ff.isDirectory())
					showDir(ff, count);
				System.out.println(getSeparator(count)+ff.getName());
			}
	}

	private static String getSeparator(int count)
	{
		StringBuilder sb = new StringBuilder();
		for (int i=0; i<count; i++)
			sb.append("-");
		return sb.toString();
	}
}

package com.itheima.io;
import java.io.File;
public class FileTest2
{
	public static void main(String[] args)
	{
		// 删除一个带内容的目录
		// 必须从里往外(一层一层)删
		File dir = new File("/Users/mskv/Demo");
		removeDir(dir);
	}
	
	public static void removeDir(File dir)
	{
		File[] files = dir.listFiles();
		if (files != null)
			for (File file : files)
			{
				if (file.isDirectory())
					removeDir(file);
				else
					file.delete();
			}	
		dir.delete();		
	}
}


PropertiesDemo:
package com.itheima.io;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;

public class PropertiesDemo
{
	public static void main(String[] args) throws IOException
	{
		demo();
		loadDemo();
	}


	private static void loadDemo() throws IOException
	{
		Properties prop = new Properties();
		BufferedReader bfr = new BufferedReader(new FileReader("TempFile/prop"));
		String line = null;
		for (;(line=bfr.readLine()) != null;)
		{
			String[] strs = line.split("=");
			prop.setProperty(strs[0], strs[1]);
		}
		bfr.close();
		prop.list(System.out);
	}


	private static void demo() throws IOException
	{
		Properties prop = new Properties();
		FileInputStream fis = new FileInputStream("TempFile/prop");
		prop.load(fis);
		prop.list(System.out);
		fis.close();
	}
}


Properties应用:

package com.itheima.io;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;

public class PropertiesTest
{
	public static void main(String[] args) throws IOException
	{
		// 记录软件试用次数,到期提示注册
//		runDemo();
		if (runDemo())
			System.out.println("runing...");
		else
			System.out.println("试用次数结束,请注册!");
	}


	private static boolean runDemo() throws IOException
	{
		// 读取配置文件
		Properties prop = new Properties();
		File conf = new File("TempFile/conf");
		if (!conf.exists())
			conf.createNewFile();
		BufferedReader br = new BufferedReader(new FileReader(conf));
		
		// 加载到流中
		prop.load(br);
		
		// 获取运行次数
		int count = 0;
		String value = prop.getProperty("count");
		if (value != null)
		{
			count = Integer.parseInt(value);
			if (count > 2)
			{
//				System.out.println("试用次数结束,请注册!");
				return false;
			}
		}
		count++;
//		System.out.println("运行"+count+"次");
		
		// 存储次数到配置文件
		prop.setProperty("count", String.valueOf(count));
		BufferedWriter bw = new BufferedWriter(new FileWriter(conf));
		prop.store(bw, "");
		
		bw.close();
		br.close();
		return true;
	}
}

装饰设计模式。
 解决的问题:给已有的对象提供增强额外的功能。还不用对原有对象进行修改。 
 比继承更为灵活。
 Writer
  |--TextWriter
  |--MediaWriter
 
  •  现有一个体系用于各种数据的写入。
  •  但是,发现写入效率有点低。想要对其进行效率的提高。
  •  可以使用缓冲技术来完成的。
  •  已有对象中的写入方法,不够高效,可以通过派生子类的形式对其进行复写,定义高效的写入动作。
 Writer
  |--TextWriter
  |--BufferTextWriter
  |--MediaWriter
  |--BufferMediaWriter
  |--DataWriter
  |--BufferDataWriter
  •  通过继承的方式提高了效率。
  •  但是对于扩展性是一个问题。而且所需的功能越多,子类就越多。
  •  一旦加入新类,就需要为它提供高效。麻烦!
  •  如何解决这个问题呢?优化!
  •  既然都需要缓冲,对数据写入效率进行提高 。
  •  可以转变一下思想,这样来做,将缓冲技术单独进行封装。
  •  哪个对象需要缓冲,就把哪个对象传递给缓冲对象即可。 
 class Buffer{
 
  Buffer(TextWriter w){
  }
  Buffer(MediaWriter w){
  }
 
 }
 为了便于扩展,可以对一组对象进行缓冲。 
 class BufferWriter extends Writer{
  Buffer(Writer w){
  }
  public void write(){
  }
 }
 体系就变成了这样:
 
 Writer
  |--TextWriter
  |--MediaWriter
  |--BufferWriter
  •  BufferWriter的出现,增强了Writer体系中的功能。
  •  这种设计方式比原理更为灵活,避免了继承的臃肿。
  •  将这样解决方式就定义了一个名称方便于后人使用:装饰设计模式。
  •  记住:装饰类和被装饰类都所属于同一个体系。 

 代码演示:
package com.itheima.io;
public class DecoratorDemo
{
	public static void main(String[] args)
	{
		Person p = new Person();
		SubPerson  sp = new SubPerson(p);
		sp.eat();
	}
}

class Person
{
	public void eat()
	{
		System.out.println("吃饭");
	}
}

class SubPerson
{
	private Person p;
	SubPerson(Person p)
	{
		this.p = p;
	}
	
	public void eat()
	{
		System.out.println("清汤");
		p.eat();
		System.out.println("甜点");
	}
}


装饰类LineNumberReader演示:
package com.itheima.io;
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 lnr = null;
		
		try
		{
			fr = new FileReader("TempFile//Demo");
			lnr = new LineNumberReader(fr);
			String line = null;
			for (;(line = lnr.readLine()) != null;)
			{
				System.out.println(lnr.getLineNumber()+":"+line);
			}
		}
		catch (FileNotFoundException e)
		{
			e.printStackTrace();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		
	}

FileInputStream演示:
package com.itheima.io;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileInputStreamDemo
{
	private static FileInputStream fis;

	public static void main(String[] args) throws Exception
	{
//		method_1();
//		method_2();
		// 创建一个刚刚好大小的数组缓冲区
		method_3();
	}

	private static void method_3() throws FileNotFoundException, IOException
	{
		fis = new FileInputStream("TempFile//Demo");
		byte[] bBuf = new byte[fis.available()];//文件过大不推荐,可能造成内存溢出
		fis.read(bBuf);
		System.out.println(new String(bBuf));
		fis.close();
	}

	private static void method_2() throws FileNotFoundException, IOException
	{
		fis = new FileInputStream("TempFile//Demo");
		byte[] bBuf = new byte[4096];
		int len = 0;
		for (;(len=fis.read(bBuf)) != -1;)
		{
			System.out.println(new String(bBuf, 0, len));
		}
		fis.close();
	}


	// 读一个打印一个
	private static void method_1() throws FileNotFoundException, IOException
	{
		fis = new FileInputStream("TempFile//Demo");
		int ch = 0;
		for (;(ch=fis.read()) != -1;)
		{
			System.out.println("ch="+(char)ch);
		}
		fis.close();
	}
} 



字节流演示(复制mp3文件):
package com.itheima.io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class CpyMp3Demo
{
	public static void main(String[] args) throws IOException
	{
		long start = System.currentTimeMillis();
//		cpyMp3();
		cpyMp3_2();
		long end = System.currentTimeMillis();
		System.out.println("时间:"+(end-start)+"ms");
	}

	// 字节流自己的缓冲区
	private static void cpyMp3_2() throws IOException
	{
		FileInputStream fis = new FileInputStream("TempFile//fis.mp3");
		FileOutputStream fos = new FileOutputStream("TempFile//cpy.mp3");
		
		BufferedInputStream bis = new BufferedInputStream(fis);
		BufferedOutputStream bos = new BufferedOutputStream(fos);
		
		int by = 0;
		for (;(by=bis.read()) != -1;)
		{
			bos.write(by);
		}	
		bos.close();
		bis.close();
	}

	// 自定义缓冲区的方式
	private static void cpyMp3() throws IOException
	{
		FileInputStream fis = new FileInputStream("TempFile//fis.mp3");
		FileOutputStream fos = new FileOutputStream("TempFile//cpy.mp3");	
		
		byte[] bBuf = new byte[4096];
		int len = 0;
		for (;(len=fis.read(bBuf)) != -1;)
		{
			fos.write(bBuf, 0, len);
		}
		
		fos.close();
		fis.close();
		
		System.out.println("Copy OK!");
	}
}


字符流与字节流的转换问题:
package com.itheima.io;
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;

public class TransStreamDemo
{
	public static void main(String[] args) throws IOException
	{
		// ReadKeyDemo2中的readKey_2()和readLine()方法一致
		
		InputStream in = System.in;
		OutputStream out = System.out;
		
		// 字节流转为字符流。InputStreamReader,
		// 字符流转为字节流,OutputStreamWriter
		// BufferedReader,BufferedWriter,缓冲技术,提高效率
		BufferedReader bin = new BufferedReader(new InputStreamReader(in));
		BufferedWriter bout = new BufferedWriter(new OutputStreamWriter(out));
		
		String line = null;
		for (;(line=bin.readLine()) != null;)
		{
			if ("over".equals(line))
				break;
			else
			{
				bout.write(line);
				bout.newLine();
				bout.flush();
			}
		}
		bin.close();
	}
}


字符流的缓冲区。
BufferedReader
BufferedWriter
缓冲区给给流的操作动作(读写)提高效率.所以缓冲区的对象建立必须要有流对象。

字符流:
FileReader
FileWriter

BufferedReader
BuffereWriter

字节流。
InputStream  OutputStream
FileInputStream FileOutputStream
BufferedInputStream BufferedOutputStream

转换流:
字节流--->字符流的桥梁。InputStreamReader 
字符流--->字节流的桥梁。OutputStreamWriter

---------------------------------------
流的操作规律:
  • 在进行数据操作时,IO包中提供了N多对象不同功能来操作设备上的数据。
  • 在实际开发时,到底用哪个流对象来完成数据处理呢?
  • 这是我们最为苦恼的事情。
  • 如何明确具体用哪个流对象呢?
  • 通过该规律就哦了。
  • 规律就是四个明确?
1,明确源和目的。
  • 源:InputStream   Reader 一定是被读取的。
  • 目的:OutputStream  Writer 一定是被写入的。 

2,处理的数据是否是纯文本的数据?
  • 是:使用字符流。Reader Writer
  • 否:使用字节流。 InputStream OutputStream
  • 如果是源并且是纯文本,Reader
  • 如果是目的并且是纯文本,Writer
  • 到这里,两个明确确定完,就可以确定出要使用哪个体系。
  • 接下来,就应该明确具体这个体系要使用哪个具体的对象。
3,明确数据所在的设备:
源设备:
  • 键盘(System.in)
  • 硬盘(FileXXX)
  • 内存(数组)
  • 网络(Socket)
  • 目的设备:
  • 显示器(控制台System.out)
  • 硬盘(FileXXX)
  • 内存(数组)
  • 网络(Socket)
  • 具体使用哪个对象就可以明确了。
4,明确是否需要额外功能?
  • 是否需要高效?缓冲区Buffered
  • 是否需要转换?转换流

实际需求:
需求1:复制一个文本文件。
1,明确源和目的:既有源,又有目的。
  • 源:InputStream Reader 
  • 目的:OutputStream Writer.
2,明确是否是纯文本?是!
  • 源:Reader
  • 目的:Writer
3,明确具体设备:
  • 源:硬盘(file)
  • 目的:硬盘(file)
  • 源对应的体系Reader中可以操作硬盘设备的对象是 FileReader 
  • 目的对应的体系Writer中可以操作硬盘设备的对象是FileWriter
直接明确具体对象并创建。
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");

4,需要额外功能吗?
  • 需要,高效。 使用缓冲区。
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));

需求2:复制一个图片
1,明确源和目的:既有源,又有目的。
  • 源:InputStream Reader 
  • 目的:OutputStream Writer.
2,明确是否是纯文本?不是!
  • 源:InputStream
  • 目的:OutputStream
3,明确设备:
  • 源:硬盘
  • 目的:硬盘:
FileInputStream fis = new FileInputStream("1.jpg");
FileOutputStream fos = new FileOutputStrema("2.jpg");

需求3:读取键盘录入,存储到一个文件中。
1,明确源和目的:既有源,又有目的。
  • 源:InputStream Reader 
  • 目的:OutputStream Writer.
2,明确是否是纯文本?一般键盘录入的都是文字,所以是纯文本的。 
  • 源:Reader
  • 目的:Writer
3,明确设备:
  • 源:键盘。
  • 目的:硬盘。

具体对象
源是:System.in.
目的是:FileWriter

InputStream in = System.in;
FileWriter fw = new FileWriter("a.txt");
对这个读写,应该这样完成,通过键盘录入读取字节数据,先不做写入操作,
而是将字节数据临时存储,转成字符串,然后在交给fw写入。

发现代码操作的起来很麻烦。有没有已有的功能可以解决这个问题啊?
4,需要额外功能吗?
  • 需要。必须的。
  • 需要将键盘录入的字节转成字符。
  • 使用转换流。而且是 将字节-->字符的转换流对象。InputStreamReader

InputStreamReader isr = new InputStreamReader(System.in);
FileWriter fw = new FileWriter("a.txt");

还需要其他功能吗?
需要,高效。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new FileWriter("a.txt"));

需求4:读取一个文本文件,显示到显示器上。
1,明确源和目的:既有源,又有目的。
  • 源:InputStream Reader 
  • 目的:OutputStream Writer.
2,明确是否是纯文本?是。
  • 源:Reader
  • 目的:Writer
3,明确设备:
  • 源:硬盘。File
  • 目的:显示器。System.out

FileReader fr = new FileReader("a.txt");
OutputStream out = System.out;
这已经可以完成读写了。
通过fr读取文本到字符数组,将字符数组转成字符串,然后在将字符串转成字节数组。
交给out输出。

4,需要额外功能吗?

  • 必须的。转换。需要将已有的字符数据转成字节。字符-->字节的桥梁 OutputStreamWriter

FileReader fr = new FileReader("a.txt");
OutputStreamWriter osw = new OutputStreamWriter(System.out);

需要高效。
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWrier(System.out));

需求5:读取一个文本文件,将文件中文本按照指定的编码表UTF-8写入到另一个文件中。
1,明确源和目的:既有源,又有目的。
  • 源:InputStream Reader 
  • 目的:OutputStream Writer.
2,明确是否是纯文本?是。
  • 源:Reader
  • 目的:Writer
3,明确设备:
  • 源:硬盘。File
  • 目的:硬盘。File
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");

这样做不行,满足不了需求,为什么呢?
因为这个两个对象在操作文本数据,都是用了默认的编码表。在我的本机中默认码表是GBK.
而需求中希望写入到文件的数据是按照utf-8的码表。
其实这两个对象就是字节流+默认编码表。 

源对象不变。
FileReader fr = new FileReader("a.txt");
需要目的为指定编码表。
这时就要用到转换流。因为转换流中可以指定具体的编码表。 需要往里传递一个字节流,而且要操作文件,FileOutputStream
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"),"UTF-8");

需要高效
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("b.txt"),"UTF-8"));

c:\\1.txt 源是一个文件也是字节数据,是不是应该使用字节流呢?
FileInputStream fis = new FileInputStream("c:\\1.txt");
InputStreamReader isr = new InputStreamReader(fis,"gbk");
isr.read();//字符。

既然是明确操作是文件,而且使用默认编码表。
可以使用InputStreamReader的子类。FileReader

FileReader fr = new FileReader("c:\\1.txt");


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值