黑马程序员---初识IO流

------- android培训java培训、期待与您交流! ----------
以前写程序的时候,对于IO流感觉有点不爽,估计很多学者都有同样的感觉,原因很简单,操作一个IO流,涉及到的类有点多,而且很多时刻都有点晕,所以也一直对它认识都不深刻。经过一段时间的专门学习,我把自己的所得和大家分享下,希望能对大家有点帮助。说前我得感谢黑马的老师,你们讲的内容很详细,很靠谱。最主要的是易懂。

在介绍之前,让我们先看下输出流和输入流以及程序、操作系统、硬盘之间的关系:

在IO流中,我们是以程序为参考对象定义输入输出。即如果数据是从程序输出到硬盘上,我们称之为输出流。反之,称之为输入流。至于数据是怎么通过操作系统接口到硬盘上,这些底层的东西我们就不必去研究,这些工作JAVA已经为我们封装好了。

在流中我们根据操作的最小单位,把它们分为字节流和字符流,换而言之,如果我们所输出的数据是以字节为单位,就称之为字节流。如果是以字符为单位,就称之为字符流。字节流一般用于操作媒体文件,比如说mp3,视频。字符流一般用于操作文本文件。

首先,我从字节流开始,当然字节流分为输入流和输出流,但不管操作的对象是目标是什么,它们分别继承InputStream和OutputStream.下面分别看下它们的类体系结构

操作字节的输入输出流的类体系结构图如上所示,我们在平时会经常进行对文件进行操作;所以我们先分析FileInputStream和FileOutputStream

操作流对象的基本步骤下:

1、创建流对象,把它和目标文件相关联;

2、确定自己的操作,选择对应的方法;

3、关闭数据流;(必要的,否则可能会造成数据丢失);

现在看具体介绍:

FileInputStream:文件输入流对象,用于读取本地文件中的字节数据;

看Read()方法的几个用法:

public static void Read_1()throws IOException{
		FileInputStream fs=new FileInputStream("E:/sd.txt");//与目标文件相关相关联,如果目标文件不存在,则抛出IOException异常
		int num=0;
		while((num=fs.read())!=-1){//一个字节一个字节的读取
			System.out.println((char)num);
		}
		fs.close();
	}

无参的Read方法返回的是所读取的字节,每次只能读取一个,并且他返回的是32位的,即Int类型,当读取完文件中的内容是,它返回-1,表示操作完成。

带参数的Read()

public static void Read_2()throws IOException{
		FileInputStream fs=new FileInputStream("E:/tttt.txt");
		int num=0;
		byte[]buf=new byte[1024];//以字节数组作为缓冲区
		while((num=fs.read(buf))!=-1){
			System.out.println(new String(buf));
		}
		fs.close();
	}

read(byte[]b)接受的是一个字符数组,把所读取的内容返回到数组里,进行缓冲,然后在将数组里的内容显示到控制台上,此种方法与上一种比读取效率更高;

public static void Read_3()throws IOException{
		FileInputStream fs=new FileInputStream("E:/tttt.txt");
		int num=fs.available();//返回的是目标文件中的字符个数,也是InputStream类中所特有的方法
		byte[]buf=new byte[num];
		fs.read(buf);//此种方法虽然简化了程序,提高了效率,但是用法不安全,容易造成内存溢出。
		System.out.println(new String(buf));
		fs.close();
	}
记住:操作完数据以后,必须进行流关闭。

其实原理很简单:就是把目标文件里的内容读入到输入流中,通过输入流进入内存里的程序,在显示到控制台,但是它是一个字节一个字节的读取,效率有点低。

还有一个Read重载方法:read(byte[]b,int off,int length);这个方法其实都和上面带参数的方法基本一致,不同的是它把规定特定的一个字符数组空间来存储读取的内容;

FileOutputStream类,用法基本一致,用于写入诸如图像数据之类的原始字节的流

其方法如下:

基本和文件输入流对象一致

public static void Writer_1()throws IOException{
		FileOutputStream fos=new FileOutputStream("e:/sd.txt");//如果文件不存在,则创建它。如果存在,则覆盖他。
		fos.write("sdfsdf".getBytes());//getBytes()使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
		/*
		 * 此方法与FileWriter方法有区别:在不刷新缓冲区情况下,他直接将数据写入文件;因为他操作的是字节数据,不需要转化;
		 * FileWriter虽然操作的是字符,但其底层还是操作的是字节,在把数据写入缓冲区/内存是,虚拟机会将相应的字符和一张码表对应(本机器的是GBK的,可以通过System.getProperties()方法查看)
		 * 然后将相应的字符转化为相应的字节,所以会在内存中驻留,需用flush刷新该缓冲区,将其写入文件
		 */
		fos.close();
	}
