黑马程序员-IO(字符流的理解)

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

 

字节流的抽象基类:InputStream ,OutputStream。

字符流的抽象基类:Reader ,Writer

    字符流的使用

         创建流对象,建立数据存放文件,但是这里有个需要注意的地方,如果当前目录下已经存在这个文件或者同名文件,那么该文件将会被覆盖掉,如果想在该文件中直接续写数据,下面会介绍

      

FileWriter fw = new FileWriter(“Test.txt”);
	//调用流对象的写入方法,将数据写入流
	fw.write(“text”);
//关闭流资源,并将流中的数据清空到文件中。
fw.close();
//一定要写关闭流对象的语句,否者数据不会写入文件中,只停留在缓存


 

 

问题1:不写close方法会有什么结果呢?

如果不写close,那么数据将会留在缓存中,并没有真的写入文件,所以每次都要执行close语句

如果想在原有文件上继续加入新的数据呢?

       FileWriter fw = new FileWriter(“Test.txt”,true);

       FileWriter的构造方法重载,有一个构造方法是传递bolean类型的参数判断是否存在已有文件,如果是true,则不覆盖,将数据写到文件中的末尾处。

 

注意一个问题:换行在windows系统中是识别\r\n,但是在linux系统中是\n,在mac中是\n\r

所以这里这样写的话不具备跨平台性,后面会介绍到一个writer的写入一个行分隔符的方法:writer.newline().这样就具备了跨平台性

 

以下是表示字符流的继承结构

 

其中InputStreamReader和OutputStreamWriter是属于转换流,是用于将字节流转换成字符流,在这里先讲

     BufferedReader和BufferedWriter是属于缓存对象,用于加强FileReader和FileWriter

 

在用BufferedWriter的时候,格式为

FileWrite fw = new FileWriter(“Demo.txt”);
BufferedWriter buw = new BufferedWriter(fw);
Fw.writer(“asfddgfdhgf”);
buw.close();

 

在设置循环输出的时候

需要注意的地方是,在使用完毕的时候,需要关闭流对象,那么是关闭fw的还是buw的呢?其实BufferedWriter是在底层调用FileWriter的写功能,所以真正在操作数据的是FileWriter,那么其实关闭任何一个BufferedWriter的buw就相当于关闭了FileWriter的流,可以这样理解现在BufferedWriter和FileWriter各有一个流,但是BufferedWriter的流包含了FileWriter的流,所以关闭BufferedWriter也就关闭了FileWriter.最后一句buw.close();

 

在使用BufferedReader的时候,有提供的读取方法是行的读取方法readline();(但是也有提供读取一个字符的方法)在读取到\r或\n这两个字符其中一个,就换行,如果读到了数据的末尾(注意不是指行的末尾)就返回null,这个和FileReader的循环读取条件有点区别, FileReader的read()读到\r或者\n的时候会返回“-1”,此时选择“-1”作为循环结束的条件。

FileReader fr =new FileReader(“Demo.txt”);

BufferedReaderbufr= new BufferReader(fr);

 

循环条件的设置格式为

String line = null;

While(line=bufr.readline()!=null)

{

         System.out.println(line);

}

 

读取一个文件,并显示在屏幕上

 

重点:

读取循环的条件,fr.read(ch)内部实现是,把文件的内容一个一个地存入字符数组ch中

当存满了1024个字符后,这时才会返回一个读取的数目,并且执行输出语句,                                                                     

输出完毕后再重新读覆盖原先字符数组里的数据,重复以上的动作,循环输出。当达到流的末尾的时候,返回-1。

import java.io.*;
class ReadFileDemo 
{
	public static void main(String[] args) throws IOException//只要涉及到IO流,必须给抛异常
	{
		FileReader fr = new FileReader("ExceptionInfo.java");
		char[] ch = new char[1024];
		int num = 0;
			while((num=fr.read(ch))!=-1)
			{
				System.out.print(new String(ch,0,num));
			}
			fr.close();
	}
}



 

 

不太理解的问题

循环的结束条件的内部实现机制:

(1)

char[] ch = new char[1024];

  intnum = 0;

while((num=fr.read(ch))!=-1)

         {

         System.out.print(newString(ch,0,num));

         }

执行一次fr.read(ch)是一次性读取文件中1024个字符(读取数据的时候读到\r\n会自动换行继续读取),读完后返回一共读了多少个字符,即返回读取数(角标+1),并且执行一次打印语句,然后在上次读取结束的地方,再次读取1024个字符,不足1024按实际字符算,假设还剩400个,那么第二次读就一次性读进了400个,并且返回400.那么此时文件中没有数据了,fr.read(ch)读不到任何数据,即返回-1,不执行打印输出

                                                                

(2)      

String str = null;

while((str =bufr.readLine())!=null)

                   {

                            System.out.println(str.toString());

                   }

