黑马程序员——IO

                                    ------- 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)
使用指定的底层 InputStream 创建一个 DataInputStream。


 包装类BufferedInputStream和BufferedOutputStream 是缓冲流,它为IO流增加了内存缓存,有两个目的,1、允许java查询一次操作多个字节,提高效率。2、由于了有了缓冲区使得在流上面skip,mark都成为可能。与他们对应的有BufferedRead和BufferedWriter

构造方法摘要
BufferedInputStream(InputStream in)
创建一个BufferedInputStream并保存其参数,即输入流in,以便将来使用。
BufferedInputStream(InputStream in, int size)

创建具有指定缓冲区大小的BufferedInputStream并保存其参数,即输入流in,以便将来使用。

BufferedOutputStream(OutputStream out)
创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
BufferedOutputStream(OutputStream out, int size)
创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。

下面我们看看由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)
创建一个使用给定大小输出缓冲区的新缓冲字符输出流。
可以看见他们的构造函数都需要接收相应的Reader和Writer 那么我们怎么把字节流转换为Reader或者Writer呢?

构造方法摘要
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();
		
	}
}


转载于:https://my.oschina.net/u/158350/blog/99400

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值