InputStrem与OutputStrem

通用dump方法(BufferedInputStream改写更好):

package intoutput;

import java.io.*;

public class IO {
	private static void dump(InputStream src, OutputStream dest) throws IOException {
		try (InputStream input = src; OutputStream output = dest) {//自动关闭资源
			byte[] data=new byte[1024];
			int length;
			while((length=input.read(data))!=-1) {
				output.write(data, 0, length);
			}
		}
	}
}
复制代码

dump()方法接受 InputStream与 outputstream实例,分别代表读取数据的来源,以及输出数据的目的地。在进行 Inputstream与 Outputstream的相关操作时若发生错误,会抛出java. io. IOException异常,在这里不特别处理,而是在dump()法上声明 throws,由调用dump()方法的客户端处理 (JDK中许多I/O操作都会声明抛出 IOEXception,如果想考虑捕捉后转为执行时期异常,可以使用JDK8新增的java.io. UncheckedIOException,这个异常继承自 RuntimeException在不使用 Inputstream与 Outputstream时,必须使用 close()方法关闭串流。) 由于Inputstream与 Outputstream操作了java.io. Closeable接口,其父接口为java.lang. Autocloseable接口,因此可使用JDK7尝试自动关闭资源语法 每次从 InputStream读入的数据,都会先置入byte数组中。 Inputstream的read()方法每次会尝试读入byte数组长度的数据,并返回实际读入的字节,只要不是-1,就表示读取到数据。可以使用 Outputstream 的 write()方法,指定要写出的byte数组、初始索引与数据长度。 dump()方法的来源、目的地都未知。dump()方法并没有限定来源或目的地真实形式,而是依赖于抽象的Inputstream、 outputstrear。 如果要将某个文档读入并另存为另一个文档,则可以这么使用:

package intoutput;

import java.io.*;

public class Copy {
	public static void main(String[] args) throws IOException {
		IO.dump(new FileInputStream(args[0]), new FileOutputStream(args[1]));
	}
}

复制代码

这个程序可以由命令行自变量指定读取的文档来源与写出的目的地,例如:

 >Java hello.intoutput.Copy B:\test.txt B:\text.proterties
复制代码

一个项目路径,两个输入输出文档。

FileInputstream 是 Inputstream的子类,Fileoutputstream 是 OutputStream的子类,用于衔接文档以读入写出数据 如果要从HTTP服务器读取某个网页,并另存为文档,也可以使用这里的dump()方法。例如:

package intoutput;

import java.io.*;
import java.net.URL;;


public class Copy {
	public static void main(String[] args) throws IOException {
		URL url=new URL(args[0]);
		IO.dump(url.openStream(), new FileOutputStream(args[1]));
	}
}
复制代码

URL的使用很简单,只要指定网址UL实例会自动进行HTTP协议。可以使用 openstream()方法取得 Inputstream实例,代表与网站连接的数据串流。 无论来源或目的地实体形式为何,只要想办法取得 Inputstream或 outputstream,接下来都是调用 Inputstream或 outputstream 的相关方法。例如,使用java.net.ServerSocket接受客户端联机的例子:

package intoutput;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class ClientDemo {
	public static void main(String[] args) {
		ServerSocket server=null;
		Socket client=null;
		try {
			server=new ServerSocket(port);
			while(true) {
				client=server.accept();
				InputStream input=client.getInputStream();
				OutputStream output=client.getOutputStream();
				
				//接下来操作InputStream,OutputStream实例......
			}
		} catch (IOException e) {
			// TODO: handle exception
		}
	}
}

复制代码

架构(图片来自网络):

1、标准输入输出
System.in与System.out其实分别是InputStream、OutputStream实例。分别代表标准输入输出。对电脑来说就是文本模式输入输出。人计算机而言,通常对应至文本模式中的输入与输出。
以 System.in而言,因为文本模式下通常是取得整行用户输入,因此较少直接操作 InputStream相关方法,而是使用java.util. Scanner打包 System.in,你操作 scanner.相关方法,而 Scanner会代你操控 System.in取得数据,并转换为取得你想要的数据类型。 可以使用 System的 setIn()方法指定 InputStream实例,重新指定标准输入来源。例如下面范例故意将标准输入指定为 FileInputstream,可以读取指定文档并显示在文本模式:

package intoutput;

import java.io.*;
import java.util.Scanner;

public class StandardIn {
	public static void main(String[] args) throws IOException {
		System.setIn(new FileInputStream("B:\\test.xml"));
		try(Scanner scan=new Scanner(System.in)){
			while(scan.hasNextLine()) {
				System.out.println(scan.nextLine());
			}
		}
	}
}

复制代码

System.out为PrintStrem实例,它是一种 Outputstream,所以若要将刚刚范例改为输出至标准输出,也可以这么写

........
IO.dump(url.openStream(), System.out));
........
复制代码

标准输出可以重新导向至文档,只要执行程序时使用>将输出结果导向至指定的文档。

IO.dump(System.in, System.out);//输入输出
IO.dump(System.in, new FileOutputStream("B:\\test.xml"));//控制台输入输出至文档
复制代码

