IO流

一、  IO体系

Reader:字符输入流基类
	|-BufferedReader:字符输入流缓冲区
		|-LineNumberReader:跟踪行号的字符输入流缓冲区
	|-InputStreamReader:是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。
		|-FileReader:用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。
	|-CharArrayReader
	|-StringReader
	|-FilterReader
	|-PipedReader

Writer:字符输出流基类
	|-BufferedWriter:字符输出流缓冲区
	|-OutputStreamWriter:是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。
		|-FileWriter:用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。
	|-CharArrayWriter
	|-StringWriter
	|-FilterWriter
	|-PipedWriter
	|-PrintWriter:字符打印流
	
InputStream:字节输入流基类
	|-FileInputStream:用于读取诸如图像数据之类的原始字节流。
	|-FilterInputStream
		|-BufferedInputStream:字节输入流缓冲区
		|-DataInputStream:用于操作基本数据类型的流对象。
	|-ObjectInputStream:对象的持久化存储的流对象。
	|-PipedInputStream:管道流,涉及到多线程的输入流对象。
	|-ByteArrayInputStream:用于操作字节数组的输入流对象,在构造的时候接收的数据源是一个字节数组。
	|-SequenceInputStream:表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。 

	
OutputStream:字节输出流基类
	|-FileOutputStream:用于写入诸如图像数据之类的原始字节的流。
	|-FilterOutputStream
		|-BufferedOutputStream:字节输出流缓冲区
		|-DataOutputStream:用于操作基本数据类型的流对象。
		|-PrintStream:字节打印流
	|-ObjectOutputStream:对象的持久化存储的流对象。
	|-PipedOutputStream:管道流,涉及到多线程的输出流对象。
	|-ByteArrayOutputStream:用于操作字节数组的输出流对象,不用定义数据目的,因为该对象内部封装了一个可变长度的字节数组。

二、  IO流的操作

1、流操作的基本规律:
1)明确源和目的
数据源:Reader和InputStream
数据目的:Writer和OutputStream
2)操作的数据是否是纯文本
是:数据源:Reader;数据目的:Writer
否:数据源:InputStream;数据目的:OutputStream
3)明确体系后选择合适的对象
明确操作的数据设备
数据源对应的设备:硬盘(File),内存(数组),键盘(System.in)
数据目的对应的设备:硬盘(File),内存(数组),键盘(System.out)
4)是否需要在基本操作上附加其他功能?缓冲技术或者指定字符编码?
字符流缓冲技术:BufferedReader、BufferedWriter
字节流缓冲技术:BufferedInputStream、BufferedOutputStream
指定字符编码:InputStreamReader(InputStream in, String charsetName)
       OutputStreamWriter(OutputStream out, String charsetName) 

2、流操作代码示例
1)、读取a.txt文件中的数据到b.txt中(复制文本文件)
文件中数据是纯文本:Reader
操作的数据设备是硬盘:File
加入缓冲技术:BufferedReader
一行一行读取数据:readLine();
综上:BufferedReader bufr = new BufferedReader(new FileReader("所要操作的纯文本文件")); 
   bufr.readLine();
文件中数据是纯文本:Writer
操作的数据设备是硬盘:File
加入缓冲技术:BufferedWriter
写入一行数据后换行:newLine();
刷新该流的缓冲:flush();
综上:BufferedWriter bufw = new BufferedWriter(new FileWriter("新纯文本文件"));
   bufw.newLine();
   bufw.flush();

import java.io.*;
class FileReaderDemo
{
	public static void main(String[] args)
	{
		BufferedReader bufr = null;
		BufferedWriter bufw = null;
		try
		{
			bufr = new BufferedReader(new FileReader("blog\\a.txt"));
			bufw = new BufferedWriter(new FileWriter("blog\\b.txt"));
			
			String line = null;
			while((line=bufr.readLine())!=null)
			{
				bufw.write(line);
				bufw.newLine();
				bufw.flush();
				//System.out.println(line);打印在控制台上
			}
		}
		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("关闭写入流失败!");
			}
		}
	}
}

2)、读取a.Mp3中的数据到b.Mp3中(复制非文本文件,比如一个Mp3文件)
文件中数据不是文本:InputStream
操作的数据设备是硬盘:File
加入缓冲技术:BufferedInputStream
综上:BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("所要操作的非文本文件"));
文件中数据不是文本:OutputStream
操作的数据设备是硬盘:File
加入缓冲技术:BufferedOutputStream
综上:BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("新非纯文本文件"));

