IO流


IO(Input Output)流:表示输入输出流

IO流用来处理设备之间的数据传输,这里的设备一般指的是硬盘,光盘,U盘,还有内存。
流按照操作的数据分为两种:输入流,输出流。
将外设中的数据读取到内存中称为输入,将内存中的数据写入到外设中称为输出流。
按照数据流向不同分为:输入流和输出流。
字符流的由来:就 是由字节流读取文字字节数据后,不直接操作而是先查指定的编码表。获取对应的文字。
在对这个文字进行操作。简单的说就是字节流+编码表。

IO流在Java中的整个体系

字符流

操作文字数据,一般使用字符流。

例如:将文字数据从内存写到硬盘上,要使用字符流中的输出流Writer

               
                 FileWriter fw = null;
		    try {
			fw = new FileWriter("c:\\demo.txt");
			fw.write("itheima" + LINE_SEPARAROT + "aaaa");// 向文件写入字符串数据
			// fw.flush();//刷新缓冲区中的流
		} catch (IOException e) {
			throw new RuntimeException("文件写入错误");
		} finally {if(fw!=null)
			try {
				fw.close();
			} catch (IOException e) {
				throw new RuntimeException("关闭字符写入流失败");
			}
		}

FileWriter fw=new FileWriter("c:\\demo.txt");这段代码会抛出一个IOException,因为构造函数中的文件名不确定如果文件不存在,则会自动创建,如果文件存在则会覆盖掉原有文件。再调用fw.write(String)方法向文件中写入数据fw.write("itheima");运行程序后发现,demo.txt文件中根本没有写入到文件中的字符串数据,这是因为数据被写入到了临时存储缓冲区中了,但是还没有真正写入到文件,这时需要刷新一下缓冲区调用fw.flush();该方法刷新该流的缓冲。如果该流已保存缓冲区中各种 write()方法的所有字符,则立即将它们写入预期目标。然后,如果该目标是另一个字符或字节流,则将其刷新。因此,一次 flush() 调用将刷新 Writer 和 OutputStream 链中的所有缓冲区。



 数据写入完成后需要关闭fw.close();因为操作流是需要windows资源的。如果不调用flush方法,直接关闭,可以将数据写入,因为close方法会先去刷新该流的缓冲,然后关闭该流,
 如果该流已经关闭,再次向文件中写入数据,或者刷新,就会抛出IOException,提示该流已经关闭。所以一个流可以多次刷新但是只能关闭一次

 
 细节一:window下的换行:\r\n,unix下的换行\n,为了让程序兼容运行,则使用System.getProperty("line.separator");,可以保证在不同系统下的同时换行 

 细节二:FileWriter fw=new FileWriter("c:\\demo.txt",true)l构造函数中指定一个boolean型变量可以控制文件流是否续写。

细节三:在关闭流时需要先判断该流是否null,不为null则进行关闭。否则会出现空指针异常,因为在创建流对象的时候,如果文件路径不存在,则会抛出系统路径错误的异常,这个流对象会创建失败,在关闭的时候,流为空,调用close方法会出现空指针异常,所以需要先判断。


字符输出流:FileReader
读取一个文本文件,将读取到的内容打印到控制台
方式一:读取单个字符
     FileReader fr=null;