可以使用 System的setout()方法指定 Printstream实例,将结果输出至指定的目的地。例如,故意将标准输出指定至文档:

package intoutput;

import java.io.*;

public class StandardOut {
	public static void main(String[] args) throws IOException {

		try (PrintStream printStream = new PrintStream(new FileOutputStream("B:\\test.txt"))) {
			System.setOut(printStream);
			System.out.println("helloWorld");
		}
	}
}

复制代码

Printstream接受 Inputstream实例,在这个范例中用 Printstream打包 Fileoutputstream,你操作 Printstream相关方法, printstream会代你操作 Fileoutputstream。
除了 System.in与 system.out之外,还有个 system.err为 Printstream实例,称为标准错误输出串流,它是用来立即显示错误信息。例如,在文本模式下, System.out输出的信息可以使用>或>重新导向至文档,但 System.err输出的信息一定会显示在文本模式中,无法重新导向。也可以使用 System. setErr()指定 Printstream,重新指定标准错误输出串流。
2. Fileinputstream与Fileoutputstream FileInputstream 是 Inputstream的子类,可以指定文件名创建实例,一旦创建文档就开启,接着就可用来读取数据。 Fileoutputstream是outputstream 的子类,可以指定文件名创建实例,一旦创建文档就开启,接着就可以用来写出数据。无论 FileInputstream还是 Fileoutputstream 不使用时都要使用 close()关闭文档。
FileInputStream主要操作了 InputStream的read()抽象方法,使之可从文档中读取数据, FileOutputstream主要操作了 Outputstream的 write()抽象方法,使之可写出数据至文档。 FileInputstream、 Fileoutputstream在读取、写入文档时,是以字节为单位,通常会使用一些高阶类加以打包,进行一些高阶操作,像是前面示范过的 Scanner与Printstream类等。之后还会看到更多打包 Inputstream、 outpustream的类,它们也可以用来打包 FileInputstream、 Fileoutputstream。 3. ByteArrayInputstream 与 ByteArrayoutputstream ByteArrayInputstream是 Inputstream的子类,可以指定byte数组创建实例,一旦创建就可将byte数组当作数据源进行读取。ByteArrayoutputStream是 Outputstream的子类,可以指定byte数组创建实例,一旦创建将bye数组当作目的地写出数据。 ByteArrayInputstream主要操作了 InputStream的read()抽象方法,使之可从byte数组中读取数据。 ByteArrayoutputStream主要操作了 Outputstream的 write()抽象方法,使之可写出数据至byte数组。 3串流处理装饰器 Inputstream、 Output Stream提供串流基本操作,如果想要为输入输出的数据做加工处理,则可以使用打包器类。前面示范过的 Scanner类就是作为打包器,其接受 Inputstream实例,你操作scanner打包器相关方法 Scanner会实际操作打包的 Inputstream取得数据,并转换为你想要的数据类型Inputstream、 Outputstream的一些子类也有打包器的作用,这些子类创建时,可以接受 Inputstream, Outputstream实例。前面介绍的 PrintStream()就是实际例子,你操作Printstream的print()、 println()等方法,Printstream会自动转换为byte数组数据,利用打包的 outputstream进行输出。 具备缓冲区作用的 BufferedInputstream Bufferedoutputstream,具备数据转换处理作用的 DataInputstream、 DataOutputstream,具备对象串行化能力的 ObiectInputstream、 Objectoutputstream等 由于这些类本身并没有改变 Inputstream、 Outputstream的行为,只不过在 Inputstream取得数据之后,再做一些加工处理,或者是要输出时做一些加工处理,再交由 outputstream真正进行输出,因此又称它们为装饰器 1. BufferedInputstream 与 Bufferedoutputstream 在前面Io.dump()方法中,每次调用 Inputstream的read()方法,都会直接向来源要求数据,每次调用 OutputStream的 write()方法时,都会直接将数据写到目的地。 以文档存取为例,如果传入IO.dump()的是 FileInputStream、FileOutputstream实例,每次read()时都会要求读取硬盘,每次 write()时都会要求写入硬盘,这会花费许多时间在硬盘定位上。 如果 InputStream第一次read()时可以尽量读取足够的数据至内存的缓冲区,后续调用read()时先看看缓冲区是不是还有数据,如果有就从缓冲区读取,没有再从来源读取数据至缓冲区,这样减少从来源直接读取数据的次数,对读取效率将会有帮助(内存的访问速度较快)。 如果 outputStream每次 write()时可将数据写入内存中的缓冲区,缓冲区满了再将缓冲区的数据写入目的地,这样可减少对目的地的写入次数,对写入效率将会有帮助。 BufferedInputstream与 BufferedOutputstream提供的就是前面描述的缓冲区功能, 创建 BufferedInputstream Bufferedoutputstream必须提供 Inputstream, Outputstream进行打包,可以使用默认或自定义缓冲区大小。 BufferedInputstream 与 BufferedoutputStream主要在内部提供缓冲区功能,操作上与 Inputstream, Outputstream并没有太大差别。例如,改写前面的dump():

