一.流的分类java
1.java.io包中的类对应两类流,一类流直接从指定的位置(如磁盘文件或内存区域)读或写,这类流称为结点流(node stream),其它的流则称为过滤器(filters)。过滤器输入流每每是以其它输入流做为它的输入源,通过过滤或处理后再以新的输入流的形式提供给用户,过滤器输出流的原理也相似。node
2.Java的经常使用输入、输出流数组
java.io包中的stream类根据它们操做对象的类型是字符仍是字节可分为两大类:字符流和字节流。网络
2.1Java的字节流:框架
InputStream是全部字节输入流的祖先,而OutputStream是全部字节输出流的祖先dom
2.2Java的字符流:jvm
Reader是全部读取字符串输入流的祖先,而writer是全部输出字符串的祖先。函数
结合开始所说的输入/输出流 ,出现了个一小框架。性能
JAVA字节流:this
FileInputStream和FileOutputStream
这两个类属于结点流,第一个类的源端和第二个类的目的端都是磁盘文件,它们的构造方法容许经过文件的路径名来构造相应的流。
FileInputStream infile = new FileInputStream("myfile.dat"); FileOutputStream outfile = new FileOutputStream("results.dat");
要注意的是:构造FileInputStream,,对应的文件必须存在而且是可读的,而构造FileOutputStream时,如输出文件已存在,则必须是可覆盖的。
BufferedInputStream和BufferedOutputStream:
它们是过滤器流,其做用是提升输入输出的效率,对于FileInputStream当调用read()方法(每次读取一个字节
)时都要从硬盘中获取数据,对性能有必定影响,因此就须要使用缓冲流:从本身内存中的字节数组中读取数据,默认一次读8192个字节
DataInputStream和DataOutputStream:
这两个类建立的对象分别被称为数据输入流和数据输出流。这是颇有用的两个流,它们容许程序按与机器无关的风格读写Java数据。因此比较适合于网络上的数据传输。这两个流也是过滤器流,常以其它流如InputStream或OutputStream做为它们的输入或输出。这两种流失对流的扩展,能够更加方便的读取int,long,字符等类型的数据,好比:DataOutputStram:中增长了writeInt()/writeDouble()/writeUTF()方法
public class Main { public static void main(String[] args) throws IOException { String file="a.txt"; DataOutputStream dos=new DataOutputStream(new FileOutputStream(file)); dos.writeInt(10); dos.writeLong(10l); dos.writeUTF("中国");//采用UTF-8编码写入 dos.writeChars("中国");//采用utf-16be方式写入 dos.close(); } }
RandomAccessFile的基本介绍和操做:
RandomAccessFile是Java提供的对文件内容的访问,既能够读文件,也能够写文件,而且能够随机访问文件,便可以访问文件的任意位置,它在访问文件时会有一个文件指针,在访问过程当中会向后移动
File demo=new File("demo"); if(demo.exists()){ demo.mkdir();//若是文件夹不存在则建立 } File file=new File(demo,"a.txt");//以demo为目录建立a.txt文件 if(file.exists()){ file.createNewFile();//若是文件不存在则建立新的文件 } RandomAccessFile raf=new RandomAccessFile(file,"rw");//rw是文件模式中的可读写模式 System.out.println(raf.getFilePointer());//获得指针的位置为0 raf.write('A');//写入'A'的后八位(每次只写一个字节),指针后移一位 int i=15; raf.write(i>>>24);//写入高八位 raf.write(i>>>16);.....每次写一个字节,要写四次 raf.writeInt(i);//直接写入一个int类型数据 String s="中国"; byte[] gbk=s.getBytes("gbk"); raf.write(gbk); raf.seek(0);//读文件 ,必须把指针移到头部 byte[] buf=new byte[(int)raf.length()];//一次性读取,把文件中的内容都读到字节数组中去 raf.read(); System.out.println(Arrays.toString(buf));
字符流主要是用来处理字符的,Java采用16位的Unicode来表示字符串和字符,对应的字符流按输入和输出分别称为Reader和writer(一次处理一个字符,字符的底层仍然是基本的字节序列)
FileReader和FileWriter:
FileReader(读文件类):
其直接父类就是InputStreamReader类
FileReader a=new FileReader("C:\\Users\\admin\\Desktop\1.txt");//注意:不能修改编码集,即便用默认编码集
FileWriter:
其直接父类为OutputStreamWriter类
FileWriter a=new FileWrite("C:\\Users\\admin\\Desktop\1.txt",true);//加true参数表示在第二次写入文件时是追加内容
InputStreamReader和OutputStreamWriter:
1.将字节流转化为字符流(解码):
FileInputStream f==new FileInputStream("D:\\test.txt");; InputStreamReader f1=f1=new InputStreamReader(f,"UTF-8");//设置字符编码为UTF-8,默认项目的编码为gbk //读取数据(一个字符一个字符的读取): int c; while((c=f1.read())!=-1){ System.out.println((char)c); } //批量读取(放入buffer这个字符数组,从0开始放置,最多放buffer.length个,返回的是读到的字符个数): char[] buffer=new char[8*1024]; while((c==f1.read(buffer,0,buffer.length))!=-1){ String s=new String(buffer,0,c); }
2.将字符流转化为字节流(编码):
FileOutputStream fos=new FileOutputStream("D:\\test.txt"); OutputStreamWriter osw=new OutputStreamWriter(fos,"UTF-8");
BufferedReader和BufferedWriter:
这两个类对应的流使用了缓冲,能大大提升输入输出的效率,这两个也是过滤器流,经常使用来对InputStreamReader和OutputStreamWriter进行处理,如:
public class Echo { public static void main(String[] args) throws IOException{ BufferedReader in =new BufferedReader(new InputStreamReader(System.in)); BufferedWriter bw=new BufferedWriter(mew FileOutputStream("d:\\test.txt")); String s; while((s = in.readLine()).length() != 0){ System.out.println(s);//一次读一行,并不能识别换行 bw.write(s); bw.newLine();//换行操做 bw.flush();//注意必定要添加这行代码,才能写入缓冲区中 } bf.close(); bw.close(); }
BuffferedReader和BufferedWriter之mark()
(方法标记流中的当前位置,调用reset()
将从新定位流)的使用:
public class Test{ public static void main(String[] args) throws IOException{ FileReader fr=new FileReader("D:\\test.txt"); BufferedReader br=new BufferedReader(fr,1000);//1000为缓冲区大小 br.mark(1000);//参数要不小于缓冲区大小,字符流须要设置,而字节流的mark会默认在起始位置 第一种方式读取: int c=0; c=br.read(); while(c!=-1){ System.out.println((char)c); c=br.read(); } 第二种方式读取: br.reset();//再读一次须要重置 String str=br.readLine(); while(str!=null) { System.out.println(str); str=br.readLine(); } }//注意关闭流最好在finally中进行 }
transient和ArrayList源码解析:
private transient int age;//该元素不会进行jvm的默认序列化,但也能够本身完成这个元素的序列化 ObjectOutputStream s; s.defaultWriteObject();//把jvm默认能序列化的元素进行序列化操做 s.writeInt(age);//本身完成age的序列化 ObjectInputStream s; s.defaultReadObject();//把jvm中默认能进行反序列化的元素进行反序列化 this.age=s.readInt();//本身完成age的反序列化操做
经过对ArrayList源码列表的分析能够知道,ArrayList中会对其中的有效元素进行序列化和反序列化以提升性能
序列化中子父类构造函数问题:
在序列化中若父类是实现了序列化接口,子类能够不用实现序列化接口,能够直接进行序列化,子类在序列化过程当中会递归的调用父类的构造方法
注意:对子类对象进行反序列化操做时,若是其父类没有实现序列化接口,那么其父类的构造函数会被显示调用,不然就不会调用