try {
fr=new FileReader("c:\\demo.txt");
int ch=0;
while((ch=fr.read())!=-1){
System.out.print((char)ch);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
if(fr!=null);
try {
fr.close();
} catch (IOException e) {
throw new RuntimeException("文件输出流关闭失败");
}
}
在创建读取流对象时,必须要明确读取的文件,而且要保证该文件是存在的。
Reader类的read方法表示读取单个字符。在字符可用、发生 I/O 错误或者已到达流的末尾前,此方法一直阻塞。返回作为整数读取的字符,如果读到末尾则回-1。可以通过循环读取文件,如果读到末尾则表示读取完毕。再将返回的整数转化为char类型的字符。


方式二:读取数组
FileReader fr=null;
try {
fr=new FileReader("c:\\demo.txt");
char[] chs=new char[30];
int num=0;
while((num=fr.read(chs))!=-1){
System.out.print(new String(chs,0,num));
}

} catch (Exception e) {
e.printStackTrace();
}finally{
if(fr!=null);
try {
fr.close();
} catch (IOException e) {
throw new RuntimeException("文件输出流关闭失败");
}
}
先创建一个固定长度的数组,调用read方法的重载read(char[] cbuf)每次将读取到的固定长度的数据存放到数组中。直到读取到文件的末尾再将字符数组构建成字符串,这中读取方式相比读取单个字符而言效率高很多。读取单个字符需要每读取一次就要循环一次,但是读取数组的次数可以根据数组的大小来确定。所以这种读取方式是常用的.



Copy文本文件的例子

将指定的文本文件复制到指定文件中
思路:1,先创建一个文件的读取流,与指定的源文件相关联
 2,再创建一个文件的写入流,每次读取到一个数组,再将数组中的数据写到指定的文件中

package com.tan.filedemo;

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

public class CopyText {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		String file="c:\\demo.txt";//源文件
		String copyFile="c:\\demo_copy.txt";//要复制到的文件
		copyTextFile(file,copyFile);
	}

	private static void copyTextFile(String file, String copyFile) {
		FileReader fileReader=null;
		FileWriter fileWriter=null;
		try {
			fileReader=new FileReader(file);//创建文件读取流对象
			fileWriter=new FileWriter(copyFile);//创建文件写入流对象
			char []buffer=new char[1024];//声明一个字符数组来存储读取的数据,相当于一个缓冲区
			int length=0;//每次读取的长度,也就是字符数组中存储的字符个数
			while((length=fileReader.read(buffer))!=-1){
				fileWriter.write(buffer, 0, length);//每读1024个长度的字符就将文件写入一次
			}
			
		} catch (Exception e) {
			throw new RuntimeException("文件复制失败");
		}finally{
			if(fileReader!=null){
				try {
					fileReader.close();
				} catch (IOException e) {
					throw new RuntimeException("文件读取流关闭失败");
				}finally{
					if(fileWriter!=null){
						try {
							fileWriter.close();
						} catch (IOException e) {
							throw new RuntimeException("文件写入流关闭失败");
						}
					}
				}
			}
		}
	}

}

字符流的缓冲区:
如果不用缓冲区,每次从硬盘上读取数据就是每读取一次,在内存上写入一次,切换的频率很高。如果使用了缓冲区,会先将硬盘上的数据依次存储到缓冲区中,当缓冲区存满后,再将缓冲区中的数据写入到内存。
BufferedReader ,BufferedWriter对象:
BufferedWriter:将文本写入字符输出流,缓冲各个字符,从而提供单个字符,数组,字符串的高效写入,可以指定缓冲区的大小
在构造的时候,需要提供一个被缓冲的流对象Writer。能提高写入效率

BufferedWriter bufferedWriter=null;//声明一个带缓冲区的写入流
try {
//将缓冲写入流和文件写入流相关联
bufferedWriter=new BufferedWriter(new FileWriter("c:\\aa.txt"));
//用带缓冲的文件写入流向文件中写入数据
bufferedWriter.write("I'm tanwei");
//空行,底层调用line.sparator换行符号
bufferedWriter.newLine();
bufferedWriter.write("haha");
} catch (Exception e) {
}finally{
if(bufferedWriter!=null){
try {
//关闭缓冲写入流,同时会将文件写入流也关掉
bufferedWriter.close();
} catch (IOException e) {
}
}
}
====================================================================
BufferedRead:字符缓冲读取流
BufferedReader bufferedReader=new BufferedReader(new FileReader("c:\\aa.txt"));
String line=null;
while((line=bufferedReader.readLine())!=null){//如果读到文件末尾直接返回null
System.out.println(line);
}
bufferedReader.close();
readLine()方法:每次都能读取一行。
BufferedReader中的read方法是从缓冲区中取出数据,所以覆盖了父类中的read方法,但是每次只能读取一个字符,所以缓冲区提供了readLine()方法每次能读取一行,每次将文件中的数据的单个字符读取到缓冲区时,如果读取到换行符号时则就不再继续读取,而是将这一行数据写入,再次读取,依次类推每次都能将一行数据读取.readLine()方法使用了读取缓冲区的read方法,将读取到的类容进行缓冲,并判断换行标记,叫标记前的缓存数据变成字符串返回。


