3.java流

来源:互联网 发布:古代人有多高知乎 编辑:程序博客网 时间:2024/05/28 06:05
 .基本流概念:     创建流,则必须要关闭流。
源---->输入流   ------>  输出流----->目的地
源和目的地可以是文件、网络的口。
InputStream和OutputStream是输入输出的祖先,派生出了很多具体的流。
InputStream
(1)abstract int read();  //唯一一个抽象方法,从输入流中读取一个字节。需要被覆盖
(2)int read(byte[]b);    //基于抽象read方法写成的,所以不需覆盖。
(3)int read(byte[]b,int off,int len);//基于抽象read方法写成的,所以不需覆盖。
(4)int available();  //从输入流中能够读取的字节数
(5)void close();  //释放资源
OutputStream
(1)abstract void write(int n);
(2)void write(byte[]b);
(3)void write(byte[]b,int off,int len);
(4)void close();
(5)void flush();把缓冲区的数据强行送到输出流
Reader和Writer是以读取写入Unicode码的类。
2.各种常用流
(1)FileInputStream fin=new FileInputStream("...");
FileInputStream fin=new FileInputStream(new File("..."));
fin仍然是以字节输入输出的,fin.read();
(2)DataInputStream能够读取数值类型
DataInputStream din=new DataInputStream();
double d=din.readDouble();
-------但是如果想要从文件中读取数值类型,就会有困难,因为DataInputStream不支持从文件读取,因此可以把两个流结合起来,称为过滤流。
FileInputStream fin=new FileInputStream("...");
DataInputStream din=new DataInputStream(fin);
double d=din.readDouble();
这样就实现了从文件中读取一个浮点数值的方法。DataInputStream并没有与文件关联,而是fin把文件的字节都读出来,再方法din里去。
(3)PushbackInputStream支持预查看,即如果读取的字节你不想要,可以重新放回输入流。
read()和unread()为读取和放回。
-------把PushbackInputStream和DataInputStream结合可以实现预读取数值类型值。
DataInputStream din=new DataInputStream(new PushbackInputStream(new BufferedInputStream(new FileInputStream("..."))));
(4)ZipInputStream
-------把ZipInputStream、 FileInputStream、DataInputStream结合可以实现从zip文件中读取数值类型。
(5)BufferedInputStream 流从缓冲区读取,缓冲区从源读取。
(6)DataInput和DataOutput接口
DataInput是从字节中读取数值类型的字节数,比如要读int,则读取4字节。
readInt()\readFully(byte[]b)\readLine()
DataOutput是从从原本的数值类型转换成一系列字节,比如要写入int,则写入4字节。
我利用DataOutputStream写入数据,发现由于DataOutputStream是以二进制写入,但是写入后文本文件中是乱码,虽然读出后又恢复,没有数据丢失。
如果我们要写入一个int y,我们可以String s=new String(y+"");   out.writeBytes(s); 这样就可以写入文本后不出现乱码。


(7)RandomAccessFile实现了DataInput和DataOutput接口,因此功能上与DataOutputStream和DataInputStream相同。
有两种模式  r和rw    RandomAccessFile s=new RandomAccessFile("...","r"|"rw");
seek改变文件指针   getFilePointer()得到文件指针
s.length(); 返回文件长度
(8)InputStreamReader和OutputWriter能够把特殊的编码方案和Unicode互转。
InputStreamReader in=new InputStreamReader(InputStream,String s) ;//InputStream是一个输入源,以s编码制造InputStreamReader.
InputStreamReader in=new InputStreamReader(new FileInputStream("..."),"ISO-8859-1");这个流就是以iso-8859-1形式编码的,并且从文件流中读取。
OutputStreamWriter类似。
(9)FileWriter和FileReader继承(8)中两个类,实现从文件中读取或写入。
(10)Charset是unicode和某个特定的字符集映射的类。
Charset cset=Charset.forName("ISO-8859-1"); 就得到了unicode和ISO-8859-1的映射。
ByteBuffer buffer=cset.encode(str);  //将str转换成ISO-8859-1的编码形式。
byte[]b=buffer.array();
(11)PrintWriter和BufferedReader是文本格式的输入输出
PrintWriter是以文本格式写入目的流,但是没有指定目的流,但是一定要是继承于Writer类,如OutputStreamWriter,FileWriter。PrintWriter out=new PrintWriter(Writer); 
例如PrintWriter out=new PrintWriter(new FileWriter("..."));
利用out.Println()和out.print()就可以完成写入。
BufferedReader是文本格式读取输入流,输入流也是要自己指定的。BufferedReader in=new BufferedReader(new FileReader("..."));
有一个readLine()方法,读取一行。
while((str=in.readLine())!=null)
{
add into result;
}可以实现读取文件。
(12)ZipInputStream和ZipOutputStream    
ZipInputStream in=new ZipInputStream(new FileInputStream("..."));
ZipEntry是zip文件中的每个子文件的对象。
entry.getName()返回这个子文件的名称。
in.getNextEntry()返回下一个ZipEntry。
in.closeEntry()关闭当前对象,指向下一个子文件对象。
!!BufferedReader in=new BufferedReader(new InputStreamReader(zin)); //得到当前zin所指向的子文件的流
JarInputStream JarOutputStream是ZIP的子类


