------- android培训、java培训、期待与您交流! ----------
首先我们看看整个javaIO输入/输出流的体系图
可以看见按照不同的分类可以IO可以分为多种类型的流 输入/输出、字节/字符、节点流/包装流
一、我们看看简单的输入输出程序
import java.io.*; public class IOTest{ public static void main(String[] agrs) throws Exception{ String str ="我的IO测试类"; File file = new File("iotest.txt"); FileOutputStream fos = new FileOutputStream(file); fos.write(str.getBytes());//FileOutputStream是以字节的形式读写的,所以这里的String.getBytes()转换成字节数组 fos.close(); FileInputStream fis = new FileInputStream(file); int index = 0; byte[] buf = new byte[1024]; index = fis.read(buf);//这里的读取是读取buf.getLengthch长度的类容,所以返回的是int类型 System.out.println(new String(buf,0,index)); System.out.println("--------------"); fis.close(); } }我们顺便看一个关于file的其他操作,这个跟本文没多大关系,只是想起来了就写了个。
import java.io.*; public class FileTest{ public static void main(String[] agrs){ File file = new File(System.getProperty("user.dir"));//获取当前路径 System.out.println(file); String[] str = file.list(); for(String s : str){ System.out.println(s); } System.out.println("----------------------------------------------"); String[] str1 = file.list(new FileterJava());//获取以.java结尾的文件,参数是一个实现FilenameFilter的接口,在接口里面写具体的实现 for(String s1 : str1){ System.out.println(s1); } } } class FileterJava implements FilenameFilter{ public boolean accept(File dir,String name){ return name.endsWith(".java")||new File(name).isDirectory(); } }二、线程间通信的PipedInputStream(PipedReader)和PipedOutputStream(Pipedwriter)
import java.io.*; public class PipedTest{ public static void main(String[] agrs) throws Exception{ Sender sender = new Sender(); Receiver receiver = new Receiver(); PipedOutputStream pos = sender.getPipedOutputStream(); PipedInputStream pis = receiver.getPipedInputStream(); pos.connect(pis);//建立两个线程间的通信 new Thread(sender).start(); new Thread(receiver).start(); } } class Sender implements Runnable{ private PipedOutputStream pos = new PipedOutputStream(); public PipedOutputStream getPipedOutputStream(){//提供get方法获取pos return pos; } public void run(){ String str = "我是sender发送过来的消息"; try{pos.write(str.getBytes()); pos.close(); }catch(Exception e){e.printStackTrace();} } } class Receiver implements Runnable{ private PipedInputStream pis = new PipedInputStream(); public PipedInputStream getPipedInputStream(){//提供get方法获取pis return pis; } public void run(){ int i = 0; byte[] buf = new byte[1024]; try{ int length = pis.read(buf); System.out.println(new String(buf,0,length)); pis.close(); }catch(Exception e){e.printStackTrace();} } }三、读取内存虚拟文件或内存镜像文件
ByteArrayInputStream 和 ByteArrayOutputStream 其实他们的用法基本和fIleInputStream差不多这里就不多做复述了。
与之对应的有charArrayReader charArrayWrite。请参照我们上面的图片。
四、包装类DateOutputStream DateInputStream他们没有对应到具体的输出输入的流设备,他们的构造函数如下,我们可以看超出这两个类类似于工具类只是更方便我们编程,主要是把各种数据类型写入到输出流中。包装类也可以包装另外的包装类。
构造方法摘要 | |
---|---|
DataOutputStream(OutputStream out) 创建一个新的数据输出流,将数据写入指定基础输出流。 DataInputStream(InputStream in) |
包装类BufferedInputStream和BufferedOutputStream 是缓冲流,它为IO流增加了内存缓存,有两个目的,1、允许java查询一次操作多个字节,提高效率。2、由于了有了缓冲区使得在流上面skip,mark都成为可能。与他们对应的有BufferedRead和BufferedWriter
构造方法摘要 | ||
---|---|---|
BufferedInputStream(InputStream in) 创建一个BufferedInputStream并保存其参数,即输入流in,以便将来使用。 |
||
BufferedInputStream(InputStream in, int size) 创建具有指定缓冲区大小的BufferedInputStream并保存其参数,即输入流in,以便将来使用。
|
下面我们看看由DataOutputStream————>包装BufferedWriter优势可以创建缓冲区------->包装FileOutputStream
import java.io.*; public class DataIOTest{ public static void main(String[] agrs) throws Exception{ File file = new File("DataTest.txt");//这里也可以不写,在下面的FileOutputStream构造函数中传入字符串也可以,但这样写其实可以利用fILE判断很多东西,只是这里没写罢了 FileOutputStream fos = new FileOutputStream(file); BufferedOutputStream bos = new BufferedOutputStream(fos);//利用buffered包装 DataOutputStream dos = new DataOutputStream(bos);//利用Data包装buffered dos.writeUTF("AB中国"); dos.close();//只要关闭最外面的流 里面的也就自动关闭 FileInputStream fis = new FileInputStream(file); BufferedInputStream bis = new BufferedInputStream(fis); DataInputStream dis = new DataInputStream(bis); String str = dis.readUTF(); System.out.println(str); dis.close(); } }包装类ObjectInputStream和ObjectOutputStream用于从底层输入流中读取对象类型的数据然后写入到底层输出流, 由于对象要在系统间传输所以必须实现Serializable这个标记性接口,且对象中的transient和static类型的成员变量是不会被读取和写入的。
需要注意的是,在我们标注一个类可以序列化的时候,其以下属性应该设置为transient来避免序列化:
(1) 线程相关的属性;
(2) 需要访问IO、本地资源、网络资源等的属性;
(3) 没有实现可序列化接口的属性;(注:如果一个属性没有实现可序列化,而我们又没有将其用transient 标识, 则在对象序列化的时候,会抛出java.io.NotSerializableException 异常)。
对于是否读到文件尾部这里的readObject并没有返回-1那种变量,所以只能我们自己解决,是捕捉EOFException
import java.io.*; public class ObjectIo{ public static void main(String[] agrs) throws Exception{ Student s1 = new Student("zs1",21,0);//这里的第三个参数是id 是transient的 所以不会被序列化 等候看结果应该取出来是空 Student s2 = new Student("zs2",20,1); File file = new File("ObjectIo.txt"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file)); oos.writeObject(s1);//写入对象 oos.writeObject(s2); oos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file)); //Student s3 = (Student)ois.readObject(); //Student s4 = (Student)ois.readObject(); int i = 0; Student s3 = null; while(true){//由于不知道到底有多个对象,所以我们采取循环不停的去,当取到尾部的时候会捕捉到EOFException 然后在break循环 try{s3 = (Student)ois.readObject();}catch(EOFException e){break;} System.out.println(s3.getName()+"---"+s3.getAge()+"----"+s3.getId()+"---"+s3.getUid()); } } } class Student implements Serializable{ private String name; private Integer age; private transient Integer id;//这里定义成transient并不会被序列化 private static final String uid="uuid01";//这里也不会序列化 public Student(){} public Student(String name,Integer age,Integer id){ this.name = name; this.age = age; this.id = id; } public String getName(){ return name; } public void setName(String name){ this.name = name; } public Integer getAge(){ return age; } public void setAge(Integer age){ this.age = age; } public Integer getId(){ return id; } public void setId(Integer id){ this.id = id; } public String getUid(){ return uid; } public boolean equals(Object obj){ if(obj instanceof Student){ Student s = (Student) obj; if(name.equals(s.name)&&age==s.age&&id==s.id){ return true; }else{ return false; } }else{ return false; } } @Override public String toString(){ return "name----->"+name+"\nage----->"+age+"\nid----->"+id+"\nuid----->"+uid; } }
运行结果
C:\Users\Administrator\Desktop>javac ObjectIo.java C:\Users\Administrator\Desktop>java ObjectIo zs1---21----null---uuid01 我们看见结果在id那一列是空 是因为没有序列化 zs2---20----null---uuid01
下面我们看看字节流和字符流之间的转问题
一般我们在读写文本文件的时候尽量使用Buffered包装类来操作,因为他提供了缓存机制,可以大大的提高效率,我们看看他们的构造函数
构造方法摘要 | |
---|---|
BufferedReader(Reader in) 创建一个使用默认大小输入缓冲区的缓冲字符输入流。 |
|
BufferedReader(Reader in, int sz) 创建一个使用指定大小输入缓冲区的缓冲字符输入流。 |
构造方法摘要 | |
---|---|
BufferedWriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流。 |
|
BufferedWriter(Writer out, int sz) 创建一个使用给定大小输出缓冲区的新缓冲字符输出流。 |
构造方法摘要 | |
---|---|
OutputStreamWriter(OutputStream out) 创建使用默认字符编码的 OutputStreamWriter。 |
构造方法摘要 | |
---|---|
InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader。 |
import java.io.*; public class BufferedTest{ public static void main(String[] agrs) throws Exception{ BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("Buffered.TXT"))); bw.write("我爱中国\n",0,"我爱中国\n".length()); bw.newLine(); bw.write("我爱中国1",0,"我爱中国1".length()); bw.close(); BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("Buffered.TXT"))); String s = null; while((s=br.readLine())!=null){ System.out.println(s); } br.close(); } }