------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
今天学习IO流.
一.字符流
1.字符流是可以直接读写字符的IO流
2.字符流读取字符,就要先读取到字节数据,然后转为字符,如果要写出字符,需要把字符转为字节再写出.
3.Reader抽象类
子类InputStreamReader
子类FileReader
二.FileWriter
三.字符流的拷贝.
1.语句:
FileReader fr=new FileReader("a1.txt");
FileWriter fw=new FileWriter("a1copy.txt")
int ch;
while( (ch=fr.read()) != -1){
fw.writer(ch);
}
fr.close();
fw.close();
2.Writer底层是有缓冲区的,有一个字符数组writeBuffer,大小是1024个字符,也就是2048个字节,2KB.
如果不关流,内容就在缓冲区里,如果关流,就会刷新缓冲区.
四.什么情况使用字符流
1.字符流可以拷贝文本文件,但是不推荐使用,因为读取时会把字节转为字符,写出时还要把字符转回字节.
2.程序需要读取一段文本,或者需要写出一段文本的时候可以使用字符流.
读取的时候是按照字符的大小读取的,不会出现半个中文,写出的时候可以直接将字符串写出,不用转换为字节数组.
五.字符流是否可以拷贝非纯文本的文件.
1.不可以拷贝非纯文本的文件
2.因为在读的时候会将字节转换为字符,在转换过程中,可能找不到对应的字符,就会用?代替,写出的时候会将字符转换成字节写出去.
如果是?问号,直接写出,这样写出之后的文件就乱了,看不了了.
六.自定义字符数组的拷贝
FileReader fr=new FileReader("a1.txt");
FileWriter fw=new FileWriter("a1copy.txt")
char[] arr=new char[1024*8];
int len;
while( (ch=fr.read(arr)) != -1){
fw.write(arr,0,len);
}
fr.close();
fw.close();
七.带缓冲的字符流
BufferedReader br=new BufferedReader(new FileReader("a1.txt"));
BufferedWriter bw=new BufferedWriter(new FileWriter("a1copy.txt");
int ch;
while( (ch=br.read()) != -1){
bw.write();
}
br.close();
bw.close();
八.readLine()和newLine()方法
1.BufferedReader的readLine()方法可以读取一行字符(不包含换行符号)
2.BufferedWriter的newLine()方法可以输出一个跨平台的换行符号"\r\n".
BR br;
BW bw;
String line;
while( (line=br.readLine()) != null){
bw.write(line);
//bw.write("\r\n"); /windows系统
bw.newLine();
}
br.close();
bw.close();
九.将文本反转
分析:
1.创建输入输出流对象.
2.创建集合对象
3.将读到的数据存储在集合中
4.倒着遍历集合将数据写到文件上.
5.关流
BR br;
BW bw;
ArrayList<String> list =new ArrayList<>();
String line;
while( (line=br.readLine()) !=null){
list.add(line);
}
for(int i=list.size()-1;i>=0;i--){
bw.write(list.get(i));
bw.newLine();
}
br.close();
bw.close();
注意:流对象尽量晚开早关
所以改写:
BR br;
ArrayList;
String line;
while{}
br.close();
BW bw;
for{}
bw.close();
十.LineNumberReader
1.两个方法
setLineNumber()和getLineNumber()
2.getLineNumber()
LineNumberReader lnr=new LineNumberReader(new FileReader("a1.txt");
String line;
while( (line=lnr.readLine()) != null){
sysout(lnr.getLN+"+++"+line);
}
3.setLineNumber()
setLineNumber(100);
设置成100,那么第一行就是101.
十一.装饰设计模式
装饰设计模式就是对被装饰的对象的功能进行加强.
十二.使用指定的码表读写字符.
1.FileReader是使用默认码表读取文件,如果需要使用指定码表读取,那么可以使用InputStreamReader(字节流,编码表);
2.FileWriter是使用默认码表写出文件,如果需要使用指定码表写出,那么可以使用OutputStreamReader(字节流,编码表);
3.默认的编码表其实就是GBK.
UTF-8码表中一个中文是3个字节.
4.代码:
不能用FileReader,要用InputStreamReader
InputStreamReader isr=new InputStreamReader(new FileInputStream("utf-8.txt"),"utf-8");
OutputStreamWriter osw=new InputStreamWriter(new FileOutputStream("gbk.txt"),"gbk");
int c;
while( (c=isr.read()) != -1){
osw.write(c);
}
isr.close();
osw.close();
十三.转换流图解
utf-8.txt----------FileInputStream字节流----------InputStreamReader字节通向字符的桥梁,通过指定的编码表将字节转换为字符----------BufferedReader
BufferedWriter----------OutputStreamWriter字符通向字节的桥梁,通过指定的编码表将字符转换为字节----------FileOutputStream字节流----------gbk.txt
十四.获取文本上字符出现的次数.
分析:
1.创建带缓冲的输入流对象.
2.创建双列集合对象TreeMap
3.将读到的字符存储在双列集合中,存储的时候要做判断,如果不包含这个键,就将键和1存储,如果包含这个键,就将键和值加1存储
4.关闭输入流
5.创建输出流对象
6.遍历集合将集合中的内容写到times.txt中
7.关闭输出流.
BufferedReader br=new BufferedReader(new FileReader("a1.txt");
TreeMap<Character,Integer> tm=new TreeMap<>();
int ch;
while( (ch=br.read()) != -1){
char c=(char) ch;
/*if(!tm.containsKey(c)){
tm.put(c,1);
}else{
tm.put(c,tm.get(c)+1);
}*/
tm.put(c,!tm.containsKey(c)?1:tm.get(c)+1);
}
br.close();
BufferedWriter bw=new BufferedWriter(new FileWriter("times.txt"));
for(Character key:tm.keySet()){
bw.write(key+"="+tm.get(key));
bw.newLine();
}
bw.close();
修改:
for(Character key:tm.keySet()){
switch(key){
case'\t':
bw.write("\\t"+"="+tm.get(key));
break;
case'\n':
bw.write("\\n"+"="+tm.get(key));
break;
case'\r':
bw.write("\\r"+"="+tm.get(key));
break;
default:
bw.write(key +"="+tm.get(key));
break;
}
}
十五.试用版软件
当我们下载一个试用版软件,没有购买正版的时候,每执行一次就会提醒我们还有多少使用机会,用学过的IO流知识,模拟试用版软件,试用10此机会,执行一次就提示您还有几次机会,如果次数到了就提示请购买正版.
分析:
1.创建带缓冲的输入流对象,因为要使用readLine方法,可以保证数据的原样性
2.将读到的字符串转换为int数.
3.对int数进行判断,如果大于0,就将其--写回去,如果不大于0,就提示请购买正版
4.在if判断中要将--的结果打印,并将结果通过输出流写到文件上.
BufferedReader br=new BufferedReader(new FileReader("config.txt");
String line=br.readLine();
int times=Integer.parseInt(line);
if(times>0){
sysout("剩"+times--+"次机会");
FileWriter fw=new FileWriter("config.txt");
fw.write(times+"");
fw.close();
}else{
sysout("用完");
}
br.close();
十六.File类(递归)
1.递归就是: 方法自己调用自己
例如:
method(){
method();
}
2.5的阶乘 5!=5*4*3*2*1.
分析:
1.5*fun(4).
2. 4*fun(3).
3. 3*fun(2).
4. 2*fun(1).
代码:
public int fun(int num){
if(num==1){
return 1;
}else{
return num*fun(num-1);
}
}
弊端:如果调用次数过多,就会导致栈内存溢出.
还有可能栈内存没有溢出,但是到6000-7000次左右的时候算出来的结果已经超出了int的范围,所以结果是0.
好处:不用知道循环的次数.
3.构造方法是否可以递归调用呢?
不能,因为无穷调用.
4.递归调用是否必须有返回值?
不一定
十七.练习
需求:从键盘输入接收一个文件夹路径,打印出该文件夹下所有的.java文件名.
分析:
1.如果录入的是不存在,给提示
2.如果录入的是文件路径,给提示
3.如果是文件夹路径,直接返回
打印出所有.java文件名
1.获取到该文件夹路径下所有的文件和文件夹,存储在File数组中
2.遍历数组,对每一个文件或文件夹做判断
3.如果是文件,并且后缀是.java的就打印
4.如果是文件夹,就递归调用
public static File getDir(){
Scanner sc=new Scanner(S.in);
sysout("请输入一个文件夹路径");
while(true){
String line=sc.nextLine();
File dir=new File(line);
if(!dir.exists()){
sysout("文件夹路径不存在");
}else if(dir.isFile()){
sysout("是文件路径");
}else{
return dir;
}
}
}
public void printJavaFile(File dir){
File[] subFiles=dir.listFiles();
for(File subFile:subFiles){
if(subFile.isFile()&&subFile.getName().endsWith(".java")){
sysout(subFile);
}else if(subFile.isDirectory()){
printJavaFile(subFile);
}
}
}
main:
File dir=getDir();
printJavaFile(dir);