package intoutput;

import java.io.*;

public class IO {
	public static void dump(InputStream src, OutputStream dest) throws IOException {
		try (InputStream input = new BufferedInputStream(src); OutputStream output = new BufferedOutputStream(dest)) {//自动关闭
			byte[] data=new byte[1024];
			int length;
			while((length=input.read(data))!=-1) {
				output.write(data, 0, length);
			}
		}
	}
}

复制代码

2. DataInputstream 与 DataOutputstream DataInputstream、Dataoutputstream用来装饰InputStream, outputStream。DataInputstream、Dataoutputstream提供读取、写入Java基本数据类型的方法像是读写int、 double、 boolean等的方法。这些方法会自动在指定的类型与字节间转换,不用你亲自做字节与类型转换的动作。 下面的 Member类可以调用save()储存 Member实例本身的数据,文件名为 Member的会员号码,调用 Member.load()指定会员号码,则可以读取文档中的会员数据,封装为 Member实例并返回:

package intoutput;

import java.io.*;

public class Member {
	private String num;
	private String nam;
	private int age;

	public Member(String num, String nam, int age) {
		this.num = num;
		this.nam = nam;
		this.age = age;
	}

	@Override
	public String toString() {
		// TODO 自动生成的方法存根
		return String.format(num, nam, age);
	}

	public void save() throws IOException {
		try (DataOutputStream out = new DataOutputStream(new FileOutputStream(num))) {//建立DataOutputStream 打包FileOutputStream
			out.writeUTF(num);// 不同类型调用不同writexxx方法
			out.writeUTF(nam);
			out.writeInt(age);
		}
	}

	public static Member load(String num) throws IOException {
		Member member;
		try (DataInputStream in = new DataInputStream(new FileInputStream(num))) {
			member = new Member(in.readUTF(), in.readUTF(), in.readInt());
		}
		return member;
	}
}

复制代码

Sava方法使用DataOutputStream打包FileOutputStream,存储Member实例时会使用writexxx不同方法分别存储字符串、int类型。load()方法类似。使用Member类:

package intoutput;

import java.io.IOException;

public class MemberDemo {
	public static void main(String[] args) throws IOException {
		Member[] members = { new Member("B0101", "zhangsan", 20), new Member("F8799", "lisi", 99),
				new Member("G3566", "wanger", 55) };
		for (Member member : members) {
			member.save();
		}
		System.out.println(Member.load("B0101"));
		System.out.println(Member.load("F8799"));
		System.out.println(Member.load("G3566"));
	}
}

复制代码

例三个Member类分别存储为文档后再读取出来。 3. ObjectInputstream 与ObjectOutputstream 前面的范例是取得 Membe的 number、name、age数据进行储存,读回时也是先取得 number、ame、age数据再用来创建 Member实例。实际上,也可以将内存中的对象整个储存下来,之后再读入还原为对象。可以使用 ObjectInputStream, Objectoutputstream装饰 Inputstream outputstream来完成。objectInputstream提供 readobject()方法将数据读入为对象,而 objectoutputstream提供 writeobject()方法将对象写至目的地,可以被这两个方法处理的对象,必须操作java.io. Serializable接口,这个接口并没有定义任何方法,只是作为标示之用,表示这个对象是可以串行化的:

package intoutput;

import java.io.*;

public class Member2 implements Serializable{
	private String num;
	private String nam;
	private int age;

	public Member2(String num, String nam, int age) {
		this.num = num;
		this.nam = nam;
		this.age = age;
	}

	@Override
	public String toString() {
		// TODO 自动生成的方法存根
		return String.format(num, nam, age);
	}

	public void save() throws IOException {
		try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(num))) {
			out.writeObject(this);
		}
	}

	public static Member load(String num) throws IOException, ClassNotFoundException {
		Member member;
		try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(num))) {
			member = (Member) in.readObject();
		}
		return member;
	}
}

复制代码

为了能够直接将对象写出或读入, Member2操作了 serializable(),在储存对象时,使用 ObjectoutputStream打包 Fileoutputstreame,ObjectInputstream的 writeobject()处理内存中的对象数据,再交给 FileOutputstream写至文档。在读入对象时,使用objectInputstream 打包 FileInputStream,在readobject()时,会用 FileInputstream读入字节数据,再交给ObiectInputstream处理,还原为 Member2实例:

package intoutput;

import java.io.IOException;

public class MemberDemo {
	public static void main(String[] args) throws Exception {
		Member2[] members2 = { new Member2("B0101", "zhangsan", 20), new Member2("F8799", "lisi", 99),
				new Member2("G3566", "wanger", 55) };
		for (Member2 member : members2) {
			member.save();
		}
		System.out.println(Member2.load("B0101"));
		System.out.println(Member2.load("F8799"));
		System.out.println(Member2.load("G3566"));
	}
}

复制代码

如果在做对象串行化时,对象中某些数据成员不希望被写出,则可以标上 transient关键字(密码)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值