数据流的方向可以分为:输入流,输出流。输入和输出是针对内存来说的,从内存中出来就是输出,到内存中去就是输入。
读取数据的方式可以分为:字符流,字节流。字节流按照字节的方式的读取,字符流按照字符的方式读取,也就是一次读取两个字节,因为java中一个字符占两个字节。
那么什么情况下使用字节流?当读取图片、声音、视屏等二进制文件的时候,不过如果是纯文本的时候也是可以用字节流的!字节流万能的。
当读取纯文本的时候用字符流!那么读Word文档要用什么?Word文档不光有文字还有格式,所以不是纯文本,要用字节流。
Java中所有字节流都以Stream结尾,所有的字符流都含有Reader或者Writer
InputStreamReader、OutputStreamWriter 属于转换流,字节流转字符流
FileInputStream
文件字节输入流,按照字节方式读取文件。在D盘新建文件IOTest.txt,内容为abcde123456789
package iotest; import java.io.FileInputStream; /** * Created by Arenas on 2016/10/28. */ public class IOTest01 { public static void main(String[] args) throws Exception{ FileInputStream fis = new FileInputStream("D:/IOTest.txt"); //available()返回流中剩余的估计字节数 System.out.println(fis.available()); //14 System.out.println(fis.read()); //97 System.out.println(fis.available());//13 //跳过两个字节 fis.skip(2); System.out.println(fis.read()); //100 fis.close(); } }
FileOutputStream
package iotest; import java.io.FileOutputStream; /** * Created by Arenas on 2016/10/28. */ public class IOTest02 { public static void main(String[] args){ FileOutputStream fos = null; try{ //直接添加,会覆盖原有内容 //如果该文件不存在,则会创建一个文件 // fos = new FileOutputStream("D:/IOTest.txt"); //以追加的方式添加到文件中 fos = new FileOutputStream("D:/IOTest.txt" , true); String str = "Hello World!"; //将String转换成byte数组 byte[] bytes = str.getBytes(); //将btyes中数据全部写入 // fos.write(bytes); fos.write(bytes , 3 , 2);//去掉前面三个,从第四个开始数两个数写入,也就是追加lo //推荐最后为了将数据完整的写入硬盘,执行flush() fos.flush();//强制写入 }catch (Exception e){ e.printStackTrace(); }finally { try{ if (fos != null) fos.close(); }catch (Exception e){ e.printStackTrace(); } } } }
字节流的文件的复制粘贴
package iotest; import java.io.FileInputStream; import java.io.FileOutputStream; /** * Created by Arenas on 2016/10/28. */ public class IOTest04 { public static void main(String[] args) throws Exception{ FileInputStream fis = new FileInputStream("D:/iopic.jpg"); FileOutputStream fos = new FileOutputStream("D:/newiopic.jpg"); byte[] bytes = new byte[1024]; int length; while ((length = fis.read(bytes)) != -1){ fos.write(bytes , 0 , length); } fis.close(); fos.close(); } }
FileReader
package iotest; import java.io.FileReader; /** * Created by Arenas on 2016/10/28. * java.lang.Object 继承者 java.io.Reader 继承者 java.io.InputStreamReader 转换流:字节流--->字符流 继承者 java.io.FileReader 文件字符输入流 */ public class IOTest05 { public static void main(String[] args){ FileReader reader = null; try{ reader = new FileReader("D:/IOTest.txt"); char[] chars = new char[512];//1kb,因为是读字符,所以用char而不是byte int length; while ((length = reader.read(chars)) != -1){ System.out.println(new String(chars , 0 , length)); } }catch (Exception e){ e.printStackTrace(); }finally { try{ if (reader != null) reader.close(); }catch (Exception e){ e.printStackTrace(); } } } }
字符流的文件复制和粘贴
package iotest; import java.io.FileReader; import java.io.FileWriter; /** * Created by Arenas on 2016/10/28. * 注意只能操作纯文本 */ public class IOTest06 { public static void main(String[] args) throws Exception{ FileReader reader = new FileReader("D:/IOTest.txt"); FileWriter writer = new FileWriter("D:/newIOTest.txt"); char[] chars = new char[512]; int length; while ((length = reader.read(chars)) != -1) writer.write(chars , 0 , length); writer.flush(); reader.close(); writer.close(); } }
BufferedReader
package iotest; import java.io.BufferedReader; import java.io.FileReader; /** * Created by Arenas on 2016/10/29. * BufferedReader */ public class IOTest07 { public static void main(String[] args) throws Exception{ //根据流出现的位置,又可以分为包装流(处理流)、节点流 //比如这里fileReader是一个节点流,bufferedReader是一个处理流,相当于在管子外面套了缓存区 FileReader fileReader = new FileReader("D:/剪刀手爱德华.txt"); BufferedReader bufferedReader = new BufferedReader(fileReader); String str; while ((str = bufferedReader.readLine()) != null) System.out.println(str);//readLine()方法读取一行,但是行尾不带换行符!!所以要换行需要println() bufferedReader.close();//这里关闭只要关闭最外面的包装流,这里有一个装饰者模式 } }
关于节点流和包装流
package iotest; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStreamReader; /** * Created by Arenas on 2016/10/29. */ public class IOTest08 { public static void main(String[] args) throws Exception{ FileInputStream fis = new FileInputStream("D:/IOTest.txt");//文件字节输入流 InputStreamReader isr = new InputStreamReader(fis);//将字节流转换成字符流 BufferedReader reader = new BufferedReader(isr); //这里fis相对于isr来说,fis是节点流,isr是包装流 //而isr相对于reader来说,isr又是节点流,reader是包装流 //所以包装流和节点流是相对来说的 } }
DataInputStream/DataOutputStream
package iotest; import java.io.DataOutputStream; import java.io.FileOutputStream; /** * Created by Arenas on 2016/10/30. * DataOutputStream,数据字节输出流,这是一个比较特殊的流 * 可以将内存中 int i = 10 写到文件中,但是写进去的不是字符串,而是二进制数据,并且是带类型的!!! */ public class IOTest09 { public static void main(String[] args) throws Exception{ DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:/IOTest.txt")); dos.writeByte(1); dos.writeBoolean(false); dos.writeInt(3); dos.writeDouble(3.3); dos.writeFloat(3.4f); dos.flush(); dos.close(); } }
文件的数据直接打开是乱码,要用对应的DataInputStream来读
package iotest; import java.io.DataInputStream; import java.io.FileInputStream; /** * Created by Arenas on 2016/10/30. */ public class IOTest11 { public static void main(String[] args) throws Exception{ DataInputStream dis = new DataInputStream(new FileInputStream("D:/IOTest.txt")); //这里去读取数据的顺序必须跟写进去的顺序相同,不能多读,不然会抛出java.io.EOFException byte b = dis.readByte(); boolean flag = dis.readBoolean(); int i = dis.readInt(); int i1 = dis.readInt(); double d = dis.readDouble(); // float f = dis.readFloat(); System.out.println(b); System.out.println(flag); System.out.println(i); System.out.println(i1);//1074423398 d和i1都错了 虽然d是对应的正确的类型!! System.out.println(d);//1.9035983735196154E185 // System.out.println(f); dis.close(); } }
PrintStream/PrintWriter
package iotest; import java.io.FileOutputStream; import java.io.PrintStream; /** * Created by Arenas on 2016/10/30. * java.io.PrintStream;标准的输出流,默认打印到控制台 * java.io.PrintWriter;以字符的方式 */ public class IOTest10 { public static void main(String[] args) throws Exception{ //默认打印到控制台 PrintStream printStream = System.out; printStream.println("Hello World!"); //改变输出方向setOut,输出到IOTest.txt中 System.setOut(new PrintStream(new FileOutputStream("D:/IOTest.txt"))); System.out.println("must tear down the wall"); } }
ObjectInputStream/ObjectOutputStream
package iotest; import java.io.Serializable; /** * Created by Arenas on 2016/10/30. * Serializable这个接口内没有任何方法,只是起到一个标识的作用,称做标识接口,像这样的接口还有java.lang.Cloneable * JVM看到标识接口会对他特殊待遇 */ public class User implements Serializable { private String name; public User(String name){ this.name = name; } @Override public String toString() { return "User -- > name = " + name; } }
package iotest; import java.io.FileOutputStream; import java.io.ObjectOutputStream; /** * Created by Arenas on 2016/10/30. * java.io.ObjectInputStream;将硬盘中的数据反序列化到JVM内存中 * java.io.ObjectOutputStream;序列化Java对象到硬盘 */ public class IOTest12 { public static void main(String[] args) throws Exception{ ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:/IOTest.txt")); User user = new User("kobe");//要传输的对象必须序列化!否则会抛出异常 oos.writeObject(user); oos.flush(); oos.close(); } }
package iotest; import java.io.FileInputStream; import java.io.ObjectInputStream; /** * Created by Arenas on 2016/10/30. */ public class IOTest13 { public static void main(String[] args) throws Exception{ ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:/IOTest.txt")); Object o = ois.readObject();//注意在反序列化的时候User.java这个文件不能删,因为在readObject的时候要创建对象,创建对象需要类 System.out.print(o);//User -- > name = kobe ois.close(); } }
serialVersionUID
之前有说到User在反序列化时是不能删的,如果删掉改变User呢?比如在User中加条private int age;属性,这个时候反序列化就会抛出异常
Exception in thread "main" java.io.InvalidClassException: iotest.User; local class incompatible: stream classdesc serialVersionUID = 4408450428999604713, local class serialVersionUID = 6602202455712956108
因为反序列化时会重新编译User,得到serialVersionUID跟流里面的User的serialVersionUID不同。这是由于在User实现serializable接口的时候,JVM会提供一个“特殊待遇”----给该类加上一个属性static final long serialVersionUID = 232313231L;在改变User后,由于User重新编译,JVM会重新分配一个序列化版本号。
所以,这里可以自己加上serialVersionUID这条属性,不让系统自动生成。那么不管该类如何变,序列化版本号都不会改变了。
package iotest; import java.io.Serializable; /** * Created by Arenas on 2016/10/30. * Serializable这个接口内没有任何方法,只是起到一个标识的作用,称做标识接口,像这样的接口还有java.lang.Cloneable * JVM看到标识接口会对他特殊待遇 */ public class User implements Serializable { //自己加上版本号 static final long serialVersionUID = 2323123123L; private String name; //增加一条属性 private int age; public User(String name){ this.name = name; } //改变toString方法 @Override public String toString() { return "User -- > name = " + name + " , age = " + age; } }
再运行IOTest13会得到:User -- > name = kobe , age = 0。没有产生类的兼容性问题
如果需要某个属性不参加序列化,那么就加上transient关键字修饰,如
private transient String name;
再运行IOTest13反序列化会得到
User -- > name = null , age = 0
File
文件和目录路径名的抽象表示形式。也就是说文件夹和文件都是一个File
package iotest; import java.io.File; /** * Created by Arenas on 2016/10/31. * 递归找出所有子文件 */ public class FileTest01 { public static void main(String[] args)throws Exception{ File file = new File("D:/Android"); findAllFile(file); } public static void findAllFile(File file){ //当是文件的时候就返回 if (file.isFile()) return; //当是目录的时候就遍历所有文件 File[] files = file.listFiles(); for (File f : files){ System.out.println(f.getAbsolutePath()); findAllFile(f); } } }