IO (input output) 流:
1. IO流用来处理设备之间的数据传输
2. Java对数据的操作是通过流的方式
3. Java用于操作流的对象都在IO包中
4. 流按操作数据分为两种:字节流与字符流。
流按流向分为:输入流,输出流。
字节流的抽象基类:
InputStream ,OutputStream。
字符流的抽象基类:
Reader ,Writer。
由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。如:InputStream的子类FileInputStream。Reader的子类FileReader。
这便是IO流中最主要的四个类,其实在原始的传输中只有字节流,而没有字符流。但是当只需要传输一个纯文本文件的时候,用字节流转换显得有些麻烦,所以才有了Reader、Writer这两个类。
字符流、字节流的缓冲区:
缓冲区的出现提高了对数据的读写效率。
对应类:
1. BufferedReader,BufferedWriter
2. BufferedInputStream,BufferedOutputStream
缓冲区要结合流才可以使用,在流的基础上对流的功能进行了增强,可以提高IO流的读写效率。
下面比较复制一个图片的速度来说明问题:
package test;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test9 {
//比较两种方法复制图片所用时间的多少
public static void main(String[] args) throws Exception {
long beginTime = System.currentTimeMillis();
copy_1();
// copy_2();
long endTime = System.currentTimeMillis();
System.out.println(endTime-beginTime);
}
//用缓冲区,但是一个一个的复制
public static void copy_1(){
//为了处理异常,必须定义在try外面
BufferedInputStream bufin = null;
BufferedOutputStream bufout = null;
try {
bufin = new BufferedInputStream(
new FileInputStream("e:\\1.jpg"));
bufout = new BufferedOutputStream(
new FileOutputStream("e:\\2.jpg"));
int ch = 0;
while ((ch = bufin.read()) != -1)
bufout.write(ch);
} catch (Exception e) {
throw new RuntimeException("复制出问题了!");
}
//用到close方法,也会抛出异常,必须处理
finally{
if(bufin!=null){
try {
bufin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bufout!=null){
try {
bufout.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//不用缓冲区,自己写一个字节数组用于赋值,直接声明抛出异常,简化书写
public static void copy_2() throws Exception{
FileInputStream fis = new FileInputStream("e:\\1.jpg");
FileOutputStream fos = new FileOutputStream("e:\\2.jpg");
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1){
fos.write(buf,0,len);
}
fis.close();
fos.close();
}
}
这个运行结果是copy_1方法用时285毫秒,而copy_2方法用时52毫秒。显而易见,copy_2方法快的多,为何呢?不是copy_1用了缓冲区吗。其实缓冲区也就是加入了byte[] 数组的方式,来一次读一个数组,一次取一个数组,而copy_1是每次读一个字节,取一个字节,自然要慢上许多。
File类:
1. 用来将文件或者文件夹封装成对象
2. 方便对文件与文件夹的属性信息进行操作。
3. File对象可以作为参数传递给流的构造函数。
File在IO流中经常用到,因为它对文件的操作非常方便,省去了很多麻烦,我们必须了解其中常用的一些方法。
创建: createNewFile(); 在指定位置创建文件,如果文件已存在,则不创建。
删除: delete(); 删除指定文件。 deleteOnExit(); 在程序退出时删除指定文件。
判断: exists(); 判断文件是否存在。 ifFile(); 是否为文件。 isDirectory(); 是否为目录。
获取: getName(); 获取文件名。 getPath(); 获取相对路劲。 getAbstractePath(); 获取绝对路劲。
下面展示一个获取一个文件夹中所有以.java结尾的文件,并打印其文件名和总个数。
package test;
import java.io.File;
public class Test10 {
public static void main(String[] args) {
//传入一个文件夹路径
judgePath("E:\\JAVA\\javafile_save");
}
public static void judgePath(String path){
File file = new File(path);
//判断路劲输入是否正确,不正确则返回之
if(!file.exists()){
System.out.println("路径不存在");
return;
}
//判断路劲是否为文件夹,不是则返回之
if(!file.isDirectory()){
System.out.println("输入的路径不是文件夹");
return;
}
int count = 0;
count = sopJavaFile(file,count);
System.out.println("Java文件的总个数为:"+count);
}
//用递归的方法判断文件是否为文件夹,如果是,调用自身,不是,判断是否以.java结尾,是的就打印之
public static int sopJavaFile(File file, int count){
File[] files = file.listFiles();
for(File f: files){
if(f.isDirectory())
count = sopJavaFile(f,count);
else{
String name = f.getName();
if(name.endsWith(".java")){
System.out.println(name);
count++;
}
}
}
return count;
}
}
打印结果的一部分:
TcpDemo3.java
TcpDemo4.java
UdpDemo.java
UdpDemo1.java
Demo.java
TcpPic.java
URLDemo.java
UserLogin.java
GetWeb.java
Person.java
RegexDemo.java
RegexTest.java
RegServer.java
Java文件的总个数为:116
这样就实现了打印一个文件夹中所有java文件的操作,在实际应用上File类文件也是如此,能方便快捷的实现对文件的各种操作。
其他IO流:
Properties:集合链接IO流的方法。
PriteStream,PriteWrite: 打印流,可以将各式各样的数据原样打印。
SequenceInputStream: 对多个流进行合并。
ObjectInputStream: 对象流,通过UID记录对象的值,可以存储、读取对象
PipedInputStream: 管道流,IO流+多线程 的结合,可以一边写入,一边读出
RandomAccessFile: 随机存储文件,该类不是IO体系中的子类,但是它是IO包中的成员,因为他具备读写功能。它内部封装了一个数组,而且通过指针对数组的元素进行操作。
DataInputStream: 数据流,可以直接对基本数据类型操作。
字符编码的方式:
中文主要是两种:GBK,UTF-8。
这里便涉及到了字符流和字节流的转化,其中2个最重要的转换流是:
InputStreamReader: 字符-->字节
OutputStreamWriter: 字节-->字符
在操作IO流的时候,只要掌握了一个规律,就能随心所欲的操作:
1. 明确源和目的
2. 操作的是否为纯文本文件
3. 当体系确定后,再明确要使用哪个具体的对象
只要明确了这三点,就能实现各种读取和写入操作。