------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
IO流
1.什么是IO流?
IO流分类:
IO体系基类:
IO体系子类命名特点:
举例使用该体系一员:
FileWriter fw=new FileWriter("demo.txt");
fw.write("123");
fw.flush();
fw.close();
我们看到这是一个处理文件的字符输出流,也就是说将数据写到文件中,那么可知我们必须得有一个文件吧,"demo.txt"就是传入那个文件名的。
如果该文件不存在,那么就在指定路径下创建它,如果存在,则覆盖它。
IOException处理流程:
try
{
FileWriter fw = new FileWriter("demo.txt");
fw.write("123");
fw.flush();
}
catch(IOException e)
{
//处理该打开或者写入异常
}
finally
{
if(fw!=null)
try
{
fw.close();
}
catch(IOException e)
{
//处理关闭异常
}
}
文件续写:
FileWriter fw=new FileWriter("demo.txt",true);
第二个参数表示是否以附加的方式写入数据,我们传入true就不会覆盖掉原本的数据了。
//文件的续写
package com.helong.filewriterdemo2;
import java.io.*;
class FileWriterDemo2
{
public static void main(String[] args)
{
FileWriter fw=null;
try
{
fw=new FileWriter("Demo2.txt",true);//true表示以续写的方式打开文件
fw.write("\r\n第二行\r\n第三行");
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
if(fw!=null)
fw.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
文本拷贝原理:
拷贝文件练习:
package com.helong.copyfile;
import java.io.*;
class CopyFile
{
public static void main(String[] args) throws IOException
{
//copy1();
copy2();
}
//这种方法效率太低,每次取出一个字符然后写入,要重复很多次硬盘和内存之间的交互
private static void copy1()throws IOException
{
//每次取出一个字符,写入目的地文件
FileWriter fw = new FileWriter("Demo(2).txt");
FileReader fr = new FileReader("Demo.txt");
for(int c=fr.read();c!=-1;c=fr.read())
{
fw.write(c);
}
fr.close();
fw.close();
}
private static void copy2()
{
FileWriter fw=null;
FileReader fr=null;
try
{
fw=new FileWriter("Demo(3).txt");
fr=new FileReader("Demo.txt");
char[] arr=new char[1024];
for(int count=fr.read(arr);count!=-1;count=fr.read(arr))
{
fw.write(arr,0,count);
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
if(fw!=null)fw.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
if(fr!=null)fr.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
}
运行图:
IO流小练习:
//打印一个java文件,输出到控制台
package com.helong.filetest;
import java.io.*;
class FileTest
{
public static void main(String[] args) throws IOException
{
FileWriter fw=new FileWriter("FileText.java");
fw.write("class Demo\r\n");
fw.write("{\r\n");
fw.write("void show(){.....}");
fw.write("\r\n}");
fw.close();
FileReader fr=new FileReader(args[0]);
char[] arr=new char[1024];
for(int count=fr.read(arr);count!=-1;count=fr.read(arr))
{
System.out.print(count+":::"+new String(arr,0,count));
}
fr.close();
}
}
运行图:
/*
FileWriter的基本方法(构造函数,write,close,flush)
IOException的基本处理流程
*/
package com.helong.filewriterdemo;
import java.io.*;
class FileWriterDemo
{
public static void main(String[] args)
{
FileWriter fw=null;
try
{
fw = new FileWriter("Demo.txt");
fw.write("使用FileWriter类创建文件并写入这句话!\n\t");
fw.write(" ..........再写一句把");
}
catch (IOException e)
{
System.out.println("构造函数或者write方法:"+e.toString());
}
finally
{
try
{
if(fw!=null)
fw.close();
}
catch (IOException e)
{
System.out.println("close方法:"+e.toString());
}
}
}
}
运行图:
//文件读取方式1
package com.helong.filereaderdemo;
import java.io.*;
class FileReaderDemo
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("Demo.txt");
for(int ch=fr.read();ch!=-1;ch=fr.read())
{
System.out.print((char)ch);
}
fr.close();
}
}
运行图:
//文件读取方式2,以数组形式
package com.helong.filereaderdemo2;
import java.io.*;
class FileReaderDemo2
{
public static void main(String[] args) throws IOException
{
FileReader fr =new FileReader("Demo.txt");
char[] arr=new char[1024];//通常数组大小设置为1024的整数倍
for(int count=fr.read(arr);count!=-1;count=fr.read(arr))
{
System.out.println(count+":::"+new String(arr,0,count));
}
fr.close();
}
}
运行图:
2.字符流缓冲区对象
缓冲区对象:
装饰设计模式:
我们发现,其实BufferedWriter相对于FileWriter来说,功能基本一致,无非就是在效率,方便等方面更好了,而且在BufferedWriter方法,内部也大量的使用到了FileWriter的方法,这使得我们很疑惑,BufferedWriter在体系中与FileWriter是平行的,但是它更像是FileWriter的加强版,而不是一个独立的类,其实当我们看到BufferedWriter的构造函数时我们也会有所察觉,这个类是没有空参数构造函数的,创建该类对象,必须传递一个FileWriter对象进来,这是什么做法呢?我们不得不提一种设计模式:装饰设计模式。
当想要对已有的类进行增强时,将已有类的对象传入自定义的类中,并基于已有类方法提供增强版方法。这个新的类就是已有类的装饰类。因为当我们想增强一个类时,不建议修改其源代码,因此一般都会使用装饰类。装饰类一般通过构造函数接收被装饰的对象,基于被装饰对象的方法提供更强功能。
特点:
1.包含被装饰类的一个对象。
2.一般无空参数构造函数,那个对象也是通过构造函数传递给该类的。
3.基于对象的方法,提供增强的方法。
装饰与继承的区别:
我们来仔细分析一下:
例如此时有一个类MyReader,其有两个子类MyFileReader,MyTextReader,我们发现这两个子类的读取方法效率不高,想提高它的效率怎么办呢?改源代码是不可能的,以前我们可能会说定义新的类继承这两个子类,然后复写其中需要提高效率的方法就可以了。
这样做也不是不可以,体系如下:
MyReader:
|--MyFileReader
|--MySuperFileReader
|--MyTextReader
|--MySuperTextReader
我们发现,这样的解决方式虽然也能解决问题,但是会使得该体系过于臃肿,如果还有别的子类,那就还要再定义类,而且灵活性不强,扩展性极差,我们再来看看使用装饰设计模式来解决这个问题。
MyReader
|--MyFileReader
|--MyTextReader
|--MySuperReader
class MySuperReader extends MyReader
{
MySuperReader(MyReader r)//利用多态,可以处理所有MyReader的子类对象
{}
//基于MyReader的方法,提供对应的增强方法。
}
我们发现,这种方式的好处在于,1.扩展性强,2.代码简洁,3.灵活性强,如果有方法不想增强的可以直接使用传入对象的原方法。
缓冲区对象练习:
//使用缓冲区对象来提高FileWriter的效率
//写入99乘法表
import java.io.*;
class BufferedWriterDemo
{
public static void main(String[] args) throws IOException
{
//使用蓄水池前肯定要有个水流吧
FileWriter fr=new FileWriter("buff.txt");
BufferedWriter bw=new BufferedWriter(fr);
for(int i=1;i<=9;i++)
{
for(int j=1;j<=i;j++)
{
bw.write(j+"*"+i+"="+(i*j)+"\t");
}
bw.newLine();
bw.flush();//每次都刷新是为了防止程序突然停止后数据没有能写入硬盘中,例如写BLOG时,一般都是每隔10秒就存一次的,这是一个道理
}
bw.close();
}
}
运行图:
//使用BufferedReaderDemo对象提高读取的效率
import java.io.*;
class BufferedReaderDemo
{
public static void main(String[] args) throws IOException
{
FileReader fr=new FileReader("buff.txt");
BufferedReader br=new BufferedReader(fr);
for(String line=br.readLine();line!=null;line=br.readLine())
{
System.out.println(line);
}
br.close();
}
}
运行图:
练习装饰设计模式:
//装饰设计模式:自定义一个类,该类中包含被装饰类对象,基于该对象的方法,提供更好更强的方法
class Person
{
void eat()
{
System.out.println("吃白饭");
}
void play()
{
System.out.println("玩泥巴");
}
}
class SuperPerson
{
private Person p;
SuperPerson(Person p)
{
this.p=p;
}
void eat()
{
p.eat();
System.out.println("吃牛肉");
System.out.println("吃鸡肉");
System.out.println("吃鱼肉");
}
void play()
{
p.play();
System.out.println("玩电脑");
System.out.println("玩手机");
System.out.println("玩平板");
}
}
class DecorationDemo
{
public static void main(String[] args)
{
SuperPerson sp=new SuperPerson(new Person());
sp.eat();
sp.play();
}
}
运行图:
//使用装饰设计模式
abstract class Animal
{
abstract void eat();
abstract void sleep();
abstract void play();
abstract void work();
}
class Cat extends Animal
{
void eat()
{
System.out.println("吃鱼");
}
void sleep()
{
System.out.println("趴着睡");
}
void play()
{
System.out.println("玩毛线");
}
void work()
{
System.out.println("抓老鼠");
}
}
class Dog extends Animal
{
void eat()
{
System.out.println("吃骨头");
}
void sleep()
{
System.out.println("躺着睡");
}
void play()
{
System.out.println("玩飞盘");
}
void work()
{
System.out.println("看门");
}
}
class SuperAnimal
{
private Animal a=null;
SuperAnimal(Animal a)
{
this.a=a;
}
void eat()
{
a.eat();
System.out.println("还会自己收拾哦");
}
void sleep()
{
a.sleep();
System.out.println("而且不打呼噜哦");
}
void play()
{
a.play();
System.out.println("和主人一起玩哦");
}
void work()
{
a.work();
}
}
class DecorationDemo2
{
public static void main(String[] args)
{
SuperAnimal sa=new SuperAnimal(new Cat());
sa.eat();
sa.sleep();
sa.play();
sa.work();
sa=new SuperAnimal(new Dog());
sa.eat();
sa.sleep();
sa.play();
sa.work();
}
}
运行图:
IO异常的一种处理方式:
/*
将异常信息存放到特定的文件中
*/
import java.io.*;
import java.util.*;
import java.text.*;
class ExceptionInfoHandle
{
public static void rememberExceptionInfo(String info)throws IOException
{
Date d=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
String date=sdf.format(d);
/*//方法1*/
BufferedWriter bw=new BufferedWriter(new FileWriter("ExceptionInfo.txt",true));
bw.write(date);
bw.newLine();
bw.write(info);
bw.newLine();
bw.newLine();
bw.flush();
/*//方法2
System.setOut(new PrintStream(new FileOutputStream("ExceptionInfo.txt",true)));
System.out.println(date);
System.out.println(info);
System.out.println();*/
}
}
class ExceptionInfo
{
public static void main(String[] args) throws IOException
{
try
{
int a=12/0;
}
catch (Exception e)
{
ExceptionInfoHandle.rememberExceptionInfo(e.toString());
}
try
{
int[] arr=new int[2];
System.out.println(arr[3]);
}
catch (Exception e)
{
ExceptionInfoHandle.rememberExceptionInfo(e.toString());
}
}
}
运行图:
手写实现BufferedReader的readLine和close方法:
//自己实现BufferedReader的readLine和close功能
//思路:其实BufferedReader内部的readLine方法也是在调用FileReader的read读取一个字符的方法
import java.io.*;
class MyBufferedReader
{
private FileReader fr=null;
MyBufferedReader(FileReader fr)
{
this.fr=fr;
}
public String myReadLine()throws IOException
{
//定义一个临时存储数据的容器
//BufferedReader中使用数组,我们此处使用StringBuilder
StringBuilder sb=new StringBuilder();
for(int ch=fr.read(),temp;ch!=-1;ch=fr.read())
{
//如果文件中有单独的\r或者\n,那么将被跳过
//if(ch=='\r')continue;
//if(ch=='\n')return sb.toString();//'\n'表示读到了一行的结尾处,因此返回字符串
if(ch=='\r')
{
if((temp=fr.read())=='\n')//连续的'\t''\n'表示这是个换行符
return sb.toString();
else//单独的'\t',不是换行符的一部分,也应该存入容器中
{
sb.append(ch);
sb.append(temp);
}
}
else
sb.append((char)ch);
}
if(sb.length()!=0)return sb.toString();
return null;
}
public void myClose()throws IOException
{
fr.close();
}
}
class MyBufferedReaderDemo
{
public static void main(String[] args) throws IOException
{
FileReader fr=new FileReader("buff.txt");
MyBufferedReader mbr=new MyBufferedReader(fr);
for(String line=mbr.myReadLine();line!=null;line=mbr.myReadLine())
{
System.out.println(line);
}
}
}
运行图:
3.字节流
|--FileInputStream
|--BufferedInputStream
OutputStream:写
|--FileOutputStream
|--BufferedOutputStream
常用子类:
两个方法的特点:
转换流:
转换流特有功能:转换流可以将字节转成字符,原因在于,将获取到的字节通过查编码表获取到指定对应字符。
键盘录入(最简写法):
键盘录入练习:
//键盘录入
import java.io.*;
class ReadIn
{
public static void main(String[] args) throws IOException
{
InputStream in=System.in;
while(true)
{
StringBuffer sb=new StringBuffer();
for(int ch=in.read();ch!='\r'&&ch!='\n';ch=in.read())
{
sb.append((char)ch);
}
in.read();
if(sb.toString().equals("over"))
break;
else
System.out.println(sb.toString().toUpperCase());
}
}
}
运行图:
控制台输出:
字节流练习:
//测试FileOutputStream和FileInputStream使用
import java.io.*;
class FileStream
{
public static void main(String[] args) throws IOException
{
input_3();
}
private static void input_1()throws IOException
{
FileInputStream fis=new FileInputStream("FileStream.txt");
for(int ch=fis.read();ch!=-1;ch=fis.read())//一个字节一个字节的读数据
{
System.out.print((char)ch);
}
fis.close();
}
private static void input_2()throws IOException
{
FileInputStream fis=new FileInputStream("FileStream.txt");
byte[] buf=new byte[1024];
for(int len=fis.read(buf);len!=-1;len=fis.read(buf))//一次性读多个字节,然后一起操作
{
System.out.println(new String(buf,0,len));
}
fis.close();
}
private static void input_3()throws IOException
{
FileInputStream fis=new FileInputStream("FileStream.txt");
byte[] buf=new byte[fis.available()];
fis.read(buf);
System.out.println(new String(buf));
fis.close();
}
private static void output_1()throws IOException
{
FileOutputStream fos=new FileOutputStream("FileStream.txt");
fos.write("helong is so handsome!\r\nmuhhhhh".getBytes());
fos.close();//即便没有刷新,也会将数据写入目的地,这是因为字节流操作的是字节这种最小单元,因此不需要有中间处理,直接就存到了目的地。
}
}
运行图:
//转换流练习
import java.io.*;
class TranslateStream
{
public static void main(String[] args) throws IOException
{
//数据源
//BufferedReader br=new BufferedReader(new InputStreamReader(System.in/*数据源是标准输入,也就是键盘*/));
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("trans.txt")/*数据源是标准输入,也就是键盘*/));
//目的地
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out/*目的地是控制台*/));
//BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("trans.txt")/*目的地一个文件夹*/));
for(String line=br.readLine();line!=null;line=br.readLine())
{
if(line.equals("over"))break;
bw.write(line.toUpperCase());
bw.newLine();
bw.flush();
}
br.close();
bw.close();
}
}
运行图:
复制图片:
//复制一张图片
/*
思路:
1.以字节形式读取该图片FileInputStream
2.创建一个对应格式的图片文件到目的地FileOutputStream
3.循环读写
4.关闭资源
*/
import java.io.*;
class CopyPic
{
public static void main(String[] args)
{
FileInputStream fis=null;
FileOutputStream fos=null;
try
{
fis=new FileInputStream("使用缓冲区对象读取数据.png");
fos=new FileOutputStream("使用缓冲区对象读取数据(2).png");
byte[] buf=new byte[1024];
for(int len=fis.read(buf);len!=-1;len=fis.read(buf))
{
fos.write(buf,0,len);
}
}
catch (IOException e)
{
throw new RuntimeException("复制图片失败");
}
finally
{
try
{
if(fis!=null)fis.close();
}
catch (IOException e)
{
throw new RuntimeException("读取流关闭失败");
}
try
{
if(fos!=null)fos.close();
}
catch (IOException e)
{
throw new RuntimeException("写入流关闭失败");
}
}
}
}
运行图:
4.流操作基本流程
2.找到目的流对象,进行包装----OutputStream,Writer
3.操作的数据是否为纯文本----决定使用字符流还是字节流
4.通过设备确定使用的具体对象(源设备:内存,硬盘,键盘。目的设备:内存,硬盘,控制台)
5.是否需要提高效率,是就使用包装类
//将文本文件打印到控制台上,使用三个明确的流程
import java.io.*;
class TranslateStreamTest
{
public static void main(String[] args) throws IOException
{
/*
明确源:
1.源:文本文件
2.纯文本:Reader
3.设备:硬盘--FileReader
*/
BufferedReader br=new BufferedReader(new FileReader("根据步骤分析流操作.txt"));
/*
明确目的:
1.目的:控制台
2.纯文本:Writer,字符流对象
3.设备:控制台,System.out字节流对象(需要转换,将字节流对象转为字符流对象,需要转换流)
*/
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));
for(String line=br.readLine();line!=null;line=br.readLine())
{
bw.write(line);
bw.newLine();
}
bw.close();
br.close();
}
}
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------