---------------------- 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培训、期待与您交流! ----------------------