java中的流对象分为两种:字节流和字符流。 其实严格来说,流只有字节流一种,因为任何数据都是二进制字节,只不过字符串文本操作是很常见的需求,所以jdk就帮我们封装好了一些操作字符流的对象reader和writer他们的底层都是字节流。这一小结主要讲的是字符流,流对象中以reader和writer结尾的都是字符流。
一:FileWriter
需求:将一些文字存储到硬盘一个文件中。
分析:如果要操作文字数据,优先考虑字符流,而且要将文字数据从内存写到硬盘上,要使用字符输出流,Writer。硬盘的数据基本体现是文件。 所以就找到了FileWriter
public class FileWriterDemo {
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static void main(String[] args) throws IOException {
/**
* 创建一个可以往文件中写字符数据的字符输出流对象。
* 既然是往一个文件中写入文字数据,那么在创建对象时,就必须明确该文件(用于存储数据的目的地)。
*
* 如果文件不存在,则会自动创建。
* 如果文件存在,则会被覆盖。
*
* 如果构造函数中加入true,可以实现对文件进行续写!
*/
FileWriter fw = new FileWriter("demo.txt", true);
/*
* 调用Writer对象中的write(string)方法,写入数据。
*
* 其实数据写入到临时存储缓冲区中,并不是写入到文件。这时候应该怎么办,我们看一看flash方法
*
* "\r\n":windows下换行
* "\n":在jdk1.8上测试可以换行
* 如果想支持的更好,那么我们就那系统为我们提供的
*/
fw.write("Hello io" + LINE_SEPARATOR + "2017年6月11日18:27:39");
/**
* 进行刷新,将数据直接写到目的地中。
* flash:刷新该流的缓冲。如果该流已保存缓冲区中各种 write() 方法的所有字符,则立即将它们写入预期目标。
*/
fw.flush();
/*
* 关闭此流,但会先刷新它。在关闭该流之后,再调用 write() 或 flush() 将导致抛出 IOException。关闭以前关闭的流无效。
*/
fw.close();
}
}
二:FileReader
需求:读取文本文件。将读取到的文件打印到控制台。 既然是读取文本文件那么就用字符流Reader。硬盘中的文件是以文本体现所以就用到了FileReader
版本一:一个一个读取
public class FileReaderDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/*
* 创建读取字符数据的流对象。
* 在创建读取流对象时,必须要明确被读取的文件。一定要确定该文件是存在的。
*
* 用一个读取流关联一个已存在文件。
*/
FileReader fr = new FileReader("demo.txt");
/**
* 用Reader中的read方法读取字符,只能读取单个字符。
* 返回:作为ascll码,如果已到达流的末尾,则返回 -1
*/
int ch = fr.read();
System.out.println( (char)ch );
int ch1 = fr.read();
System.out.println( ch1 );
int ch2 = fr.read();
System.out.println( ch2 );
fr.close();
}
}
版本二:一次一个的读取明显太麻烦了,现在我们使用循环来读取
public class FileReaderDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/*
* 创建读取字符数据的流对象。
* 在创建读取流对象时,必须要明确被读取的文件。一定要确定该文件是存在的。
*
* 用一个读取流关联一个已存在文件。
*/
FileReader fr = new FileReader("demo.txt");
/**
* 有了下面的教程,我们可以写一个循环来读取
*/
int ch = 0;
while ( (ch = fr.read()) != -1){
System.out.print((char)ch);
}
/**
* 用Reader中的read方法读取字符,只能读取单个字符。
* 返回:作为ascll码,如果已到达流的末尾,则返回 -1
*/
/* int ch = fr.read();
System.out.println( (char)ch );
int ch1 = fr.read();
System.out.println( ch1 );
int ch2 = fr.read();
System.out.println( ch2 );
*/
fr.close();
}
}
三:FileReader和FileWriter流组合使用
需求:将C盘中的一个文本文件复制到D盘
public class CopyTextTest {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("d://io.txt");
FileWriter fw = new FileWriter("e://a.txt");
char[] buf = new char[1024]; //这个就是缓冲区
int len = 0;
while ( (len = fr.read(buf)) != -1) {
fw.write(buf, 0, len);
}
fw.close();
fr.close();
}
}
四:Buffer缓冲区
我们通过demo就会发现。我们在读数据的时候是定义了一个1024位的字节数组来当做缓冲区,为什么要用缓冲区。举个例子缓冲区就好比我们去超市推得购物车,超市的商品可以看做是源文件,收银台就好比目地文件。 我们能拿东西的数量是有限的,如果我们一点一点的拿就显得很麻烦,这时候我们如果推一个购物车。这样的效率明显提高了。 jdk很显然知道我们有这样的需求,早就为我们考虑到了。 这时候就引入了BufferReader和BufferWriter
BufferReader:
public class BufferedReaderDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("buf.txt");
BufferedReader bufr = new BufferedReader(fr);
String line = null;
/**
* 引入了缓冲区之后,缓冲区对象一次性就从磁盘中抓取‘一些数据’,放入缓冲中。
* 那么我们以后我们要读取的话,就可以直接从缓冲区中获取数据,而不是从磁盘中读取。
* 这样就降低了io的消耗。
*
* 既然我们获取了一些数据就可以使用readLine一次读一行,这是缓冲区为我们封装的方法
*
* readLine():使用了读取缓冲区的read方法,将读取到的字符进行缓冲并判断换行标记。
* 将标记前的缓存数据变成字符串返回。
*/
while ( (line = bufr.readLine()) != null) {
System.out.println(line);
}
bufr.close();
}
}
BufferWriter:
public class BufferedWriterDemo {
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("buf.txt");
/**
* 为了提高写入的效率。使用了字符流的缓冲区。
*
* 创建了一个字符写入流的缓冲区对象,并和指定要被缓冲的流对象相关联
*/
BufferedWriter bw = new BufferedWriter(fw);
/**
* 使用缓冲区的写入方法将数据先写入到缓冲区中。
*/
bw.write("wirter" + LINE_SEPARATOR + "reader");
bw.write("Tig");
bw.newLine(); //换行
bw.write("2017年6月11日21:46:15");
//使用缓冲区的刷新方法将数据刷目的地中。
bw.flush();
//关闭缓冲区。其实关闭的就是被缓冲的fw流对象。
bw.close();
/**
* 所以当你关闭了缓冲区,fw也就默认关闭,因为缓冲区只是封装了数组
* 提高流中数据操作效率的,没有调用流资源。
*
* 所以别认为我关闭了bw没有关闭fw。我们就可以写东西了。
* fw.write("hehe");
* fw.close();
*/
}
}
五:BufferReader和BufferWriter组合练习
需求:从d盘中读取一个文件到e盘,加入缓冲
public class CopyTextByBufTest {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("d://io.txt");
FileWriter fw = new FileWriter("e://a.txt");
BufferedReader br = new BufferedReader(fr);
BufferedWriter bw = new BufferedWriter(fw);
String line = null;
while ( (line = br.readLine()) != null) {
bw.write(line);
bw.newLine(); //因为我们一行一行读取的时候是没有读取换行符,所以这地方要换行
bw.flush();
}
bw.close();
br.close();
}
}