IO流体系中的装饰模式:
装饰设计模式: 动态地给一个对象添加一些额外的功能。
        1.在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
                 2.处理那些可以撤消的职责。
                3.当不能采用生成子类的方法进行扩充时。


例如BufferedReader就是对FileReader的功能增强,将FileReader作为参数传递到构造函数中,这时在BufferedReader类中,私有一个FileReader对象,通过public BufferedReader(FileReader fr){this. fr=fr}将传递过来的FileReader对象赋值给自己的私有成员变量fr,既可以使用fr本身的功能,还能对fr功能尽心扩展。

装饰模式和继承的区别:
装饰模式和继承都能实现一样的功能,进行功能的扩展增强,区别:装饰模式相比继承要更加灵活一些。因为通过上面的例子Buffered如果直接继承FIleReader类的话,会导致这个体系中的类变得更加臃肿。如果后期出现更多的流对象也需要缓冲的话,不能实现多继承。可以将不同的流作为参数传递给BufferedReader对象分别进行功能的增强。装饰类和被修饰的类都必须所属同一个类或者父接口


字节流:
字节流的基本操作都和字符流一样。不仅可以操作字符,也可以操作图片,媒体等二进制文件
用字节流Copy一张图片
将c盘下面的图片copy到d盘去
      

 InputStream inputStream=null;
		OutputStream outputStream=null;
		try {
			//创建一个字节输入流对象和文件相关联
			inputStream=new FileInputStream(src);
			//创建一个字节输出流对象
			outputStream=new FileOutputStream(copyFile);
			byte []img=new byte[1024];//声明一个字节数组缓冲区
			int len=0;
			while((len=inputStream.read(img))!=-1){
				outputStream.write(img, 0, len);//将字节文件写入到输出流中
			}
			outputStream.close();
			inputStream.close();
		} catch (Exception e) {
			throw new RuntimeException("复制文件出错");
		}

同字符流一样字节流也有自己的带缓冲功能的扩展类。其中BufferedInputStream带缓冲的字节输入流有available() 方法该方法表示:返回可以从此输入流读取(或跳过)、且不受此输入流接下来的方法调用阻塞的估计字节数。意思就是可以读取字节文件中的字节码大小。所以读取文件可以使用这种方法
byte []photos=new byte[fileInputStream.available()];
fileInputStream.read(photos);
表示根据文件的字节码大小一次将文件读取出来。如果文件过大的话会很耗时,一般不建议使用。

转换流:
字符流+编码表组成的就是转换流
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(System.in));
String line=null;
while((line=bufferedReader.readLine())!=null){
if("stop".equals(line))break;
System.out.println(line);
}
通过转换流接受用户键盘输入。如果使用非默认编码保存文件或者读取文件时,需要用到转换流,因为字节流的重载构造方法中有指定编码格式的参数,而FielReader 与FileWriter 是默认编码的文本文件


将用户从键盘录入的数据写入到文件中
思路:定义一个BufferedReader字符读取流对象,通过转换流将用户输入的数据写入到该流中
再定义一个BufferedWriter字符写入流对象通过转化流将数据存入到文本中
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("C:\\a.txt")));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
bufferedWriter.write(line);
bufferedWriter.newLine();
if ("stop".equals(line)) {
break;
}
}
bufferedWriter.close();
bufferedReader.close();
IO流中出现的规律:
转换流:
InputStreamReader:字节到字符的桥梁(解码)
OutputStreamWriter:字符到字节的桥梁(编码)

转换流可以使用指定的码表将要写入流中的字符编码成字节。
FileWriter:其实就是转换流指定了本机默认编码表的体现。而且这个转换流的子类对象,可以方便的操作文本文件操作文本的字节流+本机默认的编码表就就是FileWriter类,这是按照默认码表来操作文件的便捷类。如果操作文件需要明确具体的编码。FileWriter就不行了。必须用转化流。


开发时怎样使用流中的各种对象:
1首先明确源和目的 :源:InputStream Reader ,目的:OutputStream Writer
2,明确数据是否是纯文本,如果是纯文本优先使用Reader和Writer,如果是字节码文件则使用InputStream和OutputStream
3,明确具体的数据来源设备 有硬盘(File),键盘(System.in),内存(Array),网络(Socket流)目的设备同上
4,是否需要额外功能: 需要高效(缓冲区)

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值