23 IO流(3)
引言
早上已经完成IO流的相对应的练习,主要是IO流对电脑文件相对应的操作,FileInputStream和FileOutputStream的练习,接下来继续IO流,但主要会有点变化,接下来的是字符流综合使用
- 一篇文章中出现了多少个好字。读取数据,使用了字符流FileReader
- 演示FileWriter
- 演示转换流,和子类的区别五星
- 字符流缓冲区对象的使用
- 通过字符流复制文件
- 文件后缀名过滤器
- 分隔符工具类
- 请删除一个带有内容的目录
- 将学生对象(姓名,语文分数,数学分数,英语分数,总分)按照总分从高到低排序五星并将姓名和从高到低总分写入文件中
- 建立一个java文件清单列表
公共类Student.java
package cn.itcast.domain;
public class Student implements Comparable<Student>{
private String name;
private int cn,en,ma;
private int sum;
public Student() {
super();
}
public Student(String name, int cn, int en, int ma) {
super();
this.name = name;
this.cn = cn;
this.en = en;
this.ma = ma;
this.sum = cn + en + ma;
}
@Override
public int compareTo(Student o) {
int temp = this.sum - o.sum;
return temp==0?this.name.compareTo(o.name):temp;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + cn;
result = prime * result + sum;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (cn != other.cn)
return false;
if (sum != other.sum)
return false;
return true;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getCn() {
return cn;
}
public void setCn(int cn) {
this.cn = cn;
}
public int getEn() {
return en;
}
public void setEn(int en) {
this.en = en;
}
public int getMa() {
return ma;
}
public void setMa(int ma) {
this.ma = ma;
}
public int getSum() {
return sum;
}
public void setSum(int sum) {
this.sum = sum;
}
@Override
public String toString() {
return "Student [name=" + name + ", sum=" + sum + "]";
}
}
一篇文章中出现了多少个好字。读取数据,使用了字符流FileReader
package cn.itcast.io.a.charstream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
public class CharStreamDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/*
* 需求1:通过流写一个篇文章,里面有中文。"你好你好"。indexOf('好');
*/
// writeCNText();
/*
* 需求2:一篇文章中出现了多少个好字。读取数据。判断好字并计数。
* 思路:读取一个文本,获取内容判断好字。
*/
readCNText();
/*
* 解决需求2问题:
* 使用FileReader。
*
*/
System.out.println("-----------读取字符-------------");
readCNTextByReader();
}
public static void readCNTextByReader() throws IOException {
//创建一个读取字符文件的读取流对象。FileReader。
FileReader fr = new FileReader("tempfile\\cn.txt");//这个流的底层使用的是FileInputStream
// int ch = fr.read();
// System.out.println("读取一个字符:"+ch);
// int ch1 = fr.read();//一次读取一个中文,读取多个字节查表转成中文。
// System.out.println("读取一个字符:"+(char)ch1);
int ch = 0;
int count = 0;
while((ch=fr.read())!=-1){
if(ch=='好'){
count++;
}
}
System.out.println("count="+count);
fr.close();
}
public static void readCNText() throws IOException {
FileInputStream fis = new FileInputStream("tempfile\\cn.txt");
//一次读一个字节。这样对中文是无法判断。怎么解决呢?一个中文默认是两个字节。
//读取所有的字节,存储起来(字节数组),变成字符串。然后找指定的字符。
// byte[] buf = new byte[4];
// int len = 0;
// while((len=fis.read(buf))!=-1){
// String str = new String(buf,0,len);
// System.out.println(str);
// }
// int ch = 0;
// while((ch=fis.read())!=-1){
// System.out.println(ch);
// }
int ch = fis.read();
System.out.println("读取一个字节:"+ch);
int ch1 = fis.read();
System.out.println("读取一个字节:"+ch1);
fis.close();
}
public static void writeCNText() throws FileNotFoundException, IOException {
FileOutputStream fos = new FileOutputStream("tempfile\\cn.txt");
fos.write("你好你好".getBytes());
fos.close();
}
}
演示FileWriter
package cn.itcast.io.a.charstream;
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
//演示FileWriter 用于操作文件的便捷类。
FileWriter fw = new FileWriter("tempfile\\fw.txt");
fw.write("你好谢谢再见");//这些文字都要先编码。都写入到了流的缓冲区中。
fw.flush();
fw.close();
/*
* flush()和close()的区别?
*
* flush():将流中的缓冲区缓冲的数据刷新到目的地中,刷新后,流还可以继续使用。
* close():关闭资源,但在关闭前会将缓冲区中的数据先刷新到目的地,否则丢失数据,然后在关闭流。流不可以使用。
*
* 如果写入数据多,一定要一边写一边刷新,最后一次可以不刷新,由close完成刷新并关闭。
*
*
*/
}
}
//public void close(){
// flush();
//}
演示转换流,和子类的区别五星
package cn.itcast.io.b.transstream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
public class TransStreamDemo {
/**
* @param args
* @throws IOException
* @throws UnsupportedEncodingException
*/
public static void main(String[] args) throws Exception {
// writeCN();
readCN();
/*
总结:
发现继承关系是这样的。
OutputStreamWriter:
|--FileWriter:
InputStreamReader:
|--FileReader;
父类和子类的功能有什么区别呢?
OutputStreamWriter和InputStreamReader是字符和字节的桥梁:也可以称之为字符转换流。
字符转换流原理:字节流+编码表。
FileWriter和FileReader:作为子类,仅作为操作字符文件的便捷类存在。
当操作的字符文件,使用的是默认编码表时可以不用父类,而直接用子类就完成操作了,简化了代码。
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));//默认字符集。
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"GBK");//指定GBK字符集。
FileReader fr = new FileReader("a.txt");
这三句代码的功能是一样的,其中第三句最为便捷。
注意:一旦要指定其他编码时,绝对不能用子类,必须使用字符转换流。
什么时候用子类呢?
条件:
1,操作的是文件。
2,使用默认编码。
字节--->字符 : 看不懂的--->看的懂的。 需要读。输入流。 InputStreamReader
字符--->字节 : 看的懂的--->看不懂的。 需要写。输出流。 OutputStreamWriter
*/
}
public static void readCN() throws IOException {
//创建InputStreamReader对象。
InputStreamReader isr = new InputStreamReader(new FileInputStream("tempfile\\u8cn.txt"),"UTF-8");
char[] buf = new char[1024];
int len = isr.read(buf);
System.out.println(new String(buf,0,len));
isr.close();
}
//读取中文。
public static void readCN_no() throws IOException {
// 使用FileReader没出来,因为文件是UTF-8编码。读取UTF-8字节时,用该指定用UTF-8解码。
// 说明需要指定码表。那就需要使用InputStreamReader。
FileReader fr = new FileReader("tempfile\\u8cn.txt");
// int ch = (char)fr.read();
// System.out.println((char)ch);
char[] buf = new char[1024];
int len = fr.read(buf);
System.out.println(new String(buf,0,len));//浣犲ソ
fr.close();
}
public static void writeCN() throws Exception {
//需求:既然识别中文的码表有两个,GBK UTF-8
//能不能将中文数据按照utf-8的方式进行文件的存储呢?
//还能使用FileWriter吗?不能使用了,因为FileWriter中默认的是GBK
//通过FileWriter的api描述,要指定编码表这些值,需要使用OutputStreamWriter
//OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。
//它的作用的就是,将字符串按照指定的编码表转成字节,在使用字节流将这些字节写出去。
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("tempfile\\u8cn.txt"),"utf-8");
osw.write("你好");//写入缓冲区。
osw.close();
}
}
字符流缓冲区对象的使用
package cn.itcast.io.c.charstream.buffercopy;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CharStreamBufferedTest {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/*
* 字符流中是否有提供缓冲区中。
* 注意:其实自定义数组就可以解决问题缓冲区问题并提高效率。
* 为什么还要使用流中的缓冲区对象呢?因为缓冲区对象中除了封装数组以外,
* 还提供了更多的操作缓冲区数据的方法。
* BufferedReader BufferedWriter
*
* 讲解字符流缓冲区中的特有方法。
* 操作字符数据时,有一个文本特有的表形实行 :行(hang)
* 操作行的方法。
* BufferedReader:readLine():一次读取一行。
* BufferedWriter:
*/
copyTextByBuffer();
// readText();
// writeText();
}
public static void writeText() throws IOException {
BufferedWriter bufw = new BufferedWriter(new FileWriter("tempfile\\test24_buf.txt"));
for(int x=1; x<=4; x++){
bufw.write(x+"-itcast");
bufw.newLine();
bufw.flush();
}
bufw.close();
}
public static void readText() throws IOException {
BufferedReader bufr = new BufferedReader(new FileReader("Test24.java"));
String line = null;
while((line=bufr.readLine())!=null){
System.out.println(line);
}
// String line = bufr.readLine();
// System.out.println("-"+line+"-");
// String line1 = bufr.readLine();
// System.out.println("-"+line1+"-");
bufr.close();
}
public static void copyTextByBuffer() throws IOException {
BufferedReader bufr = new BufferedReader(new FileReader("Test24.java"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("tempfile\\test24_bufcopy.txt"));
//循环读写一行数据。
String line = null;
while((line=bufr.readLine())!=null){
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufw.close();
bufr.close();
}
}
通过字符流复制文件
package cn.itcast.io.c.charstream.copy;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyTextFileTest {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/*
* 练习:复制文本文件。
* 思路:
* 1,既然是文本涉及编码表。需要用字符流。
* 2,操作的是文件。涉及硬盘。
* 3,有指定码表吗?没有,默认就行。
* 操作的是文件,使用的 默认码表。使用哪个字符流对象。直接使用字符流操作文件的便捷类。FileReader FileWriter
*/
copyTextFile();
}
public static void copyTextFile() throws IOException {
//1,明确源和目的。
FileReader fr = new FileReader("Test24.java");
FileWriter fw = new FileWriter("tempfile\\test24_copy.txt");
//2,为了提高效率。自定义缓冲区数组。字符数组。
char[] buf = new char[1024];
int len = 0;
while((len=fr.read(buf))!=-1){
fw.write(buf,0,len);
}
//2,循环读写操作。效率低。
// int ch = 0;
// while((ch=fr.read())!=-1){
// fw.write(ch);
// }
//3,关闭资源。
fw.close();
fr.close();
}
}
文件后缀名过滤器
package cn.itcast.io.test;
import java.io.File;
import java.io.FileFilter;
public class FileFilterBySuffix implements FileFilter {
private String suffix;
public FileFilterBySuffix(String suffix) {
super();
this.suffix = suffix;
}
@Override
public boolean accept(File pathname) {
return pathname.getName().endsWith(suffix);
}
}
[分隔符工具类]
package cn.itcast.io.test;
/**
* 为了避免总是调用System.getProperties("系统属性中的指定键");
* 进行了封装。下次再使用分隔符,直接找个分隔符工具类就哦了。
* @author Teaching
*
*/
public class SeparatorTool {
private SeparatorTool() {
super();
}
public static final String LINE_SEPARATOR = System.getProperty("line.separator");
public static final String PATH_SEPARATOR = System.getProperty("path.separator");
public static final String FILE_SEPARATOR = System.getProperty("file.separator");
}
请删除一个带有内容的目录
package cn.itcast.io.test;
import java.io.File;
public class Test2 {
/**
* @param args
*/
public static void main(String[] args) {
// 2,请删除一个带有内容的目录。
/*
* 思路: 1,删除一个带有内容的目录原理;必须从里往外删。 2,到底有多级目录不确定,递归。
*/
File dir = new File("E:\\test");
// System.out.println(dir.delete());
removeDir(dir);
}
/**
* 删除一个目录。
*/
public static void removeDir(File dir) {
// 1,列出当前目录下的文件以及文件夹File[]
File[] files = dir.listFiles();//如果目录是系统级文件夹,java没有访问权限,那么会返回null数组。最好加入判断。
if (files != null) {
// if(files.length == 0){
// dir.delete();
// return;
// }
for (File file : files) {
// 2,对遍历到的file对象判断是否是目录。
if (file.isDirectory()) {
removeDir(file);
} else {
System.out.println(file + ":" + file.delete());// 删除文件。用打印语句验证是否删除成功,是否出现了误删操作。
}
}
}
System.out.println(dir + ":" + dir.delete());
}
}
将学生对象(姓名,语文分数,数学分数,英语分数,总分)按照总分从高到低排序五星并将姓名和从高到低总分写入文件中
package cn.itcast.io.test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;
import cn.itcast.domain.Student;
public class Test4 {
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// 4,将学生对象(姓名,语文分数,数学分数,英语分数,总分)按照总分从高到低排序,
// 并将姓名和从高到低总分写入文件中。
/*
* 思路:
* 1,描述学生。
* 2,既然要按照总分从高到低排序,学生多要存储集合,TreeSet。
* 3,将信息具体的信息保存到文件中。
* 操作文件,持久化存储,涉及了IO技术。而且是将数据存储到文件中。所以写入。输出流。
*
*/
Set<Student> set = new TreeSet<Student>(Collections.reverseOrder());
set.add(new Student("李四",20,20,20));
set.add(new Student("旺财",10,10,20));
set.add(new Student("小明",60,30,70));
set.add(new Student("小红",80,90,80));
set.add(new Student("小强",20,70,20));
File dir = new File("tempfile");
if(!dir.exists()){
dir.mkdir();
}
File destFile = new File(dir,"student_info.txt");
write2File(set,destFile);
}
public static void write2File(Set<Student> set, File destFile) throws IOException {
//1, 创建输出流对象和目的文件关联。并创建目的文件。OutputStream操作文件 FileOutputStream。
FileOutputStream fos = null;
try{
fos = new FileOutputStream(destFile);
//2,遍历集合中的对象数据。将数据写入到指定文件中。
for(Student stu : set){
String info = stu.getName()+"\t"+stu.getSum()+LINE_SEPARATOR;
//3,将数据写入到文件中。
fos.write(info.getBytes());
}
}finally{
if(fos!=null){
//关闭资源。
try {
fos.close();
} catch (IOException e) {
throw new RuntimeException("系统资源关闭失败");
}
}
}
}
}
建立一个java文件清单列表
package cn.itcast.io.test;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class Test5 {
private static final String LINE_SEPARATOR = SeparatorTool.LINE_SEPARATOR;
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// 5,获取指定目录下所有的.java文件(包含子目录中的),
// 并将这些java文件的绝路路径写入到一个文件中。
// 建立一个java文件清单列表。
/*
* 思路:
* 1,一看到包含子目录,必须递归。
* 2,写数据到文件,输出流。
* 3,继续分析,发现只要.java ,需要过滤器。
* 4,满足过滤的条件的文件有可能非常多,先进行存储。
*/
//被遍历的目录。
File dir = new File("E:\\Java_Code");
//明确一个过滤器。
FileFilter filter = new FileFilterBySuffix(".java");
//符合过滤器条件的文件有很多,最好先存储起来,然后在进行操作。
List<File> list = new ArrayList<File>();
//获取指定文件清单。
getFileList(dir,filter,list);
// System.out.println(list.size());
File destFile = new File(dir,"javalist.txt");
write2File(list,destFile);
}
/**
* 将集合中的数据的绝对路径写入到文件中。
* @param list
* @param destFile
* @throws IOException
*/
public static void write2File(List<File> list, File destFile) throws IOException {
FileOutputStream fos = null;
BufferedOutputStream bufos = null;
try{
fos = new FileOutputStream(destFile);
bufos = new BufferedOutputStream(fos);
for(File file : list){
String info = file.getAbsolutePath()+LINE_SEPARATOR;
bufos.write(info.getBytes());
bufos.flush();//每写一个绝对路径就刷新一次。
}
}finally{
if(bufos!=null){
try {
fos.close();
} catch (IOException e) {
throw new RuntimeException("关闭失败");
}
}
}
}
/**
* 根据指定的过滤器在指定目录下获取所有的符合过滤条件的文件,并存储到list集合中。
* @param dir
* @param filter
* @param list
*/
public static void getFileList(File dir,FileFilter filter,List<File> list) {
File[] files = dir.listFiles();
for(File file : files){
if(file.isDirectory()){
getFileList(file,filter,list);
}else{
//如果是文件,传递到过滤器中去过滤。将满足条件存储起来。
if(filter.accept(file)){
list.add(file);
}
}
}
}
}