将内容从内存一个字节一个字节的写入到目标文件中;两个最长用的字节流对象基本上就是如此;下面介绍字符流对象

字符流:前面说过就是说数据最小传输的单位是字符,其实,本质上而言,它还是字节流传输。它的原理就是,当它从文件里读写数据时,会把所读写的数据存放到缓冲区里,然后再把缓冲区里的字符数据和一张相应的码表相对应,取出所对应的编码,换成字节数据,然后在传入到流中,经过流到达目标文件。所以操作这类字符数据,其读写能力和字节流相比就会显得弱势一点。FileReader和FileWriter都是使用的默认编码,想看自己虚拟机的默认编码可以同个System.properties()查询,具体的操作大家可以研究下,不难。我的机器是GBK的。还是先介绍文件操作流对象FileWriter和FileReader

FileReader:用于以字符为单位读取文本文件。

看下其方法:

大多数方法和字节流对象一致,但不同的是Read()重载的参数是字符数组

import java.io.*;
public class FileReaderDemo {
	
	/**
	 * @param args
	 */注意try-catch的常规应用形式
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		FileReader fw=null;//定义在try块的外面
		try{
			fw=new FileReader("D:\\Workspaces\\MyEclipse 10\\Day18\\src\\FileReaderDemo.java");
			int num=0;
			int reads=0;
			//while((reads=fw.read())!=-1)System.out.print((char)reads);//不带参数的read方法,返回的是所读取字符的ASCII码
			char []a=new char[1024];
			while((num=fw.read(a))!=-1){//调用的是带字符数组参数的read方法,返回的是所读取的字符个数;相比前一种,此种效率更快;
				System.out.print(new String(a,0,num));
			}
		}catch(IOException e){
			e.printStackTrace();//默认情况是把异常打印到控制台上
		}finally{
			try{
				if(fw!=null)fw.close();//关闭流
			}
			catch(IOException e){
				e.printStackTrace();
			}
		}
	}

}
FileWriter类的基本方法如下:

基本操作:

/*
 * 字符流和字节李流
 * 字节流的两个基类:
 * InputStream   OutputStream
 * 字符流的两个基类:
 * Reader   Writer
 * 先学习字符流的特点
 * 既然IO流是用于操作数据的
 * 那么数据的最常用体现形式是:文件
 * 需求:在硬盘上,创建一个文件写入一些文字数据
 * 找到一个专门用于操作文件的Writer子类,FileWriter  前缀名为改流对象的功能,
 * 后缀名为所属类别
 */
import java.io.*;
public class FileWriterDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws IOException{
		// TODO Auto-generated method stub
        //创建一个FileWriter对象,该对象一被初始化就必须要明确要被操作的文件
		//而且该文件会被创建到指定的目录下,如果该目录下有同名文件,则覆盖它;如果不想覆盖原来内容,可以在创建流对象时向构造函数在加一个参数true。
		//其实该步就是要明确存放数据的目的地
		FileWriter fw=new FileWriter("x.txt");
		fw.write("abc");
		//fw.close();
		fw.flush();//刷新,把缓冲里面的数据刷新到目标文件中,如果没有这步,将无法写入数据;
		fw.close();
		
	}

}
Write()的重载方法很多,可以写入字符,字符数组,字符串等,但写入单个字符时,其参数是int类型,写完后别忘了刷新,其实忘了不打紧,close()方法本身就带有刷新功能,它是等把全部数据都读取完后,才进行刷新,所以为了不必要的麻烦,还是在每次读了之后都调用下flush()方法,把数据写入目标文件;

看下FileWriter和FileReader两者一起的应用

原理用图表示下:

代码如下

import java.io.*;
public class CopyText {
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		FileReader fr=null;
		FileWriter fw=null;
		try{
			fr=new FileReader("D:\\Workspaces\\MyEclipse 10\\Day18\\src\\FileReaderDemo.java");
			fw=new FileWriter("e:/x.txt");
			int length=0;
			char[]buff=new char[1024];
			while((length=fr.read(buff))!=-1)
			fw.write(buff,0,length);
		}catch(IOException e)
		{
			throw new RuntimeException("读取失败!");
		}finally{
			try{
				if(fr!=null)fr.close();
			}catch(IOException e){
				throw new RuntimeException("读取流关闭失败!");
			}
			finally{
				try
				{
				if(fw!=null)fw.close();
				}catch(IOException e){
					throw new RuntimeException("写入流关闭失败!");
				}
			}
		}
	}

}
现在基本把这常用的几种介绍完了,我将在深入IO流中详细介绍有关IO流的更多知识。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值