import java.io.*;
class FileStreamDemo
{
	public static void main(String[] args)throws IOException
	{
		BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("blog\\Better.mp3"));
		
		BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("blog\\Bad.mp3"));
		
		int by = 0;
		while((by=bufis.read())!=-1)
		{
			bufos.write(by);
		}
		
		bufis.close();
		bufos.close();
		
		//不使用缓冲技术,自定义一个数组,用于存放读到的数据。
		/* FileInputStream fis = new FileInputStream("blog\\Bad.mp3");
		FileOutputStream fos = new FileOutputStream("blog\\Worse.mp3");
		
		byte[] buf = new byte[1024];
		int len = 0;
		while((len=fis.read(buf))!=-1)
		{
			fos.write(buf,0,len);
		}
		fis.close();
		fos.close(); */
	}
}

3)、键盘录入一行数据并打印成大写到控制台上
  思路:通过键盘录入一行数据并打印成大写,其实就是读一行的原理,也就是readLine()方法。readLine()方法是BufferedReader类中的方法,键盘录入的类InputStream(字节流)中的读的方法是read(),那我们想把字节流转换为字符流,再使用字符缓冲区的readLine()方法呢?于是我们用到了转换流。
InputStreamReader:字节流转换为字符流的桥梁(字节流对象使用字符流中的readLine方法)
OutputStreamWriter:字符流转成字节流的桥梁(录入的是字符,但写出的是字节)
键盘录入的标准写法:
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
打印在控制台上写法:
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));

import java.io.*;
class TransDemo
{
	public static void main(String[] args)throws IOException
	{
		
		//键盘录入
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		
		//打印在控制台上
		BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
		//打印在硬盘文件中
		//BufferedWriter bufw = new BufferedWriter(new FileWriter("blog\\out.txt"));
		
		String line = null;
		while((line=bufr.readLine())!=null)
		{
			if("over".equals(line))
				break;
			bufw.write(line.toUpperCase());
			bufw.newLine();
			bufw.flush();
		}
		
		bufr.close();
		bufw.close();
	}
}

4)、转换流的应用:指定编码和解码的字符编码集。
转换流:
  转换流的特有功能就是可以将字节转换为字符,原因在于它将获取到字节后通过查找指定编码表来获取字符。
InputStreamReader:转换流=字节流+编码表。(如果没有指定也是平台默认编码表)
  |-FileReader:转换流子类=字节流+默认编码表。
OutputStreamWriter 
  |--FileWrier 
如果仅仅使用平台默认编码表,就使用FileReader。如果使用指定编码表,必须使用转换流。凡是操作设备上的文本数据,涉及到编码转换,必须使用转换流。

//用UTF-8编码,用GBK解码失败。必须使用UTF-8才能正确解码。
import java.io.*;
class TransDemo1
{
	public static void main(String[] args)throws IOException
	{
		//write();	
		read();
	}
	public static void write()throws IOException
	{
		//用UTF-8编码表编码
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("blog\\c.txt"),"UTF-8");
		osw.write("你好");
		osw.close();
	}
	public static void read()throws IOException
	{
		//用GBK编码表进行解码
		InputStreamReader isr = new InputStreamReader(new FileInputStream("blog\\c.txt"),"GBK");
		//InputStreamReader isr = new InputStreamReader(new FileInputStream("blog\\c.txt"),"UTF-8");
		
		char[] buf = new char[10];
		int len = isr.read(buf);
		String str = new String(buf,0,len);
		
		System.out.println(str);//结果是解码失败,打印:浣犲ソ
		isr.close();
	}
}

5)、读取内存中的数据到内存中

import java.io.*;
class ArrayDemo
{
	public static void main(String[] args)//throws IOException
	{
		//数据源:内存中的字节数组
		ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEF".getBytes());//将字符串转为字节数据
	
		//数据目的:流对象内部封装的可变长度的字节数组
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		
		int by = 0;
		while((by=bis.read())!=-1)
		{
			bos.write(by);
		}
		
		System.out.println(bos.size());//打印出6
		System.out.println(bos.toString());//打印出ABCDEF

		//将字节数组中的数据写入到硬盘中,该方法涉及到异常。
		//bos.writeTo(new FileOutputStream("blog\\array.txt"));
	}
}

三、  File类

