IO总结
关于流的概念及作用:
流是一种有起始点的字节集合,对数据进行传输的总称,流的本质就是数据传输
它的作用就是为了方便进行更为直观的数据传输
IO流中的四大基类:
|
字节流 |
字符流 |
输入流 |
InputStream |
Reader |
输出流 |
OutputStream |
Writer |
Io流中的所有类均是继承自这四大基类
按照输入输出的方向来分:
输入流:InputStream Reader; 输出流: OutputStream Writer
按照操作文件的形式来分:
字节流:InputStream OutputStream; 字符流:Reader Writer
输入与输出指的是硬盘对于内存的方向来说:
内存读取硬盘中的数据 ——>读取的过程,即输入流
从内存中把数据存入硬盘——>写的过程,即输出流
字节流与字符流的区别:
字符流的底层也就是字节流, 字符流 = 字节流 + 编码表
如果只是操作文本文件(能用记事本打开的文件),那么就使用字符流操作
否则,就使用字节流进行操作(操作二进制文件)
输入流与输出流:
对输入流只能进行读的操作,对输出流只能进行写的操作,输入输出根据需要待传输的
数据的不同特性而使用不同的流
字节输入流(InputStream)
InputStream是所有字节输入流的父类,所有的字节输出流均是继承自它,它是一个抽象类
这些都是InputStream的直接子类
AudioInputStream, ByteArrayInputStream,FileInputStream, FilterInputStream, InputStream, ObjectInputStream, PipedInputStream, SequenceInputStream, StringBufferInputStream
方法(常用)
int |
available() |
void |
close() |
int |
read() |
int |
read(byte[] b) |
|
read(byte[] b, int off, int len) |
|
方法的详细用法:
available():
返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数
应用:传到字节缓冲区中
byte [] buffer = new byte[fileinput.available()];
read():
从输入流中读取数据的下一个字节。如果到达流末尾而没有可用的字节,则返回值 -1。
read(byte [] b):
从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。以整数形式返回实际读取的字节数。(读完数组的长度再进行储存,必须要判断数组的长度不为空,否则会报IO异常)
read(byte[] int off,int len):
只读取数组的一部分(读到指定的长度)
close():
关闭流,释放系统资源(避免资源浪费)
字节输出流(OutputStream)
字节输出流OutputStream是所有字节输出流的父类,字节输出流都是继承自它,它是一个抽象类
OutputStream的直接子类
ByteArrayOutputStream, FileOutputStream, FilterOutputStream, ObjectOutputStream, OutputStream, PipedOutputStream
方法:
void |
close() |
void |
flush() |
void |
write(byte[] b) |
void |
write(byte[] b, int off, int len) |
|
write(int b) 将指定的字节写入输出流 |
close():
关流,释放资源
write(int b):
将指定的字节写入输出流
write(byte [] b):
将b.length个字节从指定的数组中写入输出流
write(byte [] b,int off,inr len):
将数组中的一部分写入输出流
flush():
刷新输出流
字符输入流(Reader)
字符输入流Reader:用于读取字符流的抽象类。
Reader的直接子类:
BufferedReader, CharArrayReader, FilterReader, InputStreamReader, PipedReader, StringReader
构造方法(决定了以什么样的方式初始化)
protected |
Reader() |
protected |
方法(常用):
abstract void |
close() |
void |
mark(int readAheadLimit) |
boolean |
markSupported() |
int |
read() |
int |
read(char[] cbuf) |
abstract int |
read(char[] cbuf, int off, int len) |
int |
read(CharBuffer target) |
boolean |
ready() |
字符输出流(Writer)
字符输出流Writer是所有字符输出流的父类,它是一个抽象类。
Writer的直接子类:
BufferedWriter, CharArrayWriter, FilterWriter, OutputStreamWriter, PipedWriter, PrintWriter, StringWriter
构造方法(决定了它将以什么样的方式初始化)
protected |
Writer() |
|
protected |
||
方法: |
|
|
append(char c) |
||
append(CharSequence csq) |
||
append(CharSequence csq, int start, int end) |
||
abstract void |
close() |
|
abstract void |
flush() |
|
void |
write(char[] cbuf) |
|
abstract void |
write(char[] cbuf, int off, int len) |
|
void |
write(int c) |
|
void |
||
void |
方法同与字节输出流
BufferedReader(高效,自带缓冲区)
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
可以指定缓冲区的大小
构造方法:
BufferedReader(Reader in) |
BufferedReader(Reader in, int sz) sz - 输入缓冲区的大小
|
独有的方法:
readLine:
一次读一行
BufferedWriter(高效自带缓冲)
构造方法:
BufferedWriter(Writer out) |
BufferedWriter(Writer out, int sz) |
主要方法:
newline:
写入一个行分隔符(换行)—>在Windows中的换行符为‘ \ r \ n’
/*
* 拷贝二进制文件的几种方式和时间比较
*/
long start = System.currentTimeMillis(); //系统时间毫秒值
1.available返回文件从输入流读取的剩余字节数 44ms
2.使用Buffered+字节数组缓冲区 34ms / Buffered +字节 515ms
3.使用字节数组做为缓冲区 57ms/ 按字节读写 95103 ms
由此可见:使用高效buffered+缓冲性能是最高的
转换流(InputStreamReader OutputStreamWriter)
这两个流对象本质上属于字符流(具有转换功能的字符流),所以在构造的时候需要传入字节流对象进来。
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。直接已知子类是FileReader
OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。 直接已知子类是FileWriter
装饰设计模式
就是对原有类的包装,增强其功能
与继承的区别:比继承更简单高效(代码量更少,使用更方便)
把需要增强的功能封装起来,需要调用时直接调用即可
装饰类和被装饰的特点:
1,装饰类中的构造函数需要接受被装饰类。
2,装饰类和被装饰类应该所属于同一个体系。
如:对流对象的功能增强,增强写的效率
自定义一个实现缓冲的类,继承此类的功能再进行增强
File类
文件和目录路径名的抽象表示形式。
File类是对硬盘中文件以及文件夹进行封装的对象,File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件列表,创建、删除文件和目录等方法。
File 类的实例是不可变的;也就是说,一旦创建,File 对象表示的抽象路径名将永不改变。
pathSeparator:与系统有关的路径分隔符(带“;”)
separator:与系统有关的默认名称分隔符(“File.separator”)
在不同的操作系统上的路径分隔符与名称分隔符的写法都是不同的,使用separator来通配路径分隔符(在Windows上的路径分隔符是“\\”,在Linux操作系统上则是“//”)
构造方法:
File(File parent, String child) |
File(String parent, String child) |
常用的构造方法:
File(String pathname):
通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。
(pathname —路径名字符串)
boolean |
delete() |
boolean |
exists() |
getAbsolutePath() |
|
getName() |
|
boolean |
isDirectory() |
boolean |
isHidden() |
String[] |
list() |
String[] |
list(FilenameFilter filter) |
File[] |
listFiles() |
File[] |
listFiles(FileFilter filter) |
File[] |
listFiles(FilenameFilter filter) |
boolean |
mkdir() |
toString() |
File常用的方法:
createNewFile 创建新文件
mkdir 创建新目录
mkdirs 创建多级目录
delete() 删除
exists() 判断是否存在
isDirectory() 是否为目录
isFile() 是否为文件
list:返回目录名称
listFiles:返回目录的路径及名称
文件过滤器
FilenameFilter——>文件名过滤器
FileFilter ——> 文件过滤器
文件过滤器(FilenameFilter/FileFilter)为接口,能够过滤得到指定类型的文件或者目录,但必须重写accept(File file,String path)方法,需要实现FilenameFilter接口
步骤:
1.先判断File是否目录(isDirectory)
2.通过list()方法得到这个目录下所有的文件和目录的名称数组,
3.“超级过滤器”:创建一个私有有参构造,然后使用list()的带参构造,返回以此私有方法为后缀的文件
class XFiltx implements FilenameFilter{
private String suffix;
public XFiltx(String suffix) {
super();
this.suffix = suffix;
}
@Override
public boolean accept(File dir, String name) {
return name.endsWith(suffix);
}
}
ByteArray
FileInputStream : 输入流,内容是从文件里读出来的
ByteArrayInputStream: 内容是存在这个流内部的缓冲区里的
FileOutputStream 是写入到了文件里,来存放写入的数据, 数据在磁盘上
ByteArrayOutputStream 里边有个byte类型的数组,用来缓存你所写入的数据,数据在内存里,他就相当于一个长度可变的byte数组
数组流使用完后可不必关
Properties类
Properties直接继承自hashtable(是hashmap的老哥)
Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。即:hashtable<K,V>,k v都是字符串类型
Properties类 是集合与IO相关的方法
构造方法:
Properties() |
Properties(Properties defaults) |
常用方法是使用空参构造来初始化对象。
常用方法:
getProperty(String key) |
|
getProperty(String key, String defaultValue) |
|
void |
list(PrintStream out) |
void |
list(PrintWriter out) |
void |
load(InputStream inStream) |
void |
load:
按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。
getPeoperties:
用指定的键在此属性列表中搜索属性。如果在此属性列表中未找到该键,则接着递归检 查默认属性列表及其默认值。如果未找到属性,则此方法返回 null。
list:(此list非彼list,这个list是在Properties类中重写,属于Properties的特有方法)
将属性列表输出到指定的输出流。此方法对调试很有用。
打印流
字节打印流 ——>PrintStream
字符打印流 ——>printWriter
打印流可以打印所有数据类型:小数,整数,字符/串,以及乱码;
构造方法:
PrintStream(File file) |
PrintStream(File file, String csn) |
PrintStream(OutputStream out) |
PrintStream(OutputStream out, boolean autoFlush) |
PrintStream(String fileName) |
PrintWriter(String fileName, String csn)(最实用) |
常用的构造:
PrintStream(String fileName) :
PrintStream ps = new PrintStream(
new FileOutputStream(new File("f:"+File.separator+"a.txt")));
方法:
append(char c) |
|
append(CharSequence csq) |
|
append(CharSequence csq, int start, int end) |
|
void |
close() |
void |
flush() |
void |
print(boolean b) |
void |
print(char c) |
void |
print(char[] s) |
void |
print(double d) |
void |
print(float f) |
void |
print(int i) |
void |
print(long l) |
void |
|
void |
|
void |
println() |
void |
println(boolean x) |
void |
println(char x) |
void |
println(char[] x) |
void |
println(double x) |
void |
println(float x) |
void |
println(int x) |
void |
println(long x) |
void |
|
void |
|
void |
write(byte[] buf, int off, int len) |
void |
write(int b) |
常用方法:
print和println:直接打印(区别换行与不换行)
方法2:
1)使用键盘录入
2)初始化pintWriter(使用匿名对象,true)
3)缓冲—>String line = null;
4)输出—>pw.println(line);
序列化与反序列化
把对象转换为字节序列的过程称为对象的序列化。
把字节序列恢复为对象的过程称为对象的反序列化。
对象的序列化主要有两种用途:
1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
2) 在网络上传送对象的字节序列。
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象(就是把对象转换成字节序列化存储到硬盘,然后反序列化把硬盘上的字节序列再读取到硬盘中)
ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
构造方法:
protected |
ObjectOutputStream() |
|
ObjectOutputStream(OutputStream out) |
方法:
writeObject:将指定的对象写入 ObjectOutputStream
接口:
Serializable(表示对象可序列化,用到了标记设计模式)
要写入可通过 ObjectOutputStream 中的示例读取的对象,需执行以下操作:
FileOutputStream fos = new FileOutputStream("t.tmp");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeInt(12345);
oos.writeObject("Today");
oos.writeObject(new Date());
oos.close();
ObjectInputStream是InputStream的子类,继承了它的方法
序列版本号(两种方式):
private static final long serialVersionUID = 1L;
private static final long serialVersionUID = -1308681642922066213L;
步骤:
1)创建一个文件输出流对象
2)用ObjectOutputStream来初始化这个fileoutputstream
3)写入要序列化的内容:
oos.writeObject(new Person("Jack",22));
4)关流
反序列化:
ObjectInputStream:将字节序列化恢复成对象
方法:
ReaderObject:从 ObjectInputStream 读取对象
步骤:
1)创建一个文件输入流来读取之前存储序列化的文件
2)用ObjectOutputStream来初始化这个fileinputstream
3)使用自定义类来定义对象接收读取到的序列化数据
Person p = (Person)ois.readObject();
4)在输出中转换成字符串类型
System.out.println(p.getName() + "," +p.getAge());
5)关流
Transient关键字
在序列化时自定义的类必须要实现seializable接口,但方法被transient关键字修饰后将不会再被序列化
private transient String name;
但是
如果实现 Externalizable接口,则不论是否被transient修饰都会被序列化
切割文件
SplitFile:
步骤:
1)读取文件(InputStream)
2)创建空的文件输出流(用于输出切割后的文件)
3)建立一个字节缓冲区(存满就切,这个缓冲的数组多大的切割的文件就多大)
4)定义数组长度,一个计数器
5)创建一个新的目录来存储切割后的文件(判断有无,否则创建)
6)在循环内输出,将它们存储在指定文件中
7)关流
合并流(SequenceInputStream)
把两个文件合并成一个文件
一.将要合并的多个文件的输入流存入集合
二.用集合返回Enumeration接口
步骤:
1)把输出流给存入到定义的集合中
2)把集合返回Enumeeration接口(使用了工具类Collections中的enumeration方法)
3)用SequenInputStream来初始化Enumertion接口
4)输出流输出到文件中(创建文件及路径)
5)建立一个字节缓冲区
6)在循环中输出
7)关流