(13)流的应用:
StringTokenizer是能够将一个字符串以某个特定的分隔符分割。
StringTokenizer tokenizer=new StringTokenizer(String str,String token); token为分隔符,通常为|
String s1=tokenizer.nextToken(); //nextToken()返回下一个被分割的字符串。
tokenizer.hasMoreTokens() //判断后面还有没有分隔符。
文本格式输入输出
PrintWriter out=new PrintWriter(new FileWriter("..."));
out.println(.....); //写入
BufferedReader in=new BufferedReader(new FileReader("..."));
in.readLine();//读取一行
(14)ObjectInputStream和ObjectOutputStream
in.readObject();
out.writeObject(Object);  “Object包括数组和字符串”
写入的Object必须要实现Serialable接口。
序列化会帮你以最好的方式完成一切你担心的事。比如共享问题等。
规则:保存的对象都会有一个序列号,存储一个对象前需要检查是否已保存相同对象,如果保存了,则只需要写个引用即可。
对象流输出包含对象类型和数据域,每个对象都分配一个序列号,重复出现的同一个对象则存储引用。
序列化的文档中会有一个通过SHA算法生成一个指纹,这个指纹是根据类、属性、方法生成的,因此只要类的内容有一点变化,指纹就会变化,每次从序列化文档中恢复一个对象,都要进行指纹的比较。
自定义序列化:
(1)在不需要序列化的属性前面加transient.
(2)通过在实现Serialable的类中实现两个函数:
private void readObject(ObjectInputStream in)throws...
{
in.defaultReadObject();
...
}
private void writeObject(ObjectOutputStream out)throws...
{
out.defaultWriteObject();
...
}
在调用in.readObject和out.writeObject时会自动调用上面两个函数。


因为每次读取对象都会比较指纹,如果指纹不同,则不会进行读取。但是考虑一个程序总会有修改,serialVersionUID是指纹,因此如果程序被修改了,但是希望还能读取旧的对象,可以把serialVersionUID放在修改后的程序中,这样这个可以当作新程序的指纹。
想要获得一个类的serialVersionUID,只要执行serialver **class  即可。
(15)StringReader和StringWriter是以字符串作为源和目的。
StringReader r=new StringReader(String str)  str就是一个源。
3.StringBuilder和StringBuffer    为了解决String的拼接工作效率低, 存储着char[],最后需要toString转为String
在单线程中用StringBuilder
在多线程中用StringBuffer
(1)StringBuilder(String);
(2)builder.append(String);
(3)builder.insert(int offset,String str);
(4)toString();
4.利用序列化实现克隆:利用序列化写入,然后读出,就实现了深度克隆。
细节:实现Cloneable和Serializable接口。并覆盖public Object clone();
使用ByteArrayOutputStream bout=new ByteArrayOutputStream();
ObjectOutputStream out=new ObjectOutputStream(bout);  //就可以把对象读入ByteArrayOutputStream


ByteArrayInputStream bin=new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream out=new ObjectInputStream(bin);  //可以把bout的内容传给bin,然后读出
5.File类:管理文件。 File可以表示文件或目录,如果构造参数时给定的是目录,则File对象管理的是目录。  isDirectory()和isFile()判断是目录还是文件
一、目录
(1)file.mkdir(); 创建目录
(2)file.list()列出该目录下所有文件名
(3)file.list(fileFilter); 可以过滤一些文件,通过实现FilenameFilter接口,并实现public boolean accept(File dir,String name);  dir是目录,name是文件名
public EFilter implements FilenameFilter
{public boolean accept(File dir,String name){}   public EFilter(String suffix){}}
二、文件
(1)构造器
File file=new File("filename");
File file=new File("path","filename");
(2)File.seperator是文件分隔符
(3)file.createNewFile(); 创建file指定的文件。
(4)file.getCanonicalPath(); 获得规范的文件路径,我们可以不使用file.getAbsolutePath();
(5)file.getName();获得不包含路径的文件名
(6)file.getPath();获得包含路径的文件名
(7)file.length();返回长度
file.exists()是否存在这个文件
6.内存映射
将文件映射到内存,使得访问内存像访问数组一样。内存映射适用于超大文件,比如几十M.
访问文件有:InputStream、BufferedInputStream、RandomAccessFile、MappedByteBuffer
内存映射步骤:
(1)指定一个文件流 FileInputStream fin=new FileInputStream("...");
(2)设定这个文件流的通道: FileChannel channel=fin.getChannel();               int size=channel.size();获取通道中流的长度
(3)获得MappedByteBuffer:MappedByteBuffer buffer=channel.map(MODE,int begin,int length);  MODE=FileChannel.MapMode.READ_ONLY|READ_WRITE|PRIVATE
(4)访问数据 buffer.get(i);  buffer.put(byte); buffer.getInt()   buffer.putInt(int)   
为了验证内存映射文件的完整,用java.util.zip.CRC32   
CRC32 crc=new CRC32();
crc.update(int c); 根据这个字节更新校验码
crc.getValue(); 获得校验码
7.缓冲区Buffer
缓冲区存放的是一种类型的数据,比如IntBuffer,ByteBuffer,CharBuffer,有一个position指向下一个读取或写入的位置,capacity是不变的容量,limit是限制。
初始时,position=0,capacity=limit
flip()准备缓冲区读取,position=0,limit=capacity
clear()准备缓冲区写入,position=0,limit=capacity
get()
put()
对于CharBuffer,get()得到一个char   对于ByteBuffer,得到一个Byte
put也是如此。
8.计算当前时间
long time=System.currentTimeMillis();  返回为毫秒
序列化文件格式:
72   类描述开始标记
..
..
78   结束标记
70   无超类


74    表示字符串
75    表示数组
73    表示对象存储
71    表示引用已存在的相同类描述符