将文件系统中的文件和文件夹封装成了对象。提供了更多的属性和行为可以对这些文件和文件夹进行操作。这些是流对象办不到的,因为流只操作数据。
1、File类的常见方法:
1)、创建
boolean creatNewFile():在指定位置创建文件,如果该文件已经存在,不创建,返回false和输出流不一样,输出流对象一创建文件,而文件存在,就覆盖。
boolean mkdir();创建一级目录(文件夹)
boolean mkdirs();创建多级目录(文件夹)
2)、删除
boolean delete(); 删除失败返回false
void deleteOnExit(); 在程序退出时删除指定文件。
3)、判断
boolean exists():判断文件或者目录是否存在。
boolean isFile(); 判断是否是一个标准文件
boolean isDirectory();判断表示的文件时否是一个目录
boolean isHidden(); 判断指定文件是否是一个隐藏文件
boolean isAbsolute();判断是否是绝对路径
4)、获取信息
String getName(); 返回表示的文件或者目录的名称
String getPath(); 将路径转换为路径名称字符串
String getParent();返回父目录字符串,如果没有返回null
String getAbsolutePath();将绝对路径转换为路径名称字符串
long lastModified(); 返回最后一次修改时间
long length(); 返回由此抽象路径名表示的文件的长度。
boolean renameTo(File dest); 重命名此路径名表示的文件。

2、递归
什么时候用递归呢? 
当一个功能被重复使用,而每一次使用该功能时的参数不确定,都由上次的功能元素结果来确定。 
简单说:功能内部又用到该功能,也就是函数自身调用自身。但是传递的参数值不确定。(每次功能参与运算的未知内容不确定)。
递归的注意事项: 
a.一定要定义递归的条件。 
b.递归的次数不要过多。容易出现 StackOverflowError 栈内存溢出错误。
其实递归就是在栈内存中不断的加载同一个函数。
递归应用代码示例:
//需求:删除一个带内容的目录
//删除原理:在Windows中,删除目录时从里边往外删的。既然是从里往外删除,就需要用到递归了。
import java.io.*;
class RemoveDir
{
	public static void main(String[] args)
	{
		File f = new File("F:\\Example_Java2");	
		removeDir(f);
	}
	public static void removeDir(File dir)
	{
		File[] files = dir.listFiles();
		for(int x=0; x<files.length; x++)
		{
			if(files[x].isDirectory())
				removeDir(files[x]);
			else
				System.out.println(files[x].toString()+"--"+files[x].delete());
		}
		System.out.println(dir.toString()+"=="+dir.delete());
	}
}
/*打印结果
F:\Example_Java2\1文件夹\a.txt--true
F:\Example_Java2\1文件夹\b.txt--true
F:\Example_Java2\1文件夹\c.txt--true
F:\Example_Java2\1文件夹==true
F:\Example_Java2\2文件夹==true
F:\Example_Java2\3文件夹==true
F:\Example_Java2==true
*/

3、Properties类
Java.util.Properties:一个可以将键值进行持久化存储的对象。Map--Hashtable的子类。用于属性配置文件,键和值都是字符串类型。
特点:1:可以持久化存储数据。2:键值都是字符串。3:一般用于配置文件。
方法:
load():将流中的数据加载进集合。 
原理:其实就是将读取流和指定文件相关联,并读取一行数据,因为数据是规则的key=value,所以获取一行后,通过 = 对该行数据进行切割,左边就是键,右边就是值,将键、值存储到properties集合中。 
store():写入各个项后,刷新输出流。 
list():将集合的键值数据列出到指定的目的地。 
Properties类代码示例:

//将硬盘上文本文件中的规则数据复制到另一个文件中或者打印在控制台上。
import java.io.*;
import java.util.*;
class PropertiesDemo
{
	public static void main(String[] args)throws IOException
	{
		Properties pro = new Properties();
		FileInputStream fis = new FileInputStream("info1.txt");

		//从输入流中读取属性列表(键值对)
		pro.load(fis);
		
		//修改集合中的键值
		pro.setProperty("zhangsan","99");
		FileOutputStream fos = new FileOutputStream("info2.txt");
		
		//将此 Properties 表中的属性列表(键值对)写入输出流。
		pro.store(fos,"haha");//haha是注释信息,
		
		//将集合的键值数据列出到指定的目的地(此处是打印在控制台上)。 
		pro.list(System.out);
		
		fos.close();
		fis.close();
	}
}

为避免误导初学者,本博客如有错误或者不严谨的地方,请在下方给予评论,以便及时修改!谢谢... ...

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值