这个的解释同上bufr.readLine()是读一行字符的,读完一行,输出以后,其实隐含了一个动作就是自动换行,那么下一次读的就不是同一行的数据了,这个动作被封装起来了,所以有点难以理解

扩展一下:

问题一:为什么有时候时结束条件是“!=-1”,有时候是“!=null”

问题二:返回值到底代表的是什么,为什么有时候能够要定义一个int型的变量去接收返回值,为什么有时候定义String型去接收返回值

对于字符流

BufferedReader有三个Read(),分别是:

 

int read():返回int型的数据,理解为把读到的字符强转成int返回,即数据的ASCII码,如果到达流末尾返回“-1”

 

int read(char[]buf):返回读到的字符数量,到达流末尾返回“-1”

(读到的数据存到buf中)

 

String readLine():返回读到的字符串,如果到达流末尾返回“null”//只有用readLine()才会用null,其余一律用“-1”

 

FileReader也有三个Read(),分别是:

 

int read():返回int型的数据,理解为把读到的字符强转成int返回,即字符的ASCII码,如果到达流末尾返回“-1”

int read(char[]buf):返回读到的字符数量,到达流末尾返回“-1”

(读到的数据存到buf中)

 

intread(char[],int off,int len ):返回读到的字符数量,到达流末尾返回“-1”

(读到的数据存到buf中)

 

对于字节流

FileInputStream有两个read(),分别是

int read(byte[]bt):返回读到的字节数量,到达流末尾返回“-1”

int read():返回下一字节数据,到达流末尾返回“-1”

BufferedInputStream有两个read(),分别是

intread(byte[],int off,int len):返回读到的字节数量,到达流末尾返回“-1”

int read():返回下一字节数据,到达流末尾返回“-1”

 

总结:

(1)只有用BufferedReader的readLine()才会用到null,其余一律用“-1”作为结束条件

(2)对于有参数的read()方法里有数组形参“byte[]”“char ch”“byte[],int off,int len”这三种的,返回值都是代表读取到的数据的数目,读到的内容都存到了数组

(3)read()无参数的,分两种讨论

1:字符流:返回int型的数据,理解为把字符强转成int返回,即数据的ASCII码

2:字节流:返回下一字节数据

1.2但两者返回的都是读到的数据,只是数据类型不一样

 

 

(2)到底什么时候定义int ch;

While((ch=fd.read(char))!=-1)

{}

       什么时候定义string str=null;

While((str=bufr.readLine())!=null)

{}

观察上面的代码能够得出规律,用字符缓冲区的readLine()读取行数据时,会有一个返回值,返回值是一行字符串,String型接收,判断用“!=null”;

用字符流对象直接读取数据时,也有一个返回值,但是这个返回值是读取的个数,用int型接收,判断用“!=-1”

用字节流对象直接读取数据的时候,返回值是下一字节数据

弄明白记清楚返回值类型和其代表的意义,可以知道什么时候用int什么时候用string

 

 

问题

红色代码部分,不理解为什么要定义成int ch;然后接收fr.read()的返回值

经过查阅文档,Read()方法可以发生重载

Read()返回的是读取的一个数据的整数形式,这里猜测返回的这个整数是ASCII值,但是如果到达流的末尾,则返回“-1”,还有一点要注意if(ch=='\r'),比较的应该也是ASCII码值

Read(char[] cbuf)把读取的到的数据存储到char[] cbuf这个数组缓冲区中,返回的不再是int型数据,而是数组的角标。

 

class MyBufferedReader
{
	private FileReader fr = null;
	MyBufferedReader(FileReader fr)
	{
		this.fr = fr;
	}

	public String myReaderLine()
	{
		StringBuilder sb = new StringBuilder();
		int ch = 0;      //为什么要定义成int类型的
		while((ch=fr.read())!=-1)
		{
			if(ch=='\r')
				continue;
			if(ch=='\n')
				return sb.toString();
			else
			sb.append((char)ch);
		}
	}
	public void close()
	{
		fr.close();
	}
}


仔细观察返回的条件if(ch=='\n')

returnsb.toString();

上述代码还存在一个问题,就是如果一个文本数据,最后一行没有\r\n,那么最后一行的数据,就存进去了,但是并没有返回来,所以要在最后检查缓冲区里面是否有内容,如果有,就返回

加上

if(sb.length()!=0)

returnsb.toString();

 

 

关于字节转换流的用法InputStringReader

示例:

BufferedReaderbufr =

                           newBufferedReader(new InputStreamReader(System.in))

解析:

BufferedReader(Reader rd):需要的参数是一个字符流对象

System.in返回的是一个InputStream的对象,键盘录入就是以字节流形式

而InputStreamReader(InputStreamips):就是一个字符流对象,构造函数接收一个字节输入流对象作为参数,把字节流对象封装在里面

 

 

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

详细请查看:http://edu.csdn.net 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值