Java输入、输入、IO流类层次关系梳理
目录
1.Java中IO简介
2.Java中的流
3.Java中和IO相关的类库层次结构
1.Java中IO简介
IO(InputAndOutput)在编程中是一个很常见的需求,IO即意味着我们的java程序需要和"外部"进行通信,这个"外部"可以是很多介质
1)本地磁盘文件、远程磁盘文件
2)数据库连接
3)TCP、UDP、HTTP网络通信
4)进程间通信
5)硬件设备(键盘、串口等)
...
2.Java中的流
IO是我们的目的,而要达到这一目的,我们需要一种机制来帮助我们完全,这种机制就是"流"、或者叫"数据流"。
数据流是一串连续不断的数据的集合,就象水管里的水流,在水管的一端一点一点地供水,而在水管的另一端看到的是一股连续不断的水流。数据写入程序可以是一段、一段地向数据流管道中写入数据,这些数据段会按先后顺序形成一个长的数据流。对数据读取程序来说,看不到数据流在写入时的分段情况,每次可以读取其中的任意长度的数据,但只能先读取前面的数据后,再读取后面的数据。不管写入时是将数据分多次写入,还是作为一个整体一次写入,读取时的效果都是完全一样的。
Java的IO模型设计非常优秀,它使用Decorator模式,按功能划分Stream
记住这句话对我们在编程中选择合适的类库很重要,Java中按照功能提供不同类别的流,我们接下来深入学习一下java中的各个流、以及它们的层次结构关系
3.Java中和IO相关的类库层次结构
首先,java中所有的对象(包括)流对象都从Object超类继承而来,所以,所有的流类的父类都是Object类
以下的缩进关闭表示的的类的继承关系
复制代码
Object(超类)
1.基于"字节"操作的I/O接口:
1)InputStream
InputStream类是一个abstractclass(抽象父类),它不能被直接用于实例化进行流操作,我们在编程中使用的是它的子类
1.1)ByteArrayInputStream:从字节数组(byte[])中进行以字节为单位的读取
1.2)FileInputStream:从文件中进行以字节为单位的读取
1.2.1)SocketInputStream
org.apache.commons.net.io.SocketInputStream:封装了对Socket的字节型流式读取
1.3)FilterInputStream:用来"封装其它的输入流,并为它们提供额外的功能"
1.3.1)InflaterInputStream
java.util.zip.InflaterInputStream:从压缩数据源(zip)中以字节为单位读取数据
1.3.1.1)ZipInputStream
java.util.zip.ZipInputStream:从zip文件中以字节为单位读取数据
1.3.2)BufferedInputStream:开辟"内部字节数组"对输入流进行缓存,函数的返回也是一个字节数组
1.3.3)DataInputStream:
DataInputStream是用来装饰其它输入流,它"允许应用程序以与机器无关方式从底层输入流中读取基本Java数据类型"。应用程序可以使用DataOutputStream(数据输出流)
写入由DataInputStream(数据输入流)读取的数据。
1.4)ObjectInputStream:从输入流中读取序列化后的数据,并进行反序列化(deserializes)
1.5)PipedInputStream:从管道中读取数据
2)OutputStream
OutputStream类是一个abstractclass(抽象父类),它不能被直接用于实例化进行流操作,我们在编程中使用的是它的子类
2.1)ByteArrayOutputStream:以字节为单位将数据写入到从字节数组(byte[])中
2.2)FileOutputStream:以字节为单位将数据写入到文件中
2.2.1)SocketOutputStream
org.apache.commons.net.io.SocketOutputStream:封装了对Socket的字节型流式写入
2.3)FilterOutputStream:用来"封装其它的输出流,并为它们提供额外的功能"
2.3.1)ZipOutputStream:java.util.zip.ZipOutputStream:以字节为单位向zip文件写入数据
2.3.2)PrintStream:
PrintStream是用来装饰其它输出流。它能为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式
2.3.3)DataOutputStream:
DataOutputStream是用来装饰其它输入流,它"允许应用程序以与机器无关方式向底层输出流中写入基本Java数据类型"。应用程序可以使用DataInputStream(数据输入流)
写入由DataOutputStream(数据输出流)写入的数据()。有点类似管道、或者进程间通信的感觉
2.3.4)BufferedInputStream:
2.4)ObjectOutputStream:对数据进行序列化(serializes),并向输出流中写入序列化后的数据
2.5)PipedOutputStream:向管道中写入数据
2.基于"字符"操作的I/O接口
不管是磁盘还是网络传输,最小的存储单元都是字节,而不是字符,所以I/O操作的都是字节而不是字符,为了操作方便,java封装了一个直接写字符的I/O接口,这里就涉及到java的流机制
中的一个很重要的概念,包装(装饰)。即所有的流操作在底层实现都是字节流的形式,以这个底层字节流为基础,在其上封装了各种"附加功能"(缓存、字符、管道..)
1)Reader
Reader类是一个abstractclass(抽象父类),它不能被直接用于实例化进行流操作,我们在编程中使用的是它的子类
1.1)InputStreamReader:
我们知道,字符型的流接口是在字节型的流接口基础之上进行了一次封装,提供了一些额外的功能。所以,从名字上也可以看出来,InputStreamReader是字节流通向字符流的桥梁,
封裝了InputStream在里头,它以较高级的方式,一次读取一个一个字符,以文本格式输入/输出,可以指定编码格式。
1.1.1)FileReader:提供对文本文件(保存字符的文件)进行以字符为单位的读取
1.2)BufferedReader:
BufferedReader会一次性从物理流中读取8k(默认数值,可以设置)字节内容到内存,如果外界有请求,就会到这里存取,如果内存里没有才到物理流里再去读。即使读,也是再8k
而直接读物理流,是按字节来读。对物理流的每次读取,都有IO操作。IO操作是最耗费时间的。BufferedReader就是减少了大量IO操作,节省了时间
1.3)CharArrayReader:
CharArrayReader是字符数组输入流。它和ByteArrayInputStream类似,只不过ByteArrayInputStream是字节数组输入流,而CharArray是字符数组输入流。
CharArrayReader是用于读取字符数组,它继承于Reader。操作的数据是以字符为单位
1.4)FilterReader:用来"封装其它的字符输入流,并为它们提供额外的功能"
1.5)PipedReader:PipedReader是字符管道输入流,它继承于Reader。
1.6)StringReader:以String作为数据源,进行以字符为单位的读取
2)Writer
Writer类是一个abstractclass(抽象父类),它不能被直接用于实例化进行流操作,我们在编程中使用的是它的子类
2.1)OutputStreamWriter:
2.1.1)FileWriter:提供对文本文件(保存字符的文件)进行以字符为单位的写入
2.2)BufferedWriter
2.3)StringWriter
2.4)PipedWriter
2.5)PrintWriter
2.6)CharArrayWriter
3.基于"磁盘"操作的I/O接口:
1)File:(文件特征与管理):用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等,它不负责数据的输入输出,而专门用来管理磁盘文件与目录
1)publicbooleanexists()判断文件或目录是否存在
2)publicbooleanisFile()判断是文件还是目录
3)publicbooleanisDirectory()判断是文件还是目录
4)publicStringgetName()返回文件名或目录名
5)publicStringgetPath()返回文件或目录的路径。
6)publiclonglength()获取文件的长度
7)publicString[]list()将目录中所有文件名保存在字符串数组中返回
8)publicbooleanrenameTo(FilenewFile);重命名文件
9)publicvoiddelete();删除文件
10)publicbooleanmkdir();创建目录
4.基于网络操作的I/O接口:
1)Socket
复制代码
以上是按照Java官方API文档列出的总的目录,我们接下来逐一学习一下它们的应用场景,因为输入、输出流在编程上具有对称性,所以我们把它们合并在一起学习
0x1:InputStream:字节输入流
ByteArrayInputStream、ByteArrayOutputStream
ByteArrayOutputStream类是在创建它的实例时,程序内部创建一个byte型数组的缓冲区,然后利用ByteArrayOutputStream和ByteArrayInputStream的实例向数组中写入或读出byte型数据。在网络传输中我们往往要传输很多变量,我们可以利用ByteArrayOutputStream把所有的变量收集到一起,然后一次性把数据发送出去
复制代码
importjava.io.;
publicclasscircle
{
publicstaticvoidmain(String[]args)throwsException
{
inta=0;
intb=1;
intc=2;
/
ByteArrayOutputStream()
Createsanewbytearrayoutputstream.
/
ByteArrayOutputStreambout=newByteArrayOutputStream();
/
write(intb)
Writesthespecifiedbytetothisbytearrayoutputstream.
/
bout.write(a);
bout.write(b);
bout.write(c);
/
toByteArray()
Createsanewlyallocatedbytearray.
返回内部保存的临时byte缓存数组
/
byte[]buff=bout.toByteArray();
for(inti=0;i {
System.out.println(buff[i]);
}
System.out.println("");
/
ByteArrayInputStream(byte[]buf)
CreatesaByteArrayInputStreamsothatitusesbufasitsbufferarray.
/
ByteArrayInputStreambin=newByteArrayInputStream(buff);
/
read()
Readsthenextbyteofdatafromthisinputstream.
/
while((b=bin.read())!=-1)
{
System.out.println(b);
}
}
}
复制代码
FileInputStream、FileOutputStream
复制代码
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.FileOutputStream;
publicclasscircle
{
publicstaticvoidmain(String[]args)throwsException
{
Filef=newFile("C:\1.txt");
//向文件里写如"Hello"字符串.
try
{
//要写入的数据转换成字节数组
byte[]buf="Hello".getBytes();
/
FileOutputStream(Filefile)
CreatesafileoutputstreamtowritetothefilerepresentedbythespecifiedFileobject.
如果1.txt存在,则删除1.txt里面的内容,文本所有内容变为Hello
如果1.txt不存在,在新建1.txt文本,写入Hello
/
FileOutputStreamout=newFileOutputStream(f);
/
write(byte[]b)
Writesb.lengthbytesfromthespecifiedbytearraytothisfileoutputstream.
/
out.write(buf);
out.close();
}
catch(Exceptione)
{
System.out.println(e);
}
//读取文件中的内容
try
{
/
FileInputStream(Filefile)
CreatesaFileInputStreambyopeningaconnectiontoanactualfile,thefilenamedbytheFileobjectfileinthefilesystem.
/
FileInputStreamin=newFileInputStream(f);
byte[]buf=newbyte[1024];
/
read(byte[]b)
Readsuptob.lengthbytesofdatafromthisinputstreamintoanarrayofbytes.
从流中读取内容
/
intlen=in.read(buf);
Stringstr=newString(buf,0,len);
//打印f文件的内容.
System.out.println(str);
}
catch(Exceptione)
{
System.out.println(e);
}
}
}
复制代码
ZipInputStream、ZipOutputStream(包装流)
复制代码
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.InputStream;
importjava.util.zip.ZipEntry;
importjava.util.zip.ZipInputStream;
importjava.util.zip.ZipOutputStream;
importjava.io.FileOutputStream;
publicclasscircle
{
publicstaticvoidmain(String[]args)throwsException
{
//定义要压缩的文件
Filefile=newFile("C:"+File.separator+"in.txt");
//定义压缩文件名称
FilezipFile=newFile("C:"+File.separator+"in.zip");
/
FileInputStream(Filefile)
CreatesaFileInputStreambyopeningaconnectiontoanactualfile,thefilenamedbytheFileobjectfileinthefilesystem.
定义文件的输入流
/
InputStreaminput=newFileInputStream(file);
//声明压缩流对象
ZipOutputStreamzipOut=null;
/
ZipOutputStream(OutputStreamout)
CreatesanewZIPoutputstream.
再次体现了Java的流函数架构中的"装饰器设计模式"的强大之处,我们可以根据我们对功能的
需要任意组合、加载我们需要的流,用通俗的话来说,把它们层层包裹在一起
/
zipOut=newZipOutputStream(newFileOutputStream(zipFile));
/
putNextEntry(ZipEntrye)
BeginswritinganewZIPfileentryandpositionsthestreamtothestartoftheentrydata.
设置ZipEntry对象
/
zipOut.putNextEntry(newZipEntry(file.getName()));
inttemp=0;
/
read()
Readsabyteofdatafromthisinputstream.
从文件流中读取内容
/
while((temp=input.read())!=-1)
{
//压缩输出
zipOut.write(temp);
}
//关闭输入流
input.close();
//关闭输出流
zipOut.close();
//readzipfileasinputstream
InputStreamis=newFileInputStream("C:"+File.separator+"in.zip");
//zipisreadbyZipInputStream
ZipInputStreamzis=newZipInputStream(is);
//nowwritezipfileinextractedfile
ZipEntryze;
byte[]buff=newbyte[1024];
/
getNextEntry()
ReadsthenextZIPfileentryandpositionsthestreamatthebeginningoftheentrydata.
/
while((ze=zis.getNextEntry())!=null)
{
//getfilename
FileOutputStreamfos=newFileOutputStream("C:"+File.separator+"out.txt");
intl=0;
//writebuffertofile
while((l=zis.read(buff))>0)
{
fos.write(buff,0,l);
}
}
zis.close();
}
}
复制代码
BufferedInputStream、BufferedInputStream(包装流)
复制代码
importjava.io.;
publicclasscircle
{
publicstaticvoidmain(String[]args)throwsException
{
Filefilein=newFile("C:/1.png");
Filefileout=newFile("C:/out.png");
try
{
//前面说过,File类它不负责数据的输入输出,而专门用来管理磁盘文件与目录
if(fileout.exists()==false)
{
fileout.createNewFile();
}
//要使用文件流,自然要使用文件读取流函数
FileInputStreamin=newFileInputStream(filein);
FileOutputStreamout=newFileOutputStream(fileout);
byte[]b=newbyte[1];
//在文件流外面包一层缓冲流读取函数
BufferedInputStreambin=newBufferedInputStream(in);
BufferedOutputStreambout=newBufferedOutputStream(out);
//缓存读取、缓存写入
while(bin.read(b)!=-1)
{
bout.write(b);
}
bout.close();
bin.close();
out.close();
in.close();
}
catch(Exceptione)
{
e.printStackTrace();
}
}
}
复制代码
DataInputStream、DataOutputStream(包装流)
复制代码
importjava.io.DataInputStream;
importjava.io.DataOutputStream;
importjava.io.FileInputStream;
importjava.io.FileOutputStream;
importjava.io.IOException;
publicclasscircle
{
publicstaticvoidmain(String[]args)throwsException
{
writeDemo();
readDemo();
}
publicstaticvoidreadDemo()throwsIOException
{
DataInputStreamdos=newDataInputStream(newFileInputStream("C:/in.txt"));
Strings=dos.readUTF();
System.out.println(s);
}
publicstaticvoidwriteDemo()throwsIOException
{
/
DataOutputStream(OutputStreamout)
Createsanewdataoutputstreamtowritedatatothespecifiedunderlyingoutputstream.
/
DataOutputStreamdos=newDataOutputStream(newFileOutputStream("C:/in.txt"));
/
writeUTF(Stringstr)
WritesastringtotheunderlyingoutputstreamusingmodifiedUTF-8encodinginamachine-independentmanner.
/
dos.writeUTF("你好啊");//UTF-8修改版
}
}
复制代码
ObjectInputStream、ObjectOutputStream
ObjectOutputStream可以把对象直接存入到文件中,然后利用ObjectInputStream读取文件还原成对象,前提是该对象实现了Serializable接口
复制代码
importjava.io.EOFException;
importjava.io.FileInputStream;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.io.ObjectInputStream;
importjava.io.ObjectOutputStream;
importjava.io.Serializable;
publicclasscircle
{
publicstaticvoidmain(String[]args)throwsException
{
FileOutputStreamfop=newFileOutputStream("C:/out.txt");
/
ObjectOutputStream(OutputStreamout)
CreatesanObjectOutputStreamthatwritestothespecifiedOutputStream.
/
ObjectOutputStreamoos=newObjectOutputStream(fop);
Peoplep=newPeople(1,"zhang");
/
writeObject(Objectobj)
WritethespecifiedobjecttotheObjectOutputStream.
/
oos.writeObject(p);
p=newPeople(2,"li");
oos.writeObject(p);
p=newPeople(3,"zhao");
oos.writeObject(p);
//写入三个对象
oos.close();
//关闭输出流
FileInputStreamfis=newFileInputStream("C:/out.txt");
/
ObjectInputStream(InputStreamin)
CreatesanObjectInputStreamthatreadsfromthespecifiedInputStream.
/
ObjectInputStreamois=newObjectInputStream(fis);
try
{
while(true)
{
/
readObject()
ReadanobjectfromtheObjectInputStream.
/
Peoplep2=(People)ois.readObject();
System.out.println(p2);
}
//没有办法判断文件中对象的数量,所以,只有通过EOFException异常来中断
//或者在写入的时候把所有的对象都放到一个ArrayLis里,这样就不需要判断了
}
catch(ClassNotFoundExceptione)
{
//TODOAuto-generatedcatchblock
e.printStackTrace();
}
catch(EOFExceptione)
{
System.out.println("读取结束");
}
}
}
classPeopleimplementsSerializable
{
//必须实现Serializable接口
intid;
Stringname;
People(intid,Stringname)
{
this.id=id;
this.name=name;
}
publicStringtoString()
{
return"id:"+id+"name:"+name;
}
}
复制代码
PipedInputStream、PipedOutputStream
管道流内部在实现时还有大量的对同步数据的处理。管道输出流和管道输入流执行时不能互相阻塞,所以一般要开启独立线程分别执行
复制代码
importjava.io.;
publicclasscircle
{
publicstaticvoidmain(String[]args)throwsException
{
/
PipedInputStream()
CreatesaPipedInputStreamsothatitisnotyetconnected.
/
PipedInputStreampin=newPipedInputStream();
PipedOutputStreampout=newPipedOutputStream();
/
connect(PipedOutputStreamsrc)
Causesthispipedinputstreamtobeconnectedtothepipedoutputstreamsrc.
输入流与输出流连接
/
pin.connect(pout);
ReadThreadreadTh=newReadThread(pin);
WriteThreadwriteTh=newWriteThread(pout);
newThread(readTh).start();
newThread(writeTh).start();
}
publicstaticvoidsop(Objectobj)//打印
{
System.out.println(obj);
}
}
classReadThreadimplementsRunnable
{
privatePipedInputStreampin;
ReadThread(PipedInputStreampin)//
{
this.pin=pin;
}
//由于必须要覆盖run方法,所以这里不能抛,只能try
publicvoidrun()
{
try
{
sop("R:读取前没有数据,阻塞中...等待数据传过来再输出到控制台...");
byte[]buf=newbyte[1024];
intlen=pin.read(buf);//read阻塞
sop("R:读取数据成功,阻塞解除...");
Strings=newString(buf,0,len);
sop(s);//将读取的数据流用字符串以字符串打印出来
pin.close();
}
catch(Exceptione)
{
thrownewRuntimeException("R:管道读取流失败!");
}
}
publicstaticvoidsop(Objectobj)//打印
{
System.out.println(obj);
}
}
classWriteThreadimplementsRunnable
{
privatePipedOutputStreampout;
WriteThread(PipedOutputStreampout)
{
this.pout=pout;
}
publicvoidrun()
{
try
{
sop("W:开始将数据写入:但等个5秒让我们观察...");
Thread.sleep(5000);//释放cpu执行权5秒
/
write(intb)
Writesthespecifiedbytetothepipedoutputstream.
向管道写入数据,同时解除管道上的阻塞状态
/
pout.write("W:writePiped数据...".getBytes());
pout.close();
}
catch(Exceptione)
{
thrownewRuntimeException("W:WriteThread写入失败...");
}
}
//打印
publicstaticvoidsop(Objectobj)
{
System.out.println(obj);
}
}
复制代码
在了解了"字节型"流处理函数的应用场景后,我们接下来继续学习"字符型"流处理函数
0x3:Reader:字符输入流
0x4:Writer:字符输出流
在开始学习"字符型"流处理函数的应用场景之前,我们必须牢记一个概念,Java的流函数的整体架构是"装饰器设计模式",也就是说,所有的流函数都可以按照所需的功能进行任意组合、互相嵌套、包裹。而我们的字符型流处理函数本质上也是对字节型流处理函数的一次包裹(或者说加载了字节型流处理函数的功能)
另外数据持久化或网络传输都是以字节进行的,所以必须要有字符到字节或字节到字符的转化。字符到字节需要转化,其中读的转化过程如下图所示:
InputStreamReader类是字节到字符的转化桥梁,InputStream到Reader的过程要指定编码字符集,否则将采用操作系统默认字符集,很可能会出现乱码问题。StreamDecoder正是完成字节到字符的解码的实现类。
写入也是类似的过程如下图所示
通过OutputStreamWriter类完成,字符到字节的编码过程,由StreamEncoder完成编码过程
InputStreamReader、OutputStreamReader
复制代码
importjava.io.;
publicclasscircle
{
publicstaticvoidmain(String[]args)throwsException
{
InputStreaminputStream=newFileInputStream("C:/in.txt");
/
InputStreamReader(InputStreamin)
CreatesanInputStrewww.shanxiwang.netamReaderthatusesthedefaultcharset.
在字节型输入流之上包裹一层字符型输入流
/
Readerreader=newInputStreamReader(inputStream);
/
read()
Readsasinglecharacter.
/
intdata=reader.read();
while(data!=-1)
{
chartheChar=(char)data;
System.out.print(theChar);
data=reader.read();
}
reader.close();
OutputStreamoutputStream=newFileOutputStream("C:/out.txt");
/
OutputStreamWriter(OutputStreamout)
CreatesanOutputStreamWriterthatusesthedefaultcharacterencoding.
在字节型输出流之上包裹一层字符型输出流
/
Writerwriter=newOutputStreamWriter(outputStream);
/
write(Stringstr,intoff,intlen)
Writesaportionofastring.
/
writer.write("HelloWorld");
writer.close();
}
}
复制代码
从上面的代码我们可以看到,我们使用字节型的文件流读取文件,然后再在上面包裹一层字符型流读取函数。除此之外,还有另一种方法(严格来说不能算另一种方法,因为java的流函数架构是"装饰器设计模式",功能之间可以任意组装),直接之用字符型文件流读取(本质上来说,字符型文件流读取也是一些功能的组装)。
FileReader、FileWriter
复制代码
importjava.io.;
publicclasscircle
{
publicstaticvoidmain(String[]args)throwsException
{
/
FileReader(StringfileName)
CreatesanewFileReader,giventhenameofthefiletoreadfrom.
/
Readerreader=newFileReader("C:/in.txt");
intdata=reader.read();
while(data!=-1)
{
chartheChar=(char)data;
System.out.print(theChar);
data=reader.read();
}
reader.close();
Writerwriter=newFileWriter("C:/out.txt");
writer.write("HelloWorld");
writer.close();
}
}
复制代码
BufferedReader、BufferedWriter
和BufferedInputStream、BufferedOutputStream不同的是,BufferedReader、BufferedWriter提供了ReadLine、newLine()这种以行为单位的字符读写机制
复制代码
importjava.io.;
publicclasscircle
{
publicstaticvoidmain(String[]args)throwsException
{
/
FileReader(StringfileName)
CreatesanewFileReader,giventhenameofthefiletoreadfrom.
/
Readerreader=newFileReader("C:/in.txt");
/
BufferedReader(Readerin)
Createsabufferingcharacter-inputstreamthatusesadefault-sizedinputbuffer.
在Reader之上再包一层Buffer缓冲区的功能
/
BufferedReaderbrd=newBufferedReader(reader);
Stringdata=brd.readLine();
while(data!=null)
{
System.out.print(data);
data=brd.readLine();
}
brd.close();
reader.close();
Writerwriter=newFileWriter("C:/out.txt");
/
BufferedWriter(Writerout)
Createsabufferedcharwww.sm136.comacter-outputstreamthatusesadefault-sizedoutputbuffer.
/
BufferedWriterbwd=newBufferedWriter(writer);
/
write(Strings,intoff,intlen)
WritesaportionofaString.
/
bwd.write("HelloWorld");
/
newLine()
Writesalineseparator.
/
bwd.newLine();
bwd.close();
writer.close();
}
}
复制代码
CharArrayReader、CharArrayWriter
CharArrayReader是字符数组输入流。它和ByteArrayInputStream类似,只不过ByteArrayInputStream是字节数组输入流,而CharArray是字符数组输入流。CharArrayReader是用于读取字符数组,它继承于Reader。操作的数据是以字符为单位
复制代码
importjava.io.;
publicclasscircle
{
publicstaticvoidmain(String[]args)throwsException
{
chara=''a'';
charb=''b'';
charc=''c'';
/
CharArrayWriter()
CreatesanewCharArrayWriter.
/
CharArrayWritercarrWrt=newCharArrayWriter();
/
write(intc)
Writesacharactertothebuffer.
/
carrWrt.write(a);
carrWrt.write(b);
carrWrt.write(c);
/
toCharArray()
Returnsacopyoftheinputdata.
/
char[]buff=carrWrt.toCharArray();
for(inti=0;i {
System.out.println(buff[i]);
}
System.out.println("");
/
CharArrayReader(char[]buf)
CreatesaCharArrayReaderfromthespecifiedarrayofchars.
/
CharArrayReadercarrRed=newCharArrayReader(buff);
/
read()
Readsthenextbyteofdatafromthisinputstream.
/
intdata;
while((data=carrRed.read())!=-1)
{
System.out.println(data);
}
}
}
复制代码
FilterReader、FilterWriter
用来"封装其它的字符输入流,并为它们提供额外的功能"
PipedReader、PipedWriter
字符管道流,原理上和PipedInputStream类似
PrintWriter
printwriter是向文本输出流打印对象的格式化表示形式,它允许以一种格式化的方式进行数据流的写入,类似C语言中的printf()函数
复制代码
importjava.io.FileWriter;
importjava.io.IOException;
importjava.io.PrintWriter;
publicclasscircle
{
publicstaticvoidmain(String[]args)throwsException
{
Stringfilename="C:/out.txt";
/
PrintWriter(Writerout)
CreatesanewPrintWriter,withoutautomaticlineflushing.
/
PrintWriterpw=newPrintWriter(newFileWriter(filename));
String[]words=newString[]{"hello","world","!"};
for(inti=0;i {
/
format(Stringformat,Object...args)
Writesaformattedstringtothiswriterusingthespecifiedformatstringandarguments.
/
pw.format("words:%s\n",words[i]);
}
/
flush()
Flushesthestream.
/
pw.flush();
}
}
复制代码
0x5:File文件、目录操作接口
我们已经学习了关于流操作的各种函数接口,接下来我么继续学习File类,要明确的一点是,虽然这个类名是File类,但是这个类却不负责文件流的实际读写,在我本人看来,我更愿意叫它"文件元数据Meta操作接口"。而File类常常和文件流读写函数配合起来,进行文件的操作
复制代码
importjava.io.;
publicclasscircle
{
publicvoidFileOperate()
{
}
/
新建目录
@paramfolderPathString如c:/fqf
@returnboolean
/
publicvoidnewFolder(StringfolderPath)
{
try
{
StringfilePath=folderPath;
filePath=filePath.toString();
java.io.FilemyFilePath=newjava.io.File(filePath);
if(!myFilePath.exists())
{
myFilePath.mkdir();
}
}
catch(Exceptione)
{
System.out.println("新建目录操作出错");
e.printStackTrace();
}
}
/
新建文件
@paramfilePathAndNameString文件路径及名称如c:/fqf.txt
@paramfileContentString文件内容
@returnboolean
/
publicvoidnewFile(StringfilePathAndName,StringfileContent)
{
try
{
StringfilePath=filePathAndName;
filePath=filePath.toString();
FilemyFilePath=newFile(filePath);
if(!myFilePath.exists())
{
myFilePath.createNewFile();
}
FileWriterresultFile=newFileWriter(myFilePath);
PrintWritermyFile=newPrintWriter(resultFile);
StringstrContent=fileContent;
myFile.println(strContent);
resultFile.close();
}
catch(Exceptione)
{
System.out.println("新建目录操作出错");
e.printStackTrace();
}
}
/
删除文件
@paramfilePathAndNameString文件路径及名称如c:/fqf.txt
@paramfileContentString
@returnboolean
/
publicvoiddelFile(StringfilePathAndName)
{
try
{
StringfilePath=filePathAndName;
filePath=filePath.toString();
java.io.FilemyDelFile=newjava.io.File(filePath);
myDelFile.delete();
}
catch(Exceptione)
{
System.out.println("删除文件操作出错");
e.printStackTrace();
}
}
/
删除文件夹
@paramfilePathAndNameString文件夹路径及名称如c:/fqf
@paramfileContentString
@returnboolean
/
publicvoiddelFolder(StringfolderPath)
{
try
{
delAllFile(folderPath);//删除完里面所有内容
StringfilePath=folderPath;
filePath=filePath.toString();
java.io.FilemyFilePath=newjava.io.File(filePath);
myFilePath.delete();//删除空文件夹
}
catch(Exceptione)
{
System.out.println("删除文件夹操作出错");
e.printStackTrace();
}
}
/
删除文件夹里面的所有文件
@parampathString文件夹路径如c:/fqf
/
publicvoiddelAllFile(Stringpath)
{
Filefile=newFile(path);
if(!file.exists())
{
return;
}
if(!file.isDirectory())
{
return;
}
String[]tempList=file.list();
Filetemp=null;
for(inti=0;i {
if(path.endsWith(File.separator))
{
temp=newFile(path+tempList[i]);
}
else
{
temp=newFile(path+File.separator+tempList[i]);
}
if(temp.isFile())
{
temp.delete();
}
if(temp.isDirectory())
{
delAllFile(path+"/"+tempList[i]);//先删除文件夹里面的文件
delFolder(path+"/"+tempList[i]);//再删除空文件夹
}
}
}
/
复制单个文件
@paramoldPathString原文件路径如:c:/fqf.txt
@paramnewPathString复制后路径如:f:/fqf.txt
@returnboolean
/
publicvoidcopyFile(StringoldPath,StringnewPath)
{
try
{
intbytesum=0;
intbyteread=0;
Fileoldfile=newFile(oldPath);
if(oldfile.exists())
{//文件存在时
InputStreaminStream=newFileInputStream(oldPath);//读入原文件
FileOutputStreamfs=newFileOutputStream(newPath);
byte[]buffer=newbyte[1444];
intlength;
while((byteread=inStream.read(buffer))!=-1)
{
bytesum+=byteread;//字节数文件大小
System.out.println(bytesum);
fs.write(buffer,0,byteread);
}
inStream.close();
}
}
catch(Exceptione)
{
System.out.println("复制单个文件操作出错");
e.printStackTrace();
}
}
/
复制整个文件夹内容
@paramoldPathString原文件路径如:c:/fqf
@paramnewPathString复制后路径如:f:/fqf/ff
@returnboolean
/
publicvoidcopyFolder(StringoldPath,StringnewPath)
{
try
{
(newFile(newPath)).mkdirs();//如果文件夹不存在则建立新文件夹
Filea=newFile(oldPath);
String[]file=a.list();
Filetemp=null;
for(inti=0;i {
if(oldPath.endsWith(File.separator))
{
temp=newFile(oldPath+file[i]);
}
else
{
temp=newFile(oldPath+File.separator+file[i]);
}
if(temp.isFile())
{
FileInputStreaminput=newFileInputStream(temp);
FileOutputStreamoutput=newFileOutputStream(newPath+"/"+(temp.getName()).toString());
byte[]b=newbyte[10245];
intlen;
while((len=input.read(b))!=-1)
{
output.write(b,0,len);
}
output.flush();
output.close();
input.close();
}
if(temp.isDirectory())
{//如果是子文件夹
copyFolder(oldPath+"/"+file[i],newPath+"/"+file[i]);
}
}
}
catch(Exceptione)
{
System.out.println("复制整个文件夹内容操作出错");
e.printStackTrace();
}
}
/
移动文件到指定目录
@paramoldPathString如:c:/fqf.txt
@paramnewPathString如:d:/fqf.txt
/
publicvoidmoveFile(StringoldPath,StringnewPath)
{
copyFile(oldPath,newPath);
delFile(oldPath);
}
/
移动文件到指定目录
@paramoldPathString如:c:/fqf.txt
@paramnewPathString如:d:/fqf.txt
/
publicvoidmoveFolder(StringoldPath,StringnewPath)
{
copyFolder(oldPath,newPath);
delFolder(oldPath);
}
}
复制代码
4.后记
复制代码
1.什么时候改用什么流函数:
我在学习Java的的API的时候第一个问自己的问题就是这个,在我看来,可以遵循以下两点:
1)明确我们的目的,例如需要读取文件,就使用文件流FileInputStream、需要缓存就包上一层BufferedInputStream、要进行字符型读取就使用InputStreamReader
2)理解"装饰器设计模式"的概念,我们需要的功能可以通过流函数之间的包裹来进行实现,在编程的时候,注意参考API文档,查明哪些流对象之间可以互相包裹很重要
2.对流函数的深入理解:
Java的源代码是公开的,为了深入理解Java中的IO机制,下一步希望从源代码角度去深入研究一下Java中的IO、流、缓存机制,以及优化方案
|
|