IO流
一、IO流
IO流是处理设备之间数据的传输
常用的流对象有直接操作文件的流对象以及带缓冲的流对象
根据处理数据不同分为:
字节流:对于图片或是视频等非纯文本文件的操作只能用字节流。
字符流:字符流其实就是字节流+编码机制。当对文件的操作是用字符流
1.字节流:
字节流不存在缓冲区
InputStream:读操作
OutputStream:写操作
FileInputStream:FileOutputStream中不存在缓冲区,直接将数据写入到目的地
FileInputStream中的available()方法:获取和流相关联的文件的“剩余”字节数
2.字符流:
Reader,常用FileReader对纯文本读操作
Writer,常用FileWriter 对纯文本写操作
注意:字符流不能对图片和音频复制,因为当字符流读取数据时,字符流会查默认的编码表,如果编码表中没有查到具体的数据,就会用其他的数据替代。就会出现数据错乱。只有当操作操作数据是文本时建议使用。
FileReader:对文件的读操作
定义数组的长度一般为1024的整数倍
FileWriter:对文件的写操作
1)可以对文件进行续写new FileWriter("aa.txt",true);
2)new FileWriter("a.txt");当要创建的文件已经存在,就会产生覆盖
3.缓冲区:(装饰设计模式)
1.缓冲区可以提高读写效率,但是缓冲区对象的建立首先得将流初始化进来。
2.用到缓冲区一定要flush();
3.缓冲区是提高流的操作效率而存在的,内部提供了数组。对数组缓冲。但是最终的操作还是流来完成的,所以 关闭缓冲区,其实就是关闭流。其内部调用的是close()方法
BufferedReader:读操作的缓冲区。
BufferedWriter:写操作的缓冲区,每读一行要调用newLine()和flush()方法。
示例:
import java.io.*;
import java.io.FileReader;
import java.io.IOException;
import java.io.BufferedReader;
public class Test{
public static void main(String...args) throws IOException{
Reader r = new FileReader("C:\\1.Java");
/*
为了提高效率,加入缓冲技术,将字符读取流对象作为参数传递给缓冲对象的构造函数
*/
BufferedReader br = new BufferedReader(r);
for(String line = null;(line=br.readLine())!=null;){
System.out.print(line);
System.out.println();
}
}
}
装饰设计模式:当对类的功能进行增强时,称为对该类的装饰,具备灵活性。
例如:现在要用A接口的一个方法,但是需要把A接口所有的方法实现才可以,以后如果再次用到A接口,其他的方法同样繁琐。这样我们就先定义一个类B实现A接口,但是B类的方法全部为空,以后直接继承B类即可。
4.转换流:
InputStreamReader:字节流通向字符流的桥梁
OutputStreamWriter:字符流通向字节流的桥梁
转换流可以设置编码表,不设置就是本机默认的编码表。如果是指定编码表,就要将编码表作为字符串传入构造函数中。
例如:BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream
("aa.jpg")));
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream
("bb.jpg")));
5. LineNumberReader:带有行号
readLine():底层其实就是调用了read()方法,一次读一个字符,并把该字符临时存储,当读到换行符的时候就将存储的数据作为字符串返回,输入流和输出流其实都是需要缓冲区来先存放读取的数据,再通过写缓冲区的数据来实现。
6.打印流:PrintWriter和PrintStream
只操作写,而且PrintWriter不抛异常
7.管道流:PipedlnputStream和PipedOutputStream
1) 输入输出可以直接进行连接
2) 先读后写会出现死锁,所以建议多线程
8.序列流: SequenceInputStream
对多个流进行合并,实现数据的合并
9.文件切割:RandomAccessFile
1)随机访问文件,自身具备读写方法;
2)该对象操作的数据时字节数据,其中封装了读取流和写入流;
3)提供getFilePointer方法获取指针位置,有seek设置指针位置。
raf.write(65);只将一个整数的最低四个字节写出。
raf.seek(8);从指针索引位8开始进行写入,完成数据的随机写入。
对已有数据修改,移动指针,seek()方法可以应用对于多线程对于大数据的写入,同时写入,给每个线程分配一个起始索引位,可以多线程随机写入。
10.对象的持久化ObjectStream
就是将对象中封装数据保存到持久化的设备比如硬盘;
Serializable接口,序列化。有相对于的SerializableUID,即序列号,通过类成员数据签名完成;
没有方法的接口称之为标记接口;
对象中静态数据时不会被持久化的,它不在堆内存中;
非静态数据不想被持久化:进行transient修饰;
指定固定的序列号public static final long serialVersionUID = 42L;
11.操作基本数据类型的IO:DateInputStream和DateOutputStream
注意:ByteArrayOutputstream:关闭它无效,因为该对象根本没有调用底层资源。不抛出异常。可以通过toByArray()或者toString()获取数据
关闭流必须在finally中进行操作,而且在关闭之前判断流是否存在,否则会出现空指针异常。另外关闭流的时候也会抛出异常,每一个流的关闭都单独执行。
对文件进行读写的时候,可能文件路径错误,所以会出现异常;
flush()和close():
flush():刷新缓冲区,流依然存在,并可以继续使用;
close():先刷新缓冲区,其实就是调用一次flush(),然后关闭调用底层资源,将资源释放。
二、装饰设计模式
装饰设计模式的出现是为了增强功能;
装饰设计模式通常不单独存在,都是通过构造函数接收被装饰的对象,基于被装饰对象的功能,对外界提供增强的功能。它可以对一组类进行功能的增强
和继承的区别:
继承会让体系变得臃肿,但是装饰则显得更为灵活
IO流中很多体系用到装饰设计模式,例如Writer
1、当想要对已有对象进行功能增强时,可以定义一个类,将已有对象传入,基于已有的功能,并提供加强功能,那么该自定义类称为装饰类。
2、装饰类通常会通过构造方法接收被装饰的对象。并基于被装饰的功能,提供更强的功能。
(可以理解为打扮,比如自己如果要去面试之前,咱们要把自己打扮一下,把自己搞上点新鲜的衣服,但是最后还是一个人,只是身上多个点东西,这就是装饰)
三、IO流体系
类
Reader
|--InputStreamReader
|--FileReader
|--BufferedReader
|--LineNumberReader
|--CharArrayReader
|--StringReader
|--PipedReader
Writer
|--OutputStreamWriter
|--FileWriter
|--BufferedWriter
|--CharArrayWriter
|--StringWriter
|--PrintWriter
|--PipedWriter
File
InputStream
|--FilerInputStream
|--LineNumberInputStream
|--BufferedInputStream
|--DataInputStream
|--FileInputStream
|--ByteArrayInputStream
|--PipedInputStream
|--ObjectInputStream
|--SequenceInputStream
OutputStream
|--FilerOutputStream
|--PrintOutputStream
|--BufferedOutputStream
|--DataOutputStream
|--FileOutputStream
|--ByteArrayOutputStream
|--PipedOutputStream
|--ObjectOutputStream
RandomAccessFile
接口
Serializable
四、File类
可以是文件对象,也可以是文件夹对象
File f=new File("c:\\a.txt");把指定文件封装成File对象
File f=new File("c:\\","a.txt");
File dir=new File("c:\\a.txt");
File f=new File(dir,"a.txt");
1.程序跨平台
File f=new File("c:"+File.separator+"a.txt");目录分隔符
2.创建
File f=new File("f.txt");
boolean b=f.createNewFile(); 如果这个文件不存在创建,存在就不创建;但是如果是输出流创
建文件,就会直接覆盖,如果构造函数true,不会覆盖,可以续写抛异常
File f=new File("abc");
f.mkdir();创建你目录
f.mkdirs();创建多级目录
3. 删除
File f=new File("f.txt");
f.delete();直接删除,不经过回收站
删除文件夹,如果文件夹中有内容,应该先将内容清空
void deleOnExit()告诉JVM,程序退出,一定要把该文件删除
4.判断
isFile();文件
isDirectory();目录
isAbsolute(); 绝对路径
exists();判断File封装的对象是否存在
canExecute();判断文件是否执行
File f=new File(path);
Runtime r=Runtime.getRuntime();
if(f.canExecute()) r.exec(path);
注意:File f=new File("xx.txt");格式为xx.txt不一定是文件,也可能是文件夹。
5.获取
getPath();相对路径
getAbsolutePath();绝对路径
getParent();父目录
getName();文件名
length();返回该文件字节数,只对文件而言,文件夹没有
lastModified();最后一次修改的时间
服务器配置文件就是的,设一条线程,隔几秒监控是否改变
File f1=new File("qq.txt");
File f2=new File("ww.txt");
6.重命名 f1.renameTo(f2);将f的文件名改成ff的文件名,
可以进行文件的移动(剪切+全命名)
7.文件列表
File[] roots=File.listRoots();获取系统可用盘符
for(File root: roots){}
File dir=new File("c:\\");获取当前目录下得文件夹和文件的名称
包括隐藏文件,如果是文件的话,就返回null
String [] names=dir.list();
String[] list();只获取名称
File[] listFiles();获取当前目录下文件或文件夹的对象
8.获取mp3文件
实现FilenameFilter接口,accept方法 return name.endWith(".mp3");
return new File(dir,name).isFile() && name.endsWith(".mp3");
首先必须是文件
获取指定目录下所有的文件和文件夹,包括子目录中的内容:递归
五、字符编码
ASCII用一个字节7位表示
GB2312中文编码表,六千多字
GBK中文编码表升级,两万多字,中文两个字节,最高位都是1
Unicode国际标准码,Java使用的Unicode
UTF-8最多用三个字节表示一个字符
编码:字符串——>字节数组
解码:字节数组——>字符串
例如:abc你好cd
对字符串进行字节个数截取,如果出现半个中文,舍弃
1.判断最后一个被截取的字节是不是负数
2.如果是负数,继续往前判断,连续负数的个数
3.如果是偶数,说明没半个中文,不用舍弃
4.如果是奇数,说明出现半个中文,舍弃最后一个字节
gbk一个中文两个字节,有的字节可能正数
gb2312一个中文两个字节都是负数