---------------------- android培训、java培训、期待与您交流! ----------------------
一 .io概览
java语言的i/o库提供了四大等级结构:InputStream,OutputStream,Reader,Writer四个系列的类。InputStream和OutputStream处理8位字节流数据, Reader和Writer处理16位的字符流数据。InputStream和Reader处理输入, OutputStream和Writer处理输出。大家一定要到J2SE文档中看看这四大等级结构的类继承体系。
除了这四大系列类,i/o库还提供了少数的辅助类,其中比较重要的是InputStreamReader和OutputStreamWriter。InputStreamReader把InputStream适配为Reader, OutputStreamWriter把OutputStream适配为Writer;这样就架起了字节流处理类和字符流处理类间的桥梁。
例如:一个应用字符写入流的小程序
/*
需求:练习使用字符写入流的使用
*/
import java.io.*;
class FileWriteDemo
{
public static void main(String[] args) throws IOException
{
FileWriter fi=new FileWriter("abc.txt"); //定义一个字符写入流对象
BufferedWriter bu=new BufferedWriter(fi); //把字符流写入对象作为参数传递给缓冲区
for (int x=0;x<8 ;x++ )
{
bu.write("abcde"+x); //利用for循环重复向缓冲区写入
bu.newLine(); //换行
bu.flush(); //每执行一次循环刷新一下
}
bu.close(); //相当于执行关闭字符流对象
System.out.println("Hello World!");
}
}
二.IO流(BufferedReader)
很明显Bufferedreader的用法比inputstream要复杂,复杂的存在必然会导致优势的存在!我们都知道Inputstream是一个字节一个字节的读取,每次读取都会执行一次IO,我们知道io的操作是很费时间的,这就必然会导致程序的效率,而Bufferedreader很好的解决这一问题,它可以一次读取大量的数据,大大减少了io次数,效率也就上去了,这就像有辆能乘坐一百人的大巴,从热力输送学生到理工本部,司机脑残,学生没睡醒,非要一次只坐一个同学,大巴的来回跑一百趟才能把这一百人全部送到学校,这就类似Inputstream,另一个司机是清华毕业,智商当然高了,他让这一百人全部上车,一次九ok了,虽然在学生上车时多用了点时间,但总时间要远比那个脑残司机要少的多。
示例1:
/*
需求:模拟BufferedReader的读取一行readLine功能
思路:可以利用StringBuilder来完成,文本数据实际上是一系列的字符所构成,换行符“\r”,回车符"\n"是其中两个较为
特殊的符号,可以利用字符读取流的read方法对文本读取,当读到"\r"令其继续,读到”\n“则表明一行数据已经读完,可以
返回打印,读到普通字符则令其存入StringBuilder.
*/
import java.io.*;
class BufReader
{
FileReader fi=null;
BufReader(FileReader f)
{
this.fi=f;
}
public String myReadLine() throws IOException
{
StringBuilder bu=new StringBuilder();//定义一个容器用来装入临时一行的数据
int ch=0;
while ((ch=fi.read())!=-1)
{
if (ch=='\r')// \r代表将输入点移到行首
{
continue;
}
else if (ch=='\n')// \n转义字符是移到下一行
{
return bu.toString();
}
else
bu.append((char)ch);
}
if(bu.length()!=0)//防止最后没有回车的一行被漏读
return bu.toString();
return null;
}
public void myClose() throws IOException
{
fi.close();
}
}
class FileReaderDemo3
{
public static void main(String[] args) throws IOException
{
FileReader fi=new FileReader("write.txt");
BufReader buR=new BufReader(fi);
String line=null;
while ((line=buR.myReadLine())!=null)
{
System.out.println(line);
}
buR.myClose();
System.out.println("Hello World!");
}
}
示例2:利用BufferedReader,BufferedWriter复制一个文本文件
/*
需求:利用写入流和输出流完成一个文件内容的复制
*/
import java.io.*;
class FileReaderDemo2
{
public static void main(String[] args)
{
BufferedReader fi=null;//将引用与对象的初始化分开写,有利于程序的健壮性
BufferedWriter ri=null;
try
{
fi=new BufferedReader(new FileReader("FileReaderDemo.java"));
ri=new BufferedWriter(new FileWriter("write.txt"));
String line=null;
while ((line=fi.readLine())!=null)
{
ri.write(line);
ri.newLine();
ri.flush();
}
}
catch (IOException e)
{
throw new RuntimeException("读写失败");
}
finally
{
try
{
if (fi!=null)//防止fi初始化失败却被关闭
{
fi.close();
}
}
catch (IOException e)
{
throw new RuntimeException("关闭读取流异常");
}
try
{
if (ri!=null)
{
ri.close();
}
}
catch (IOException e)
{
throw new RuntimeException("关闭写入流异常");
}
}
System.out.println("Hello World!");
}
}
三.装饰设计模式
装饰设计模式:当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。那么自定义的该类称为装饰类,装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
(1) 装饰者和被装饰者必须具有相同的超类型。
(2) 装饰者即可以包装被装饰者,也可以包装装饰者。往往利用多层包装来达到目的。
(3) 装饰者中组合了被装饰者对象 ( 装饰类的关键特征 ) 。使得我们能够通过嵌套装饰来动态扩展行为。
装饰与继承:
(1) 类的继承是高耦合,会产生更多的子类,从而引起类的爆炸 )
(2) 对象组合即装饰模式能够降耦,不会创造更多的子类,动态的为对象添加功能, 所以类应该对扩展开放,对修改关闭 ,装饰模式比继承要灵活。避免了继承体系臃肿。
示例代码:自定义装饰类的例子
/*
需求:模拟类MyLineNumberReader,并要求该类包含方法设置行号mySetNum和获取行号myGetNum两个方法
思路:采用装饰类的思想解决此问题,用一个变量lineNum记录读取'\r'的次数,此次数即为行号,而设置行号的方法对lineNum进行初始化动作。
步骤:定义类MyLineNumberReader,成员变量lineNum,用构造函数传入FileReader对象。
在此类定义myReaderLine方法,以便实现对实际字符流对象整行的读入,用lineNum记录行号信息;
用MySetNum方法实现对lineNum的初始化,用myGetNum方法实现获取最终的Numline
*/
import java.io.*;
class MyLineNumberReader
{
private FileReader fi=null;
private int lineNum=0;
MyLineNumberReader(FileReader f)
{
this.fi=f;
}
public void mySetNum(int i)
{
this.lineNum=i;
}
public int myGetNum()
{
return this.lineNum;
}
public void myClose() throws IOException
{
fi.close();
}
public String myReaderLine() throws IOException
{
StringBuilder bu=new StringBuilder();
int ch=0;
while ((ch=fi.read())!=-1)
{
if (ch=='\r')
{
lineNum++;
continue;
}
else if (ch=='\n')
{
return bu.toString();
}
else
bu.append((char)ch);
}
if(bu.length()!=0)
return bu.toString();
return null;
}
}
class FileReaderDemo4
{
public static void main(String[] args) throws IOException
{
FileReader fi=new FileReader("write.txt");
MyLineNumberReader myl=new MyLineNumberReader(fi);
String line=null;
//myl.mySetNum(100);
while ((line=myl.myReaderLine())!=null)
{
System.out.println(myl.myGetNum()+":"+line);
}
myl.myClose();
System.out.println("Hello World!");
}
}
四.IO流(字节流File读写操作)
字节流:操作数组是字节数组,而字符流则是对字符数组进行操作,字符流的底层实际上也是字节流,但字符有编码,所以字符流需要有编码解码过程,也需要刷新,而字节流无须任何转换,是不需要刷新的。
实例:
/*
需求:用字节流实现对一个图片文件的复制
思路:1,用字节读取流对象和图片关联。
2,用字节写入流对象创建一个图片文件。用于存储获取到的图片数据。
3,通过循环读写,完成数据的存储。
4,关闭资源。
*/
import java.io.*;
class CopypicDemo
{
public static void main(String[] args)
{
FileInputStream fis=null;
FileOutputStream fos=null;
try
{
fis=new FileInputStream("test.jpg");//定义读取的源文件
fos=new FileOutputStream("shuchu.jpg");
int num=0; //用以判断输入流是否为空
byte[] bt=new byte[1024]; //定义一个字节数组用以装临时数据
while ((num=fis.read(bt))!=-1) //fis为-1说明已经读完源文件
{
fos.write(bt,0,num);//向目标文件写入数据
}
}
catch (IOException e)
{
throw new RuntimeException("读取失败");
}
finally
{
try
{
if (fis!=null)//防止fis初始化失败却被关闭
{
fis.close();
}
}
catch (IOException e)
{
throw new RuntimeException("读取关闭失败");
}
try
{
if (fos!=null)
{
fos.close();
}
}
catch (IOException e)
{
throw new RuntimeException("写入关闭失败");
}
}
System.out.println("Hello World!");
}
}
五.IO流-转换流
通过刚才的键盘录入一行数据并打印其大写,发现其实就是读一行数据的原理。
也就是readLine方法。能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?
readLine方法是字符流BufferedReader类中的方法。而键盘录入的read方法是字节流InputStream的方法。那么能不能将字节流转成字符流在使用字符流缓冲去的readLine方法呢?
Java为我们提供了转换流实现此类需求
实例:import java.io.*;
class TransStreamDemo
{
public static void main(String[] args) throws IOException
{
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));//实现字节流向字符流的转换,就可以利用BufferedReader的读取一行的方法,提高效率
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))//当输入over时结束整个程序
break;
bufw.write(line.toUpperCase());//变大写
bufw.newLine();
bufw.flush();
}
bufr.close();
}
}
六.流操作规律
流操作的基本规律:在实际应用过程中,最痛苦的就是流对象有很多,不知道该用哪一个,可以根据下面的方法进行分析明确:
1,明确源和目的。
源:输入流。InputStream Reader
目的:输出流。OutputStream Writer。
2,操作的数据是否是纯文本。
是:字符流。
不是:字节流。
3,当体系明确后,在明确要使用哪个具体的对象。
通过设备来进行区分:
源设备:内存,硬盘。键盘
目的设备:内存,硬盘,控制台。
例如:将一个文本文件中数据存储到另一个文件中。复制文件,可以采用以下步骤进行分析:
源:因为是源,所以使用读取流,在InputStream Reader 中选择一个,再看是不是操作文本文件,是!这时就可以选择Reader这样体系就明确了,接下来明确要使用该体系中的哪个对象。明确读取的设备是硬盘,Reader体系中可以操作文件的对象是 FileReader,最后看是否需要提高效率:是!。加入Reader体系中缓冲区 BufferedReader.。
FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);
再看目的,是硬盘上另一个文件,所以可以选择OutputStream或者 Writer,是否是纯文本,是!那么选择Writer。Writer体系中可以操作文件的对象FileWriter。再看是否需要提高效率:是!加入Writer体系中缓冲区 BufferedWriter。
FileWriter fw = new FileWriter("b.txt");
BufferedWriter bufw = new BufferedWriter(fw);
再例如:将键盘录入的数据保存到一个文件中。这个需求中有源和目的都存在。那么分别分析如下:
源:InputStream Reader
是不是纯文本?是!Reader
设备:键盘。对应的对象是System.in.
不是选择Reader吗?System.in对应的不是字节流吗?
为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。
所以既然明确了Reader,那么就将System.in转换成Reader。
用了Reader体系中转换流,InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
需要提高效率吗?需要!BufferedReader
BufferedReader bufr = new BufferedReader(isr);
目的:OutputStream Writer
是否是存文本?是!Writer。
设备:硬盘。一个文件。使用 FileWriter。
FileWriter fw = new FileWriter("c.txt");
需要提高效率吗?需要。
BufferedWriter bufw = new BufferedWriter(fw);
实例代码:将一个文本数据打印在控制台上。要按照以上格式自己完成三个明确。
class TransStreamDemo2
{
public static void main(String[] args) throws IOException
{
System.setIn(new FileInputStream("PersonDemo.java"));//设置输入流
System.setOut(new PrintStream("zzz.txt"));//设置输出流
//键盘的最常见写法。
BufferedReader bufr =
new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();
}
}
七.File对象
File类:直接用于对文件的各种操作,常见方法如下:
1,创建。
boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false。和输出流不一样,输出流对象一建立创建文件。而且文件已经存在,会覆盖。
boolean mkdir():创建文件夹。
boolean mkdirs():创建多级文件夹。
2,删除。
boolean delete():删除失败返回false。如果文件正在被使用,则删除不了返回falsel。
void deleteOnExit();在程序退出时删除指定文件。
3,判断。
boolean exists() :文件是否存在.
isFile():
isDirectory();
isHidden();
isAbsolute();
4,获取信息。
getName()
getPath()
getParent()
getAbsolutePath()
long lastModified()
long length()
实例:用File类实现显示某个目录下的文件列表
/*
需求:1.用File对象将指定目录“f:\\”下的各个文件以及子目录获取出来,并将路径打印在控制台
2.用File对象的list方法将“D:\\安装文件”下的rar文件找出来,并获得抽象路径名列表,打印到控制台
思路:1.用File对象的list方法可以返回指定目录下的文件及子目录信息,可以用file数组先存入这些数据,再遍历打印
2.list的过滤器FilenameFilter有两个参数,File对象,要找的文件名String name,可以自己定义匿名内部类,覆盖accept方法
*/
import java.io.*;
class FileDemo2
{
public static void getInfo(String str)
{
File c=new File(str); //通过传递路径字符串获取一个File对象
String[] fi=c.list(); //list方法返回一个String类型的数组
for (String f:fi)
{
System.out.println(f); //将所有的文件或子目录抽象路径打印出来
}
}
public static void searchf()
{
File dir=new File("D:\\安装文件");
String[] str=dir.list(new FilenameFilter()//用过滤器过滤出需要的文件名
{
public boolean accept(File f,String name)
{
System.out.println(f.getName());
return name.endsWith("rar");
}
});
for (String s:str )
{
System.out.println(s);
}
}
public static void searchf2()
{
File dir=new File("D:\\安装文件");
File[] str=dir.listFiles(new FileFilter()
{
public boolean accept(File c)
{
System.out.println(c.getName());
return c.getName().contains("360");
}
}
);
for (File c:str)
{
System.out.println(c.getName()+"......"+c.length());
}
}
public static void searchf3() //listFiles,返回的是文件以及目录的对象,可以进一步利用文件对象的各种方法来进一步操作
{
File dir=new File("D:\\安装文件");
File[] str=dir.listFiles(new FilenameFilter()
{
public boolean accept(File c,String name)
{
System.out.println(c.getName());
return name.contains("360");
}
}
);
for (File c:str)
{
System.out.println(c.getName()+"......"+c.length());
}
}
public static void main(String[] args)
{
//getInfo("F:\\java\\javastudy\\day15");
//searchf2();
searchf3();
System.out.println("Hello World!");
}
}
八.其他流对象
打印流:该流提供了打印方法,可以将各种数据类型的数据都原样打印。
字节打印流:PrintStream
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
字符打印流:PrintWriter
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
4,字符输出流,Writer。
合并流:用于合并多个流对象
实例:练习合并流的使用
/*
需求:练习合并流的使用
思路:SequenceInputStream的构造方法可以实现将枚举中的流对象合并
步骤:新建一个vector对象,此对象可以把多个读取流装起来,并通过elements方法返回到Enumeration即枚举
*/
import java.io.*;
import java.util.*;
class SequenDemo
{
public static void main(String[] args) throws IOException
{
Vector ve=new Vector(); //创建一个vector容器用于装读取流对象
ve.add(new FileInputStream("public.txt"));
ve.add(new FileInputStream("public2.txt"));
ve.add(new FileInputStream("public3.txt"));
Enumeration enu=ve.elements(); //枚举ve的元素
SequenceInputStream seq=new SequenceInputStream(enu); //创建合并流
byte[] by=new byte[1024];
int len=0;
while ((len=seq.read(by))!=-1)
{
String s=new String(by);
System.out.println(s);
}
System.out.println("Hello World!");
}
}
切割流:用于把一个流分割成多个流
实例:用分割流的方法读取文件,并用合并流进行合并
/*
需求:用分割流的方法把一个文件分成2m的小块
思路:用一个读取流,多个写入流
步骤:写出通常的读取写入程式,在遍历写入时加入创建新的写入流语句即可
需求2:用合并流的方法把分割的文件再合并起来
思路2:因为合并流,故要用到sequenceInputstream
步骤2:用一个For循环同时新建多个读取流对象,把读取流对象装入枚举中,再用合并流合并输出
*/
import java.io.*;
import java.util.*;
class SequenDemo2
{
public static void splitrar() throws IOException
{
FileInputStream fis=new FileInputStream("yuan.rar");
FileOutputStream fos=null;
int len=0; //用于判断读取是否结束
int count=1; //用于对分割文件进行命名
byte[] by=new byte[1024*1024*2];
while ((len=fis.read(by))!=-1)
{
fos=new FileOutputStream("yuan"+count+++".part");
fos.write(by);
fos.flush();
}
fos.close();
fis.close();
}
public static void merge() throws IOException
{
FileInputStream fis=null;
ArrayList<FileInputStream> ar=new ArrayList<FileInputStream> ();
for (int x=1; x<20; x++)
{
fis=new FileInputStream("yuan"+x+".part");
ar.add(fis); //依次把多个读取流对象装入集合中
}
final Iterator<FileInputStream> it=ar.iterator(); //使用迭代器取出元素,从内部类访问变量要加final
Enumeration<FileInputStream> enu=new Enumeration<FileInputStream>() //覆盖枚举的两个方法返回迭代器中的元素
{
public boolean hasMoreElements()
{
return it.hasNext();
}
public FileInputStream nextElement()
{
return it.next();
}
};
SequenceInputStream seq=new SequenceInputStream(enu);//再合并流
FileOutputStream fos=new FileOutputStream("ji.rar");
int len=0;
byte[] by=new byte[1024];
while ((len=seq.read(by))!=-1)
{
fos.write(by);
fos.flush();
}
fos.close();
seq.close();
fis.close();
}
public static void main(String[] args) throws IOException
{
//splitrar();
merge();
System.out.println("Hello World!");
}
}
---------------------- android培训、java培训、期待与您交流! ----------------------