IO流概述
2)File(String parent,String child);(与3区别创建文件) 5
3)File(File f,String child)(与4区别传送文件) 6
1. FileInputStream 与 FileOutputStream 类(字节流) 7
2. FileReader 与 FileWriter 类(字流多用于传递汉字) 8
1. BufferedInputStream 与 BufferedOutputStream 类 9
2. BufferedReader 与 BufferedWriter 类 10
一、流概述
流是一组有序的数据序列,根据操作的类型,可以分为输入流和输出流两种。
I/O(Input/Output)流提供了一条通道程序,可以使用这条通道把源中的字节序列送到目的地。
虽然I/O流通常与磁盘存取有关,但是程序的源和目的地也可以是键盘、鼠标、显示器和内存等。
Java由数据流处理输出/输出模式,程序从指向源的输出流中读取源中的数据。源可以是网络、文件、压缩包等。
输出流的指向是数据要达到的目的地,程序通过指向输出流中写入的数据把信息传递到目的地。输出流的目标可以是文件、网络、压缩包等输出目标。
二、输入流、输出流
Java中定义了许多类专门扶着各种方式的输入和输出,这些方式都被放在java.io里面。
其中,所有的输入类都是抽象类InputStream(字节输入流)或者Reader(字符输入流)的子类;而所有的输出流都是OutputStream(字节输出流)或者Writer(字符输出流)的子类。
1.输入流
1)InputStream类
InputStream类是字节输入流的抽象类,是所有字节输入流的父类。它的层次机构为:
=====================================================
InputStream
AudioInputStream
ByteArrayInputSteam
StringBufferInputStream
InputStream
FileInputStream
FilerInputStream
BufferdeInputStream
DataInputStream
PushbackInputStream
...
ObjectInputStream
SequenceInputStream
PipedInputStream
=====================================================
该类的所有方法遇到都错误时都会引发IOException异常。下面是对该类中的一些方法的简要说明:
Ø read();从输入流中读取数据的下一个字节。返回范围0~255范围内的int字节值。如果因为达到流末尾而没有可用的字节,则返回-1.
Ø read(byte[] b);从输入流中读入一定长度的字节,并以整数的类型返回字节数。
Ø mark(int readlimit);在输入流的当前位置放置一个标记,readlimit参数告知次输入流在标记位置失效前允许读取字节数。
Ø reset();将输入指针返回到当前所做标记处;
Ø skip(long n);跳过输入流上的n个字节并返回实际跳过的字节数。
Ø markSupported();如果当前支持mark()/reset操作就返回True。
Ø close;关闭此流并释放与该流关联的所有系统资源。
2)Reader类
Java中字符是Unicode编码,是双字节的。InputStream是用来处理字节的,并不适合处理文本。Java为字符文本专门提供了一套单独的类Reader,但是Reader类并不是InputStream类的替换者,只是在处理字符串是简化了编程。
Reader类是字符输入流的抽象类,所有字符输出流的实现都是它的子类。Reader类的具体层次结构为:
=====================================================
Reader
CharArrayReader
BufferedReader
LineNumberReader
FilterReader
PushbackReader
InputStreamReader
FileReader
PipedReader
StringReader
=====================================================
Reader类的方法和InputStream类中的相似,可以再API中进行查找。
2.输出流
1)OutputStream
OutputStreanm类是字节输出流的抽象类,此抽象类是表示输出字节的所有类的超类。
其层次图为:
=====================================================
OutputStream
ByteArrayOutputStream
FileOutputStream
FilterOutputSream
BufferedOutputStream
DataOutputStream
...
ObjectOutputStream
OutputStream
OutStream
PipedOutputStream
=====================================================
OutputSream类中的所有方法均为viod,在遇到错误时会引发IOException异常。
Ø write(int b);将指定的字节写入此输出流。
Ø write(byte[] b);将b个字节从指定的byte数组写入此输出流。
Ø write(byte[] b,int off,int len);将指定byte数组中从偏移量off开始的len个字节写入此输入流。
Ø flush();彻底完成输出并清空缓存区。
Ø close();关闭输出流。
2)Writer
Writer类是字符输出流的抽象类,所有字符输出类的实现都是它的子类。
Writer类的层次结构:
=====================================================
Writer
BufferedWriter
CharArrayWriter
FilterWriter
OutputSteamWriter
FileWriter
PipedWriter
PrintWriter
StringWriter
=====================================================
三、File类
File类是java.io包中唯一代表磁盘文件本身的对象。File类定义了一些平台无关的方法来操作文件,可以通过调用File类的方法,实现创建、删除、重命名等操作。
File类的对象主要用来获取文件本身的一些信息,如文件所在目录、文件长度、文件读写权限等。
数据流可以将数据写入到文件中,文件也是数据流常用的数据媒体。
1.文件的创建和删除
1)File(pathname);
l pathname:指路径名
File file=new Fiel(“d:/1.txt”)
2)File(String parent,String child);(与3区别创建文件)
该构造方法根据定义的父路径和子路径字符串(包含文件名)创建一个新的File对象。
l parent:指父路径名
l child:指子路径名(泛指文件名+后缀)
3)File(File f,String child)(与4区别传送文件)
该构造方法根据parent抽象路径名和child路径名字字符串创建一个新的File实例。
l f:指父路径名
l child:指子路径名(泛指文件名+后缀)
File file=new File("word.txt");//创建文件对象,指定目录
if(file.exists()){//如果该文件存在
file.delete();//删除文件
System.out.println("文件已删除");
}else{
try{
file.createNewFile();//创建该文件
System.out.println("文件已经创建");
}catch(Exception e){
e.printStackTrace();
}
}
2.获取文件信息
File提供了很多方法用于获取一些文件本身的信息,其中方法如下:
方法 |
返回值 |
说明 |
getName() |
String |
获取文件的名称 |
canRead() |
boolean |
判断文件是否可读 |
canWrite() |
boolean |
判断文件是否可以被写 |
exits() |
boolean |
判断文件是否存在 |
length() |
long |
获取文件的长度 |
getAbsolutePath() |
String |
获取文件绝对路径 |
getParent() |
String |
获取文件父路径 |
isFile() |
boolean |
判断文件是否存在 |
isDirectory() |
boolean |
判断文件是否是一个目录 |
isHidden() |
boolean |
判断文件是否隐藏 |
lastModified() |
long |
获取文件最后修改时间 |
File file=new File("word.txt");//创建文件对象
if (file.exists()) {//如果文件存在
String name=file.getName();//获取文件名
long length=file.length();//获取文件大小
boolean hidden=file.isHidden();//获取文件隐藏状态
System.out.println("文件名称:"+name);
System.out.println("文件长度:"+length);
System.out.println("是否隐藏:"+hidden);
}else{
System.out.println("该文件不存在!");
}
四、文件输入输出流
程序运行期间,大部分数据都在内存中进行操作,当程序结束或关闭时,这些数据将消失。如果需要将数据永久保存,可使用文件输入/输出流与指定文件建立连接,将需要的数据永久保存到文件中。
1.FileInputStream 与 FileOutputStream 类(字节流)
FileInputStream类与FileOutputStream类都是用来操作磁盘文件的。如果用户读取需求比较简单,则可以使用FileInputStream类,该类继承自InputStream类。
FileOutputStrem与FileInputStream类对应,提供了基本的文件写入能力。FileOutputSteam是OutputSteam的子类。
FileInputStream类常用的构造方法如下:
Ø FileInputStream(String name);
Ø FileInputStream(File file);
第一个构造方法使用给定的文件名name创建一个FileInputStream对象,第二个构造方法使用File对象创建了FileInputStream对象。第一个构造方法比较简单,但是第二个否早方法允许在把文件连接输入流之前对文件进一步分析。
FileOutputStream类有与FileInputStream类相同的构造方法,创建一个FileOutputStream对象时,可以指定不存在的文件名,但是此文件不能是一个已经被打开的文件。
例:
File file=new File("word.txt");//创建文件
try {
//创建FileOutputStream对象
FileOutputStream out=new FileOutputStream(file);
byte buy[]="我有一头小毛炉,从来也不骑!".getBytes();
out.write(buy);//将数组信息写入到文件中
out.close();//将流关闭
} catch (Exception e) {
e.printStackTrace();
}
try {
//创建FileInputStream类对象
FileInputStream in=new FileInputStream(file);
byte byt[]=new byte[1024];//创建byte数组
int len=in.read(byt);//从文件中读取信息
//将文件中的信息输出
System.out.println("文件中的信息是:"+new String(byt,0,len));
in.close();//关闭流
} catch (Exception e) {
e.printStackTrace();
}
2.FileReader 与 FileWriter 类(字流多用于传递汉字)
使用FileInputStream和FileOutputStream时,用的是字节传送,容易对汉字(字)产生错乱。此时应采用FileReader和FileWriter,此方法可以避免这种现象。
FileWriter和FileReader字符流对应了FileOutputStream和FileInputStream类。FileReader流顺序的读取文件,只要不关闭流,每次调用read()方法就顺序的读取源中剩余的内容,指导员中的数据结束或者关闭。
例:用法和字节流完全一样
File file=new File("word.txt");//创建文件
try {
//创建FileOutputStream对象
FileWriter out=new FileWriter(file);
char buy[]="我有一头小毛炉,从来也不骑!".toCharArray();
out.write(buy);//将数组信息写入到文件中
out.close();//将流关闭
} catch (Exception e) {
e.printStackTrace();
}
try {
//创建FileInputStream类对象
FileReader in=new FileReader(file);
char byt[]=new char[1024];//创建char数组
int len=in.read(byt);//从文件中读取信息
//将文件中的信息输出
System.out.println("文件中的信息是:"+new String(byt,0,len));
in.close();//关闭流
} catch (Exception e) {
e.printStackTrace();
}
五、带缓存的输入输出流
缓存是I/O的一种性能优化。缓存流为I/O增加了内存缓存区。有了缓存区,使得在流上执行skip()、mark()和reset()方法都成为可能。
1.BufferedInputStream 与 BufferedOutputStream 类
BufferedInputStream类是可以对所有InputStream类进行带缓存区的包装已达到性能的优化。
BufferedInputSream有两个构造方法:
Ø BufferedInputStream(InputStream in);
Ø BufferedInputStream(InputStream in,int size);
第一种形式的构造方法创建了一个32个字节的缓存流;
第二种形式的构造方法创建了一个size长度的缓存区。
一个最优的缓存区的大小,取决于他所在的操作系统、可用的内存空间以及机器的配置。从构造方法可以看出,BufferedInputStream对象位于InputStream类对象之前。
文件》》InputStream》》BufferedInputStream》》目的地
使用bufferedOutputStream输出信息和用OutputStream输出信息完全一样,只不过BuffereOutputStream有一个flush()方法用来将缓存区的数据强制输出完。BufferedOutputStream类也有两个构造方法:
Ø BufferedOutputStream(OutputStream in);
Ø BufferedOutputStream(OutputStream in,int size);
第一种自动创建32个字节缓存区,第二个指定创建大小。
2.BufferedReader 与 BufferedWriter 类
BufferedReader类与BufferedWriter类分别继承了Reader类和Writer类。这两个类同样具有内部缓存机制,并可以以行为单位进行输入输出。
根据BufferedReader类的特点,总结如下:
字符数据》》BufferedWriter》》OutputStreamWriter》》OutputStream》》文件
BufferedReader常用的方法有:
Ø read();读取单个字符。
Ø readLine();读取一行文本。
Ø write(String s,int off,int len);读取一行文本,并将其返回为字符串。若无数据可读,则返回null。
BufferedWriter类中的方法都返回void。重用方法如下:
Ø flush();刷新该流的缓存。
Ø newLine();写入一行分隔符。
在使用BufferedWriter类的Wirte()方法时,数据并没有立即被直接写入至输出流,而是首先进入缓存区中。如果想立刻将缓存区中的数据写入输出流,一定要调用flush()方法。
例:
//定义字符串数组
String content[]={"好久不见","最近好吗","记得常联系"};
File file=new File("word.txt");//创建文件
try {
FileWriter fw=new FileWriter(file);//创建FileWrter类
//创建BufferedWriter类对象
BufferedWriter bufw=new BufferedWriter(fw);//创建BufferedWriter类
for (int k = 0; k < content.length; k++) {
bufw.write(content[k]);//将字符串写入到的文件中
bufw.newLine();//将数组中的数据以单行的形式写入文件
}
bufw.close();//关闭流
fw.close();//关闭流
} catch (Exception e) {
e.printStackTrace();
}
try {
FileReader fr=new FileReader(file);//创建FileReader类
//创建BufferdReader类
BufferedReader bufr=new BufferedReader(fr);//创建BufferedReader类
String str=null;//创建容器
int i=0;//循环参数
//如果文件的文本不为null则循环
while(bufr.readLine()!=null){
i++;
System.out.println("第"+i+"行"+str);
bufr.close();//关闭流
fr.close();//关闭流
}
} catch (Exception e) {
e.printStackTrace();
}
六、数据输入输出流
数据输入输出流(DataInputStream 和DataOutputStream)允许应用程序与机器无关的方式从底层输入流中读取基本Java数据类型。也就是说,当读取一个数据时,不必再关心这个数值应当是那种字节。
DataInputStream类与DataOutputStream类的构造方法如下:
Ø DataInputStream(InputStream in):使用指定的基础InputStream创建一个DataInputStream。
Ø DataOutputStream(OutputStream out):创建一个新的数据输出流,将数据写入制定的基础输出流。
DataOutputStream提供了一下3种字符串写入方法。
Ø writeBytes(String s);
Ø writeChars(String s);
Ø writeUTF(String s);
由于java中字符方式Unicode编码,是双字节的,writeBytes是只是将字符串的每一个字符的低字节写入目标设备中;
而writeChars是将字符串的每个字符的两个字节内容都写到目标设备中;
writeUTF将字符串按照UTF编码后的字节长度写入目标设备,然后才是每个字节的UTF编码。
DataInputStream类只提供了一个readUTF()方法返回字符串。这是因为要在一个连续的字节流读取一个字符串,如果没有特殊的标记作为一个字符串的结尾,并不知道这个字符串的长度,就无法知道读取到什么位置才是这个字符串的结束。
DataInputStream类中只有writeUTF()方法向目标设备中写入字符串的长度,所以也能准确的读回写入字符串。
try {
//创建FileOutputStream
FileOutputStream fs=new FileOutputStream("word.txt");
//创建DataOutputStream
DataOutputStream ds=new DataOutputStream(fs);
ds.writeUTF("使用writeUTF()方法写入数据");
ds.writeChars("使用writeChars()方法写入数据");
ds.writeBytes("使用writeBytes()方法写入数据");
ds.close();
//创建FileInputStream对象
FileInputStream fis=new FileInputStream("word.txt");
//创建DataInputStream对象
DataInputStream dis=new DataInputStream(fis);
System.out.println(dis.readUTF());
} catch (Exception e) {
e.printStackTrace();
}
结果如:
使用writeUTF()方法写入数据
记事本显示
尽管在记事本程序中看不出writeUTF写入的字符串,当时通过readUTF读回后显示在屏幕上的和传送的字符串相同。但是如果使用writeChars和writeByte方法写入字符串后,在读取回来就不容易了。
七、ZIP压缩输入输出流
ZIP压缩管理文件(ZIParchive)是一种十分经典的的文件压缩形式,使用它可以节省储存空间。关于ZIP压缩的IO实现,在Java的内置类中提供了非常好的的相关类,所以其实现方式非常简单。本文将介绍使用java.util.zip包中的ZipOutputStream和ZipInputStream类来实现文件的压缩和解压。
如要从ZIP压缩管理文件内读取某个文件,要先找到对应的文件目录,才能读取这个文件的内容。如果要把写入文件内容的位置移动到次进入所指的位置,然后再写入文件。
Java实现了IO数据流与网络数据流的单一接口,因此数据的压缩、网络传送和解压缩的实现比较容易。ZipEntry类产生的对象,是用来代表一个ZIP压缩文件的进入点(entry)。ZipInputStream类用来读取ZIP压缩格式的文件,所支持的包括要压缩及未压缩的的进入点(entry)。ZipOutputStream类用来写出ZIP压缩格式的文件,而且所支持的包括已压缩及未压缩的进入点(entry)。
1.压缩文件
ZipOutputStream类对象,可将文件压缩为(.zip)文件。
构造方法如下:
Ø ZipOutputStream(OutputStream out);
常用的方法:
方法 |
返回值 |
说明 |
pubNextEntry(ZipEntry e) |
void |
开始写一个新的ZipEntry,并将流内的位置以至此entry所指的开头。 |
write(byte[]b,int off,int len) |
void |
将字节数组写入当前ZIP条目数据。 |
finis() |
void |
完成写入ZIP输出流的内容,无须关闭它所配合的OutputSream。 |
setComment(String comment) |
void |
可设置此ZIP文件的注释文字 |
下面实例为压缩E盘的hello文件夹,在该文件夹中有hello1.txt和hello2.txt文件,并将压缩后的hello.zip文件夹保存在E盘根目录下。
例:
import java.io.*;
import java.util.zip.*;
public class MyZip {//创建类
private void zip(String zipFileName,File inputFile) throws Exception{
ZipOutputStream out =new ZipOutputStream(new FileOutputStream(zipFileName));//创建ZipOutputStream类对象
zip(out,inputFile,"");//调用方法
System.out.println("压缩");//输出信息
out.close();//将流关闭
}
private void zip(ZipOutputStream out, File f, String base) throws Exception{//方法重载
if (f.isDirectory()) {//测试此抽象路径名表示的文件是否是一个目录
File[]fl=f.listFiles();//获取路径数组
out.putNextEntry(new ZipEntry(base+"/"));//写入此目录的entry
base=base.length()==0?"":base+"/";//判断参数是否为空
for (int i = 0; i < fl.length; i++) {//循环遍历数组中的文件
zip(out,fl[i],base+fl[i]);
}
}else{
out.putNextEntry(new ZipEntry(base));//创建新的接入点
FileInputStream in=new FileInputStream(f);//创建FileInputStream对象
int b;//定义int变量类型
System.out.println(base);
while ((b=in.read())!=-1) {//如果没有达到流的末尾
out.write(b);//将字节写入当前ZIP条目
}
in.close();//关闭流
}
}
public static void main(String[] args) {//住方法
MyZip book=new MyZip();//创建本例对象
try{
//调用方法,参数为压缩后的文件与要压缩的文件
book.zip("E:/hello.zip",new File("E:/hello"));
System.out.println("压缩完成");
}catch(Exception e){
System.out.println("1111");
}
}
}