黑马程序员——JAVA学习笔记十(IO)
1, 可以从其中读入一个字节序列的对象成为输入流,可以向其中写入一个字节序列的对象就做输出流。这些字节序列的来源地可以是文件,也可以是网络连接或者内存块。抽象类InputStream和OutputStream构成了I/O层次的基础。因为字节流不便于处理以Unicode存储的信息,所以有了Writer和Reader抽象类,这些从其中继承的类都是读入和写入基于2个字节的Unicode码元,而不是单个字节。
2, InputStream 与OutputStream:
abstract int read(): 读入一个字节,读到末尾返回-1,在具体类中,必须覆盖它。还有读入一个字节数组,或者跳过大量的字节。这些都是调用它。
absract void wirte(int b): 输出一个字节,它们都是阻塞调用。
int available()方法使我们去检查当前可以读入的字节数量。类 InputStream 的 available 方法总是返回 0,此方法应该由子类重写。
close() 完成读写后需要关闭流,释放十分有限的系统资源。关闭一个流时,还会冲刷该输出流的缓冲区,因为有时候被临时置于缓冲区中,以便用更大的包的形式传递的字符在关闭输出流时将被送出。
long skip (long n) 再输入流跳过N个字节。
3, Writer 与 Reader:
对于Unicode文本可以使用他们的子类。
abstract int read()(0~65535),末尾返回-1;
abstract void write() 写入一个码元
还有四个附加接口:Closeable、 Flushable、Readable、Appendable、前两个接口分别用用以下方法:
void close() throws IOException
和 void Flush()
InputStream OutputStream Reader Writer都实现了closeable(try 资源)
OutputStream 和Writer实现了Fulshable接口,
Readable 接口:int read(CharBuffer cb)CharBuffer类拥有按顺序和随机的读写访问方法,它表示一个内存中缓冲区或者内存映像文件。
Appendable: Appendable append(char c)
Apppendable append(CharSequence s)charSequence接口描述了一个char值序列的基本属性,String charbuffer、 SringBuilder和StringBuffer都实现了它。
只有writer实现了它。
四个接口关系图:
4,组合流过滤器:
FileInputSteam和FileOutStream可以提供附着在磁盘文件(可以在末尾添加),但是只能读入写出字节或者字节数组。java使用了一种灵巧的机制来分离这两种职责。有的流负责从文件或者外部获取字节流,而其他的流可以将字节数组组成其它类型。所以程序员必须对两者进行组合。
FileInputStream和FileterOutputStream这些类的子类向原生字节流添加更多的功能。
字节流默认情况是不会缓冲的,每个read,write调用都会请求操纵系统分发一个字节。
LineNumberReader 行号字符流
BufferedInputStream BufferedOutputStream 字节流缓冲
DataInputStream DataOutputStream 数字流
PushBackInputStream 栈字节流
OutputStreamWriter类将使用选定的字符编码方式,把Unicode字符流转化为字节流,而InputStreamReader类将包含字节(用某种字符编码方式表示的字符)的输入流转为字符流。
system.in 为inputstream类型
system.err system.out 为PrintStream
文本输出:
PrintWriter 如果写出器需要自动冲刷模式,那么只要println被调用,缓冲区的所有字符都会被发送到他们的目的地。与 PrintStream 类不同,如果启用了自动刷新,则只有在调用 println、printf 或 format 的其中一个方法时才可能完成此操作,而不是每当正好输出换行符时才完成。这些方法使用平台自有的行分隔符概念,而不是换行符。
PrintStream 为了自动刷新,可以创建一个 PrintStream;这意味着可在写入 byte 数组之后自动调用 flush 方法,可调用其中一个 println 方法,或写入一个换行符或字节 ('\n')。
PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类。
文本输入:
Scaner BufferedReader 文本一整行输入
5, 字符集:charSet类统一了对字符集的转换。
Set<String> alias(),返回字符集的别名集合
forName(String name),返回某个字符对象
availableCharsets(),字符集是否可用
编码字符串:
Stirng str = .....;
ByteBuffer buffer = cset.encode(str);
byte[] bytes = buffer.array();
解码字符串:
byte[] bytes = ...;
ByteBuffer bbuf = ByteBuffer.wrap(bytes, offset, length);
CharBuffer cbuf = cset.decode(bbuf);
String str = cbuf.toString();
6, 读写二进制数据:DataOutput和DataInput接口:接口定义了一下方法:
write(read)Chars
writeBytes
wirteInt
writeShort
writeLong
writeDouble
writeChar
writeBoolean
writeUTF
略过:
7, 随机访问文件:RandomAccessFile类可以在文件中的任何位置查找或写入数据。磁盘文件是随机写入,但是从网络而来的数据却不是。可以通过字符串"r" "rw" "w"来打开文件。其实现了Datainput DataOutput接口。
void seek(long pos)
long getFilePointer()
ZipInputStream ZipOutputStream压缩文档类:
8, 对象流以及序列化:将对象写入流中,并在之后将其读回。
wrteiObject(Object obj)
Object read ()
对希望在对象流中存储或恢复的所有类都应该进行一下修改,这些类都必须实现Serializable接口,没有任何方法。
每个对象都使用一个序列号保存的,这就是这种机制之所以称为对象序列化的原因,算法如下。
写对象时:
对你遇到的每一个对象引用都关联一个序列号
对于每个对象,当第一次遇到时,保存其对象数据到流中
如果某个对象之前已经被保存过,那么只写出“与之前保存过得序列号为X的对象相同”。
再读回来时,整个过程是相反的:
对于流中的对象,在第一次遇到其序列号时,构建它,并使用流中数据来初始化它,然后记录这个顺序号和新对象之间的关联。
当遇到“与之前保存过的序列号为x的对象相同”标记时,获取与这个顺序号相关联的对象引用。
某些数据是不可以被序列化的,那么将他们标记成transient的,static也是不可被序列化的。
可序列化的类可以向默认的读写行为添加验证或其他行为。
private void readObject(OjbectInputStream in) throws IoException, ClassNotFoundException
private void writeObject(OjbectOutStream out) throws IoException, ClassNotFoundException
除了让序列化机制来保存和恢复数据,类还可以实现自己的机制,但是这个类必须实现Externalizable接口:
publc void readExternal(OjbectInputStream in) throws IoException, ClassNotFoundException
public void writeExteranl(OjbectOutStream out) throws IoException, ClassNotFoundException
要记住向遗留代码中所有类型安全的枚举以及向所有支持单列设计模式的类中添加readResolve方法,readObject默认会调用它,用它的返回值作为自己的返回值,保证唯一性。