字符流的抽象基类:
字节流的抽象基类:
特点:四个类派生出来的子类名称都是以其父类名作为子类名的后缀
字节流+编码表
继承体系:
特点:文件不存在,则会自动创建;如果文件存在,则会被覆盖
基本方法:
步骤:
IO流的异常处理方式:为防止代码异常导致流无法关闭,因此在finally中对流进行关闭。
FileWriter fw = null;
try {
fw = new FileWriter("demo.txt");
fw.write("abcdefg");
}
catch (IOException e) {
System.out.println(e.toString());
}
finally {
try {
if(fw!=null)
fw.close();
}
catch (IOException e) {
throw new RuntimeException("关闭失败");
}
继承体系:
特点:最后带Reader的均为其子类
字符读取流缓冲区:BufferedReader
特点:使用了读取缓冲区的read方法,将读取到的字符进行缓冲并判断换行标记,将标记前的缓冲数据变成字符串返回。
代码示例:
/*
明白了BufferedReader类中特有方法readerLine的原理后,
可以自定义一个类中包含一个功能和readLine一致的方法。
来模拟一下BufferedReader
*/
import java.io.*;
class MyBufferedReader extends Reader{
private Reader r;
MyBufferedReader(Reader r) {
this.r = r;
}
//可以一次读一行数据的方法。
public String myReadLine() throws IOException{
//定义一个临时容器。原BufferedReader封装的是字符数组。
//为了演示方便。定义一个StringBuilder容器,因为最终还是要将数据变成字符串。
StringBuilder sb = new StringBuilder();
int ch =0;
while ((ch=r.read())!=-1) {
if(ch=='\r')//跳过\r
continue;
if(ch=='\n')
return sb.toString();//通过回车符来标识每一行的数据返回;若文件的最后一行没有回车符,该行将不会返回,因此需在循环结束时,增加判断语句。
else
sb.append((char)ch);
}
if(sb.length()!=0)
return sb.toString();
return null;
}
/*
覆盖Reader类中的抽象方法
*/
public int read(char[] cbuf,int off, int len) throws IOException {
return r.read(cbuf,off,len);
}
public void close()throws IOException {
r.close();
}
public void myClose()throws IOException{
r.close();
}
}
class MyBufferedReaderDemo {
public static void main(String[] args) throws IOException{
FileReader fr = new FileReader("buf.txt");
MyBufferedReader myBuf = new MyBufferedReader(fr);
String line = null;
while ((line=myBuf.myReadLine())!=null) {
System.out.println(line);
}
myBuf.myClose();
}
}
运行结果:
LineNumberReader类:BufferedReader的子类。跟踪行号的缓冲字符输入流。
字符输出流缓冲区:BufferedWriter
基本操作与字符流类相同。但它不仅可以操作字符,还可以操作其他媒体文件。
字节流两个基类:
InputStream
OutputStream
//读取方式一
public static void readFile_1() throws IOException {
//创建一个读取流对象,和指定文件关联
FileInputStream fis = new FileInputStream("fos.txt");
//打印刚好字符字节大小,不过要少用,当文件太大时,可能内存溢出
byte[] buf = new byte[fis.available()];//定义一个刚刚好的缓冲区,不用再循环了
fis.read(buf);
System.out.println(new String(buf));
fis.close();
}
//读取方式二
public static void readFile_2() throws IOException {
FileInputStream fis = new FileInputStream("fos.txt");
//建议使用这种方式
byte[] buf = new byte[1024];
int len =0;
while ((len=fis.read(buf))!=-1) {
System.out.println(new String(buf,0,len));
}
fis.close();
}
//读取方式三
public static void readFile_3() throws IOException{
FileInputStream fis = new FileInputStream("fos.txt");
//一次读取一个字节
int ch = 0;
while ((ch=fis.read())!=-1) {
System.out.println((char)ch);
}
fis.close();
}
应用:字节流中的数据都是字符时,转成字符流操作更高效。
注:
FileWriter fw = new FileWriter("a.txt");
等同OutputStreamWriter osw = new OutputStreamWriter(newFileOutputStream("a.txt"),"GBK");
其实就是转换流指定了本机默认码表的体现,而且这个转换流的子类对象,可以方便操作文本文件。简单说:操作文件的字节流+本机默认的编码表。是按照默认码表来操作文件的便捷类;如果操作文本文件需要明确具体的码表必须用转换流。
说明:使用字节流读取一个中文字符需要读取两次,因为一个中文字符由两个字节组成,而使用字符流只需读取一次。
InputStream in = System.in;
InputStreamReader isr = new InputStreamReader(in);
BufferedReader bufr =new BufferedReader(isr);
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw =new BufferedWriter(new OutputStreamWriter(System.out));
是否需要额外功能
是否需要高效(缓冲区)
代码示例:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
/*
* 需求:把键盘录入的数据按照指定的编码表(utf-8),存到文件中。
* 分析:
* 源:键盘(System.in)
* 目的:FileWriter
*
* 纯文本 Writer
*
* 设备:硬盘,一个文件,使用FileWriter
* 但是FileWriter是使用的默认编码表:GBK,存储时,需要加入指定的编码表,而指定的编码表只有转换流可以指定
* 所以要使用的对象是OutputStreamWriter。
* 而该转换流对象需要接收一个字节输出流,而且还可以操作的文件的字节输出流:FileOutputStream
* OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt","UTF-8"));
*
* 需要提高效率吗?需要
* BufferedWriter bufw = new BufferedWriter(osw);
*/
public class TransStreamDemo {
public static void main(String[] args) throws IOException {
// 更改源
// System.setIn(new FileInputStream("PersonDemo.java"));
// 更改目标,将会生成一个空文件(若不存在,存在则会覆盖)
System.setOut(new PrintStream("zz.txt"));
// 键盘录入
BufferedReader bufr = new BufferedReader(new InputStreamReader(
System.in));
// 按照指定的编码表(utf-8),将数据存到文件中
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream("d1.txt"), "UTF-8"));
String line = null;
while ((line = bufr.readLine()) != null) {
if ("over".equals(line))
break;
// System.out.println(line.toUpperCase());
bufw.write(line.toUpperCase());
bufw.newLine();// newLine()为BufferedReader特有方法,跨平台
bufw.flush();
}
bufr.close();
}
}
用来将文件或者文件夹封装成对象,方便对文件与文件夹的属性信息进行操作。
File对象可以作为参数传递给流的构造函数。
File(File parent, String child) 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例。
//可以将一个已存在的,或者不存在的文件或者目录封装成file对象,不会创建文件
//方式一:
File f1 = new File("d:\\demo\\a.txt" );
//方式二:
File f2 = new File("d:\\demo" ,"a.txt" );
//方式三:
File f = new File("d:\\demo" );
File f3 = new File(f,"a.txt" );
/*考虑到Windows和Linux系统通用(File.separator是与系统有关的默认名称分隔符。
在 UNIX 系统上,此字段的值为 '/';在 MicrosoftWindows 系统上,它为 '\\'。):
*/
File f4 = new File("d:" + File.separator + "demo" +File.separator + "a.txt" );
删除:
判断:
获取信息:
注:该方法的File对象中封装的必须是目录,否则会产生NullPointerException,如果访问的是系统级目录也会发生空指针异常;如果目录存在但是没有内容,会返回一个数组,但是长度为0。
重命名:
boolean renameTo(File dest)重新命名此抽象路径名表示的文件。
//示例:
File f1 = new File("d:\\code\\day21\\0.mp3" );
File f2 = new File("d:\\code\\day21\\1.mp3" );
boolean b = f1.renameTo(f2);
import java.io.File;
import java.io.FilenameFilter;
/*
* 需求:获取指定目录下,任意一个指定类型文件的列表
* 分析:可以使用 String[] list(FilenameFilter filter)方法
* 自定义一个类,实现FilenameFilter接口,覆盖其accept方法
*/
public class FileListDemo {
public static void main(String[] args) {
// 建立一个指定目录的File对象
File dir = new File("D:\\Java\\Day20");
dirList(dir);
}
private static void dirList(File dir) {
// 调用传入File对象的list方法,并传入一个自定义文件名过滤器类
String[] dirname = dir.list(new MyTypeFilter(".java"));
for (String s : dirname) {
System.out.println(s);
}
}
}
// 自定义文件名过滤器类,并实现FilenameFilter接口,覆盖accept方法
class MyTypeFilter implements FilenameFilter {
private String type;
// 定义构造器
public MyTypeFilter(String type) {
this.type = type;
}
@Override
public boolean accept(File dir, String name) {
return name.endsWith(type);
}
}
运行结果:
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/*
*需求:
* 将一个指定目录下的java文件的绝对路径,存储到一个文本文件中。
* 建立一个java文件列表文件。
*
*思路:
* 1,对指定的目录进行递归
* 2,获取递归过程所有的java文件路径。
* 3,将这些路径存储到集合中。
* 4,将集合中的数据写入到一个文件中。
*/
class JavaFileListDemo {
public static void main(String[] args) {
// 将指定目录封装成对象
File dir = new File("D:\\Java");
// 建立集合用于存放路径
List list = new ArrayList();
// 调用自定义获取文件列表方法
fileToList(dir, list);
// System.out.println(list.size());
File file = new File(dir, "javalist.txt");
// 调用自定义将集合数据,写入文件的方法
writeToFile(list, file.toString());
}
// 自定义获取文件列表方法
public static void fileToList(File dir, List list) {
File[] files = dir.listFiles();
for (File f : files) {
if (f.isDirectory())
// 当路径仍为目录时,进行递归
fileToList(f, list);
else {
// 直到是java文件时,将路径存储到集合中
if (f.getName().endsWith(".java"))
list.add(f);
}
}
}
// 定义一个将集合数据,写入文件的方法
public static void writeToFile(List list, String javaListFile) {
BufferedWriter bufw = null;
try {
bufw = new BufferedWriter(new FileWriter(javaListFile)); // 传入一个用于存放数据的文件字符串名"D:\\Java\\javalist.txt"
for (File f : list) {
String path = f.getAbsolutePath();
bufw.write(path);
bufw.newLine();
bufw.flush();
}
} catch (IOException e) {
throw new RuntimeException("文件写入失败");
} finally {
try {
if (bufw != null)
bufw.close();
} catch (IOException e) {
throw new RuntimeException("写入关闭失败");
}
}
}
}