关于文件流:
首先是四大基本抽象流:字节流:InputStream、OutputStream,字符流:Reader、Writer;输入流:InputStream、Reader,输出流:
OutputStream、Writer;后面的所有流都是这四个的子类;
文件流:FileInputStream、FileOutputStream,FileReader、FileWriter,文件流算是四大基本抽象流的最初级实现类,前面两个是字节
流,可以用于任何格式文件的读写(因为文件的最基本存储形式就是字节数据),后面两个是字符流,只能用来处理文本文件;
字节输入流简单实例
import java.io.File ;
import java.io.InputStream ;
import java.io.FileInputStream ;
public class InputStreamDemo01{
public static void main(String args[]) throws Exception{ // 异常抛出,不处理
// 第1步、使用File类找到一个文件
File f= new File("d:" + File.separator + "test.txt") ; // 声明File对象
// 第2步、通过子类实例化父类对象
InputStream input = null ; // 准备好一个输入的对象
input = new FileInputStream(f) ; // 通过对象多态性,进行实例化
// 第3步、进行读操作
byte b[] = new byte[1024] ; // 所有的内容都读到此数组之中
input.read(b) ; // 读取内容
// 第4步、关闭输出流
input.close() ; // 关闭输出流
System.out.println("内容为:" + new String(b)) ; // 把byte数组变为字符串输出
}
};
字节输出流简单实例
import java.io.File ;
import java.io.OutputStream ;
import java.io.FileOutputStream ;
public class OutputStreamDemo01{
public static void main(String args[]) throws Exception{ // 异常抛出,不处理
// 第1步、使用File类找到一个文件
File f= new File("d:" + File.separator + "test.txt") ; // 声明File对象
// 第2步、通过子类实例化父类对象
OutputStream out = null ; // 准备好一个输出的对象
out = new FileOutputStream(f) ; // 通过对象多态性,进行实例化
// 第3步、进行写操作
String str = "Hello World!!!" ; // 准备一个字符串
byte b[] = str.getBytes() ; // 只能输出byte数组,所以将字符串变为byte数组
out.write(b) ; // 将内容输出,保存文件
// 第4步、关闭输出流
out.close() ; // 关闭输出流
}
};
字符输入流简单实例
import java.io.File ;
import java.io.Reader ;
import java.io.FileReader ;
public class ReaderDemo01{
public static void main(String args[]) throws Exception{ // 异常抛出,不处理
// 第1步、使用File类找到一个文件
File f= new File("d:" + File.separator + "test.txt") ; // 声明File对象
// 第2步、通过子类实例化父类对象
Reader input = null ; // 准备好一个输入的对象
input = new FileReader(f) ; // 通过对象多态性,进行实例化
// 第3步、进行读操作
char c[] = new char[1024] ; // 所有的内容都读到此数组之中
int len = input.read(c) ; // 读取内容
// 第4步、关闭输出流
input.close() ; // 关闭输出流
System.out.println("内容为:" + new String(c,0,len)) ; // 把字符数组变为字符串输出
}
};
字符输出流简单实例
import java.io.File ;
import java.io.Writer ;
import java.io.FileWriter ;
public class WriterDemo01{
public static void main(String args[]) throws Exception{ // 异常抛出,不处理
// 第1步、使用File类找到一个文件
File f= new File("d:" + File.separator + "test.txt") ; // 声明File对象
// 第2步、通过子类实例化父类对象
Writer out = null ; // 准备好一个输出的对象
out = new FileWriter(f) ; // 通过对象多态性,进行实例化
// 第3步、进行写操作
String str = "Hello World!!!" ; // 准备一个字符串
out.write(str) ; // 将内容输出,保存文件
// 第4步、关闭输出流
out.close() ; // 关闭输出流
}
}
练习Copy一个文件夹下的.java到指定目录下,并改后缀名.jad
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
public class Test9 {
public static void main(String[] args) throws Exception {
File file = new File("d:\\java");// 得到一个file对象
// 判断源目录是不是目录,是不是存在
if (!(file.exists() && file.isDirectory())) {
throw new Exception("源目录不存在");// 不存在则抛出异常
}
File[] fs = file.listFiles(new FilenameFilter() {// 匿名内部类类
@Override
public boolean accept(File dir, String name) {// 重写FilenameFilter的accept方法,接受文件的类型
// TODO Auto-generated method stub
File file = new File(dir, name);
if (file.isFile() && name.endsWith(".java")) {// 判断文件后缀名是不是java和是不是文件
return true;
} else {
return false;
}
}
});
// 循环遍历这个符合条件的数组,调用复制的方法。
for (int i = 0; i < fs.length; i++) {
copy(fs[i]);// 复制文件
}
}
private static void copy(File file) throws Exception {
File f2 = new File("d:\\jad");
OutputStream ouput = null;
InputStream input = null;
if (f2.isDirectory() && f2.exists()) {
try {
String path = f2.getPath() + "\\"
+ file.getName().replaceAll("\\.java$", ".jad");// 改变后缀名
input = new FileInputStream(file);// 定义输入流
ouput = new FileOutputStream(path);// 定义输出流
int temp = 0;
while ((temp = input.read()) != -1) {// 读取流
ouput.write(temp);// 写入流
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
// 关闭输入流和输出流
input.close();
ouput.close();
}
} else {
f2.mkdir();// 目标不存在则创建一个文件夹
}
}
}
练习
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
//周可
public class Test9 {
public static void main(String[] args) throws IOException {
String src = "c:\\a";// 源文件夹
String des = "d:\\a";// 目的文件夹
File filesrc = new File(src);// 源文件夹
new File(des).mkdir();// 创建目标文件夹
if (filesrc.isDirectory() && filesrc.exists()) {// 判断源是不是一个文件夹,是不是存在
File[] files = filesrc.listFiles();// 得到所有的文件盒文件夹
for (int i = 0; i < files.length; i++) {// 循环遍历,分别对文件文件夹处理
if (files[i].isFile()) {
// 如果是文件调用复制文件的方法。
copyFile(files[i],
new File(des + "\\" + files[i].getName()));
}
// 如果是文件夹,调用复制文件的方法。
if (files[i].isDirectory()) {
// 得到绝对路径的方法
copyDirectiory(files[i].getAbsolutePath(), des + "\\"
+ files[i].getName());
}
}
} else {
System.out.println("源文件不存在");
}
}
/**
*
* @param srcFile
* 源文件
* @param desFilePath
* //目标文件
* @throws IOException
*/
public static void copyFile(File srcFile, File desFilePath)
throws IOException {
InputStream input = new FileInputStream(srcFile);// 得到文件的输入流
BufferedInputStream bis = new BufferedInputStream(input);// 利用缓冲区技术封装输入流流对象
OutputStream out = new FileOutputStream(desFilePath);// 得到文件的输出流
BufferedOutputStream bos = new BufferedOutputStream(out);// 利用缓冲区技术封装输出流对象
int ch = 0;// 读取的字节
byte[] by = new byte[1024];// 缓冲数组
while ((ch = bis.read(by)) != -1) {// 如果读取到了数据
bos.write(by, 0, ch);// 写入缓冲区中。
}
// bos.flush();可以不用缓冲,缓冲区到缓冲区
bos.close();// 关闭缓冲输入流
bis.close();// 关闭缓冲输出流
}
/**
* 复制一个文件夹
*
* @param src
* 源文件夹路径
* @param des
* 目标文件夹路径
* @throws IOException
*/
public static void copyDirectiory(String src, String des)
throws IOException {// 目标,源 文件夹的路径
File fdes = new File(des);// 创建目标file对象
fdes.mkdir();// 创建目标文件夹
File fsrc = new File(src);// 创建源file对象
File[] files = fsrc.listFiles();// 源文件夹的所有文件
for (int i = 0; i < files.length; i++) {
if (files[i].isFile()) {// 如果是文件
// 调用复制文件的方法
File desFile = new File(des + "\\" + files[i].getName());
copyFile(files[i], desFile);// 调用
} else if (files[i].isDirectory()) {// 如果是文件夹,复制文件夹
copyDirectiory(files[i].getAbsolutePath(), des + "\\"
+ files[i].getName());
}
}
}
}
缓冲区的出现提高了对数据的读写效率。
对应的两个类
BufferedWriter Writer子类
BufferedReader
缓冲区要结合流才可以使用。
在流的基础上对流的功能进行了增强。
缓冲区的出现是为了提高流的操作效率而出现的。
所以创建缓冲区之前必须要先有流对象。
写入字符流缓冲区
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferDemo {
public static void main(String[] args) throws IOException {
//创建一个字符写入流对象
FileWriter fw=new FileWriter("buf.txt");
//为了提高字符谢如柳效率,加入了缓冲技术
//只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可
BufferedWriter bufw=new BufferedWriter(fw);
for(int x=1;x<5;x++){
bufw.write("abcd"+x);
bufw.newLine();//该缓冲区中提供了一个跨平台的换行符。
bufw.flush();
}
/// bufw.write("abced");
//只要用到缓冲区,就要记得刷新
bufw.flush();
//其实关闭缓冲区,就是关闭缓冲区的流对象
bufw.close();
}
}
字符读取流缓冲区
从字符输入流中读取文本,缓冲各个字符,从而实现字符,数组,和行的搞笑读取
在进行对象建立的时候,也要有一个被缓冲的对象。
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class BufferDemo2 {
public static void main(String[] args) throws IOException {
//创建一个读取流对象和文件相关联
FileReader fr=new FileReader("buf.txt");
//为了提高效率。加入缓冲区将字符读取流对象作为参数传递给缓冲对象的构造函数
BufferedReader bufr=new BufferedReader(fr);
String line=null;
while((line=bufr.readLine())!=null){//一行一行的读取最为方便
System.out.println(line);
}
String s1=bufr.readLine();//读取一行只返回回车符之前的数据内容,不带任何行终止符
System.out.println("s1"+s1);
bufr.close();
}
}
通过缓冲区复制一个文本文件
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
* 通过缓冲区复制一个java文件
*
* @author Administrator
*
*/
public class Test9 {
public static void main(String[] args) {
BufferedReader bufr = null;
BufferedWriter bufw = null;
try {
bufr = new BufferedReader(new FileReader("c:\\Test8.java"));//缓冲读取流
bufw = new BufferedWriter(new FileWriter("d:\\Test8.java"));//缓冲输出流
String line = null;
while ((line = bufr.readLine()) != null) {
bufw.write(line);//把独到的这一行写出去
bufw.newLine();// 这里一定要写入一个新行,因为readLine不代表换行,关于readLine方法,见下面的讲解
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
bufr.close();// 关闭读取流
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
bufw.close();//关闭写入流
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
readLine方法原理:
无论是读一行,获取多个字符。其实最终都是在在硬盘上一个一个的读取。所以最终使用的还是read方法一次读一个的方法。读到回车符好\r\n时,就返回该数据中的数据。其实就是临时存入一个缓冲数组中。 比read方法高效很多。
返回:包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回null。
明白了BufferedReader类中特有方法readLine的原理后,
可以自定义一个类中包含功能和readLine一致的方法。来模拟一下BuffreedReader
package com.jbit.zhkk;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Test3 {
public static void main(String[] args) throws Exception {
MyBufferedReader mybuf = null;
FileReader fr = new FileReader("a.txt");
mybuf = new MyBufferedReader(fr);
String line = null;
while ((line = mybuf.myReadLine()) != null) {
System.out.println(line);
}
mybuf.myClose();
}
}
class MyBufferedReader {
private FileReader r;
public MyBufferedReader(FileReader r) {
this.r = r;
}
// 可以一次读取一行数据的方法。
public String myReadLine() throws IOException {// 谁调用谁处理,不需要try
// 定义一个临时容器,原BufferedReader封装的是字符数组。
// 为了演示方便,定义一个StringBuilder容器,因为最终还是要将数据变成字符串
StringBuilder sb = new StringBuilder();
int ch = 0;
while ((ch = r.read()) != -1) {
// 回车符有两个一个\r,一个\n
if (ch == '\r') {
continue;// 继续读取,不存储
}
if (ch == '\n') {// 到了行结尾,变成字符串返回
return sb.toString();
} else {// 如果不是\r或\n的话添加
sb.append((char) ch);
}
}
//
if (sb.length() != 0) {// 如果不加这个判断,代码是有问题的,假如鼠标的光标在末行的最后,最后一行不打印了。
// 相反加入这个判断,可以将缓冲区有数据,却没有被返回。直接返回null了。,直接将缓冲区的数据返回
return sb.toString();
}
return null;// 读到结尾没有数据返回null
}
/**
* 怎么关呢? 缓冲区为了提高FielReader而存在的
*/
public void myClose() {
try {
r.close();// 流关闭
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
装饰模式:
其实ReadLine的出现增强read方法的功能,那么增强功能的方式,将被增强的对象传递给增强类,以上的代码其实就是MyBufferedReader就是对FileReader的增强。这中方式叫做装饰设计模式。
解释:当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有对象的功能,并提供加强功能,
那么自定义的该类,就称为装饰类。
看下面代码的小例子
package com.jbit.zhkk;
/**
* 装饰设计模式: 当想要对已有的对象进行功能增强时, 可以定义类,将已有的对象传入,基于已有的功能,并提供加强功能。 那么自定义的该类称为装饰类。
* 装饰类通常会通过构造方法接受被装饰的对象。 并基于被装饰的对象的功能,提供更强的功能。
*
* @author Administrator
*
*/
public class Test4 {
public static void main(String[] args) {
Person p = new Person();
SuperPerson sp = new SuperPerson(p);
sp.superEat();
}
}
class Person {
public void eat() {
System.out.println("吃饭");
}
}
class SuperPerson {
private Person p;
public SuperPerson(Person p) {
this.p = p;
}
public void superEat() {
System.out.println("甜点");
p.eat();
System.out.println("香烟");
}
}
装饰模式比继承要灵活,避免了继承体系臃肿。
而且降低了类与类之间的关系。
装饰类因为增强已有的对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰类通常是都属于一个体系中的。
LineNumberReader的使用
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.LineNumberReader;
public class Test9 {
public static void main(String[] args) throws Exception {
FileReader fr = new FileReader("c:\\Test8.java");//创建文本流对象
LineNumberReader lnr = new LineNumberReader(fr);//LineNumberReader 关联文本流
String line = null;
//读取一行
while ((line = lnr.readLine()) != null) {
System.out.println(lnr.getLineNumber() + "::" + line);
}
lnr.close();//关闭,其实也就是fr.close()
}
}
模拟一个带行号的缓冲区对象
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Test9 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("c:\\Test8.java");// 读取流对象
MyLineReaderDemo frd = new MyLineReaderDemo(fr);// 自定义的模拟一个带行号的缓冲区类对象
String line = null;
while ((line = frd.readLine()) != null) {
System.out.println(frd.getLineNum() + ":" + line);
}
frd.close();
}
}
/**
* /自定义的模拟一个带行号的缓冲区类
*
* @author Administrator
*
*/
class MyLineReaderDemo {
private int linenum;// 当前行号
private FileReader fr;// 文本读取流
// 构造函数关联读取流
public MyLineReaderDemo(FileReader fr) {
this.fr = fr;
}
// 得到行号
public int getLineNum() {
return linenum;
}
// 读取一行
public String readLine() throws IOException {
linenum++;// 读取一行 行号加一
StringBuilder sb = new StringBuilder();// 字符串追加器,把一行的数据放到sb中。
int ch = 0;
// 一个行的结束就是\r\n
while ((ch = fr.read()) != -1) {
if ((char) ch == '\r') {
continue;// 读到\r继续读取
}
if ((char) ch == '\n') {
return sb.toString();// 读取\n返回字符串
} else {
sb.append((char) ch);
}
}
if (sb.length() != 0) {// 如果没有\r\n说明读取到了结尾行,直接返回sb
return sb.toString();
}
return null;
}
/**
* 设置开始行号
*
* @param linenum
*/
public void setlineNum(int linenum) {
this.linenum = linenum;
}
// 关闭流,其实就是读取流关闭
public void close() throws IOException {
fr.close();
}
}
优化后的代码是
package com.jbit.zhkk;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Test6 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("c:\\Test8.java");
MyLineReaderDemo frd = new MyLineReaderDemo(fr);
String line = null;
while ((line = frd.readLine()) != null) {
System.out.println(frd.getLineNum() + ":" + line);
}
frd.close();
}
}
/**
* 这里可以继承自定义的读取缓冲区
* @author Administrator
*
*/
class MyLineReaderDemo extends MyBufferedReader {
private int linenum;
public MyLineReaderDemo(FileReader fr) {
super(fr);//调用父类的构造函数,都是FileReader对象
}
public int getLineNum() {
return linenum;
}
public String readLine() throws IOException {
linenum++;
return super.myReadLine();//代码重复调用父类的myReadLine()就可
}
public void setlineNum(int linenum) {
this.linenum = linenum;
}
public void close() throws IOException {
super.myClose();
}
}
键盘录入
import java.io.IOException;
import java.io.InputStream;
public class Test9 {
public static void main(String[] args) throws IOException {
InputStream in = System.in;
StringBuilder sb = new StringBuilder();
while (true) {
int ch = in.read();
String s = null;
if ((char) ch == '\r') {// 读到\r继续下一次读取
continue;
}
if ((char) ch == '\n') {// 读到\n如果不是自定义结束标记的话,打印输出
s = sb.toString();
if (s == "over") {// 自定义over结束标记
break;
}
System.out.println(s);// 打印
sb.delete(0, sb.length());// 这里一定要重新清除,否则会自动追加到sb中。
} else {
sb.append((char) ch);// 如果没有读取到换行标记就追加
}
}
}
}
以上的例子,其实就是读一行的原理,也就是readLine方法。
能不能直接用readLine方法来完成键盘录入的一行数据的读取呢?
readLine方法是BufferedReader类的方法,而键盘录入的read方法是字节流InputStream的方法
能不能将字节流转成字符流在使用字符流缓冲区的ReadLine方法呢?
package com.jbit.zhkk;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Test9 {
public static void main(String[] args) throws IOException {
// 获取键盘录入对象
InputStream in = System.in;
// 将字节流对象转换成字符流对象,使用转换流。InputStreamReader
InputStreamReader isr = new InputStreamReader(in);
// 为了提高效率,将字符流进行缓冲区技术的搞笑操作,使用BufferedReader
BufferedReader bufr = new BufferedReader(isr);
String line = null;
while (((line = bufr.readLine())) != null) {
if ("over".equals(line)) {
break;
}
System.out.println(line.toUpperCase());
}
}
}
writer是写,把文件写出去,文件以字节形式存在的,而录入的都是字符,Reader这就是字符
从JDK文档中可以知道FileOutputStream是OutputStream 的直接子类,FileInputStream也是InputStream的直接子类,但是在字符流文件中的两个操作类却有一些特殊,FileWriter并不直接是Writer的子类,而是OutputStreamWriter的子类,而FileReader也不直接是Reader的子类,是InputStreamReader的子类,那么从这两个类的继承关系就可以清楚地发现,不管是使用字节流还是字符流实际上最终都是以字节的形式操作输入/输出流的。
package com.jbit.zhkk;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
public class Test9 {
public static void main(String[] args) throws IOException {
// 获取键盘录入对象
InputStream in = System.in;
// 将字节流对象转换成字符流对象,使用转换流。InputStreamReader
InputStreamReader isr = new InputStreamReader(in);
// 为了提高效率,将字符流进行缓冲区技术的高效操作,使用BufferedReader
BufferedReader bufr = new BufferedReader(isr);
OutputStream out=System.out;
OutputStreamWriter osw=new OutputStreamWriter(out);
BufferedWriter bufw=new BufferedWriter(osw);
String line = null;
while (((line = bufr.readLine())) != null) {
if ("over".equals(line)) {
break;
}
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();//字符输出流内部有缓冲区,把数据缓冲了,刷新
}
}
}
简写后的格式为
package com.jbit.zhkk;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
public class Test9 {
public static void main(String[] args) throws IOException {
// // 获取键盘录入对象
// InputStream in = System.in;
// // 将字节流对象转换成字符流对象,使用转换流。InputStreamReader
// InputStreamReader isr = new InputStreamReader(in);
// // 为了提高效率,将字符流进行缓冲区技术的搞笑操作,使用BufferedReader
// BufferedReader bufr = new BufferedReader(isr);
// 键盘录入最常见写法
BufferedReader bufr = new BufferedReader(new InputStreamReader(
System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(
System.out));
// OutputStream out=System.out;
// OutputStreamWriter osw=new OutputStreamWriter(out);
// BufferedWriter bufw=new BufferedWriter(osw);
String line = null;
while (((line = bufr.readLine())) != null) {
if ("over".equals(line)) {
break;
}
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
}
}
流对象的操作规律:
最痛苦的就是流对象有很多,不知道该用哪一个。
通过三个明确来完成。
1,明确源和目的
源:输入流。 InputStream Reader
目的:输出流。OutputStream Writer
2,操作的数据是否是存文本
是:字符流
不是:字节流
3,当体系明确后,再明确要使用哪个具体的对象。
通过设备来进行区分:
源 设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台。
io所有流的总结概述
首先是四大基本抽象流:字节流:InputStream、OutputStream,字符流:Reader、Writer;输入流:InputStream、Reader,输出流:
OutputStream、Writer;后面的所有流都是这四个的子类;
文件流:FileInputStream、FileOutputStream,FileReader、FileWriter,文件流算是四大基本抽象流的最初级实现类,前面两个是字节
流,可以用于任何格式文件的读写(因为文件的最基本存储形式就是字节数据),后面两个是字符流,只能用来处理文本文件;
缓冲流:字节流:BufferedInputStream、BufferedOutputStream,字符流:BufferedReader、BufferedWriter,这四个流用的是装饰设计
模式,在使用时要接收其它的流对象,比如文件流;同文件流一样,前面两个流可用于任何类型的文件读写,后面两个流主要用于文本文件
的读写,由于这四个流在建立对象后内部会自建缓冲区,所以读写的效率比较高,尤其是BufferedReader中的readLine()方法读取文本文
件特别合适,可以整行整行的读取,遇到换行符算是一行的结束,但是它不会返回换行符,所以需要在调用write()方法后用newLine()
方法新建换行符;
数据流:DataInputStream、DataOutputStream:用于基本类型数据的读写,采用装饰设计模式,构造方法的形参是流对象;
标准输入输出流:java.lang.System下的两个流,public static final InputStream in:标准输入流,此流已打开并准备提供输入数据。
通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。public static final PrintStream out:标准输出流,此流已打
开并准备接受输出数据。通常,此流对应于显示器输出或者由主机环境或用户指定的另一个输出目标。
转换流:输入流InputStreamReader,将读取的字节数据转换为字符数据,输出流:OutputStreamWriter,将字符转换为字节输出,这两个
流都采用装饰设计模式,构造方法的形参是流对象,都可以指定转码时的编码表或者使用平台默认的码表;
从键盘录入:BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
输出到控制台:法一:BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
法二:PrintWriter pw = new PrintWriter(System.out, true);(PrintWriter流属于Print流,加上true参数,表示自动刷新缓冲区,无需调用flush方法,
而且这个流中的println方法会自动添加换行符,无需再调用newLine方法)
File类:将用户传递过来的文件名或者文件的路径封装为类对象,然后在对其进行读写前进行一系列的判断:比如exists(),判断文件或
路径是否存在,isFile(),判断是不是文件,isDirectory(),判断是不是目录,如果结果为false,直接让程序return,这样做岂不是更
安全!
Print流:PrintStream和PrintWriter,都用于写出,前者构造方法接收的参数类型为String文件名、File对象、OutputStream对象,后者
构造方法接收的参数类型为String文件名、File对象、OutputStream对象以及Writer对象,由于后者接收的参数类型范围广,所以其使用的
频率更高。
public PrintWriter(Writer out, boolean autoFlush):若autoFlush的值为true,则每次输出一行后会自动刷新,无需调用flush方法,
否则等遇到输入结束标志,才会在关闭流的时候刷新,但此法仅限于使用println、printf或者format三个方法时有效;
public PrintStream(OutputStream out, boolean autoFlush):功能类似于PrintWriter,但只有使用println方法或者遇到换行符时就会
刷新;
其它流:ByteArrayInputStream:构造函数接收字节数组,也即数据源就是字节数组;
ByteArrayOutputStream:构造函数不需要数据目的地,因为在该流内部已经封装了一个字节数组作为目的地,它会随着写入数据的增多而
自动增长,可使用 toByteArray() 和 toString() 获取数据;
这两个流因为并没有调用底层系统资源,所以close方法无效,类中的方法在关闭此流后仍可被调用,它们也不会抛出IOException;
流操作中的数据源和目的地:
数据源:
键盘(System.in)、硬盘(FileInputStream(文件))、内存(ByteArrayInputStream);
数据目的地:
控制台(System.out)、硬盘(FileOutputStream(文件))、内存(ByteArrayOutputStream);
这众多的流中,除了最早出场的文件流外,其它的都是装饰设计模式,构造方法接收的形参都是流对象