Java I/O -- Byte Stream

Java I/O库的设计原则

• Java的I/O库提供了一个称做链接的机制,可以将一个流与另一个流首尾相接,形成一个流管道的链接。这种机制实际上是一种被称为Decorator(装饰)设计模式的应用。

• 通过流的链接,可以动态的增加流的功能,而这种功能的增加是通过组合一些流的基本功能而动态获取的。

• 我们要获取一个I/O对象,往往需要产生多个I/O对象,这也是Java I/O库不太容易掌握的原因,但在I/O库Decorator模式的运用,给我们提供了实现上的灵活性。

 

流的概念

Java程序通过流来完成输入/输出。流是生产或消费信息的抽象。流通过Java的输入/输出系统与物理设备链接。尽管与它们链接的物理设备不尽相同,所有流的行为具有同样的方式。这样,相同的输入/输出类和方法适用于所有类型的外部设备。这意味着一个输入流能够抽象多种不同类型的输入:从磁盘文件,从键盘或从网络套接字。同样,一个输出流可以输出到控制台,磁盘文件或相连的网络。流是处理输入/输出的一个洁净的方法,例如它不需要代码理解键盘和网络的不同。Java中流的实现是在java.io包定义的类层次结构内部的。

 

流的分类

节点流:从特定的地方读写的流类,例如:磁盘或一块内存区域。

过滤流:使用节点流作为输入或输出。过滤流是使用一个已经存在的输入流或输出流连接创建的。

 

输入/输出流的概念

输入/输出时,数据在通信通道中流动。所谓“数据流(stream)”指的是所有数据通信通道之中,数据的起点和终点。信息的通道就是一个数据流。只要是数据从一个地方“流”到另外一个地方,这种数据流动的通道都可以称为数据流。

 

输入/输出是相对于程序来说的。程序在使用数据时所扮演的角色有两个:一个是源,一个是目的。若程序是数据流的源,即数据的提供者,这个数据流对程序来说就是一个“输出数据流”(数据从程序流出)。若程序是数据流的终点,这个数据流对程序而言就是一个“输入数据流” ( 数据从程序外流向程序)。

 

输入/输出类

• 在java.io包中提供了60多个类(流)。

• 从功能上分为两大类:输入流和输出流。

• 从流结构上可分为字节流(以字节为处理单位或称面向字节)和字符流(以字符为处理单位或称面向字符)。

• 字节流的输入流和输出流基础是InputStream和OutputStream这两个抽象类,字节流的输入输出操作由这两个类的子类实现。字符流是Java 1.1版后新增加的以字符为单位进行输入输出处理的流,字符流输入输出的基础是抽象类Reader和

Writer

 

字节流和字符流

• Java 2 定义了两种类型的流:字节流和字符流。字节流(byte stream)为处理字节的输入和输出提供了方便的方法。例如使用字节流读取或写入二进制数据。

字符流(character stream)为字符的输入和输出处理提供了方便。它们采用了统一的编码标准,因而可以国际化。当然,在某些场合,字符流比字节流更有效。

• Java的原始版本(Java 1.0)不包括字符流,因此所有的输入和输出都是以字节为单位的。Java 1.1中加入了字符流的功能

• 需要声明:在最底层,所有的输入/输出都是字节形式的。基于字符的流只为处理字符提供方便有效的方法。

• 字节流类(Byte Streams) 字节流类用于向字节流读写8位二进制的字节。一般地,字节流类主要用于读写诸如图象或声音等的二进制数据。

• 字符流类(Character Streams) 字符流类用于向字符流读写16位二进制字符。

 

 

流的分类

• 两种基本的流是:输入流(Input Stream)和输出流(Output Stream)。可从中读出一系列字节的对象称为输入流。而能向其中写入一系列字节的对象称为输出流。

Byte Streams          Character Streams          
InputStreamReader
OutputStreamWriter

 

 

 

 

 

字节流

• 字节流类为处理字节式输入/输出提供了丰富的环境。一个字节流可以和其他任何类型的对象并用,包括二进制数据。这样的多功能性使得字节流对很多类型的程序都很重要。

• 字节流类以InputStream 和OutputStream为顶层类,他们都是抽象类(abstract)

• 抽象类InputStream和 OutputStream定义了实现其他流类的关键方法。最重要的两种方法是read()和write(),它们分别对数据的字节进行读写。两种方法都在InputStream 和OutputStream中被定义为抽象方法。它们被派生的流类重写

• 每个抽象类都有多个具体的子类,这些子类对不同的外设进行处理,例如磁盘文件,网络连接,甚至是内存缓冲区。

• 要使用流类,必须导入java.io包

 

InputStream

• 三个基本的读方法

abstract int read() :读取一个字节数据, 并返回读到的数据,如果返回-1,表示读到了输 入流的末尾。

int read(byte[] b) :将数据读入一个字节 数组,同时返回实际读取的字节数。如果返回-1, 表示读到了输入流的末尾。

int read(byte[] b, int off, int len) :将数 据读入一个字节数组,同时返回实际读取的字节 数。如果返回-1,表示读到了输入流的末尾。off指定在数组b中存放数据的起始偏移位置;len指 定读取的最大字节数。

• 其它方法

long skip(long n) :在输入流中跳过n个字节,并返 回实际跳过的字节数。

int available() :返回在不发生阻塞的情况下,可读 取的字节数。

void close() :关闭输入流,释放和这个流相关的系 统资源。

void mark(int readlimit) :在输入流的当前位置放 置一个标记,如果读取的字节数多于readlimit设置的值, 则流忽略这个标记。

void reset() :返回到上一个标记。

boolean markSupported() :测试当前流是否支持 mark和reset方法。如果支持,返回true,否则返回 false。

• 该类的所有方法在出错条件下引发一个IOException 异常

• 通过打开一个到数据源(文件、内存或网络端口上的数据)的输入流,程序可以从数据源上顺序读取数据。

• InputStream中包含一套字节输入流需要的方法,可以完成最基本的从输入流读入数据的功能。当Java程序需要外设的数据时,可根据数据的不同形式,创建一个适当的InputStream子类类型的对象来完成与该外设的连接,然后再调用执行这个流类对象的特定输入方法来实现对相应外设的输入操作。

• InputStream 类 子 类 对 象 自 然 也 继 承 了InputStream类的方法。常用的方法有:读数据的方法 read() , 获取输入流字节数的方法available(),定位输入位置指针的方法skip()、reset()、mark()等。

 

 

OutputStream

• 三个基本的写方法

abstract void write(int b) :往输出流中写入一个字节。

void write(byte[] b) :往输出流中写入数组b中的所有字节。

void write(byte[] b, int off, int len) :往输出流中写入数组b中从偏移量off开始的len个字节的数据。

• 其它方法

void flush() :刷新输出流,强制缓冲区中的输出字节被写出。

void close() :关闭输出流,释放和这个流相关的系统资源。

• OutputStream是定义了流式字节输出模式的抽象类。该类的所有方法返回一个void 值并且在出错情况下引发一个IOException异常。

• 通过打开一个到目标的输出流,程序可以向外部目标顺序写数据

• OutputStream中包含一套字节输出流需要的方法,可以完成最基本的输出数据到输出流的功能。当Java程序需要将数据输出到外设时,可根据数据的不同形式,创建一个适当的OutputStream子类类型的对象来完成与该外设的连接,然后再调用执行这个流类对象的特定输出方法来实现对相应外设的输出操作。

• OutputStream类子类对象也继承了OutputStream类的方法。常用的方法有:写数据的方法write(),关闭流方法close()等。

 

 

字节流InputStream和OutputStream类的类层次

 

 

文件的读写

• Java提供了一系列的读写文件的类和方法。在Java中,所有的文件都是字节形式的。Java提供从文件读写字节的方法。而且,Java允许在字符形式的对象中使用字节文件流。

• 两个最常用的流类是FileInputStream和FileOutputStream,它们生成与文件链接的字节流。为打开文件,你只需创建这些类中某一个类的一个对象,在构造方法中以参数形式指定文件的名称

• 当你对文件的操作结束后,需要调用close( )来关闭文件。

– void close( ) throws IOException

 

FileInputStream(文件输入流)

输入流

• 读数据的逻辑为:

open a stream

while more information

read information

close the stream

• FileInputStream 类创建一个能从文件读取字节的InputStream 类,它的两个常用的构造方法如下

– FileInputStream(String filepath)

– FileInputStream(File fileObj)

– 它们都能引发FileNotFoundException异常。这里,filepath 是文件的全称路径,fileObj是描述该文件的File对象。

• 为读文件,可以使用在FileInputStream中定义的read( )方法。

– int read( ) throws IOException

• 该方法每次被调用,它仅从文件中读取一个字节并将该字节以整数形式返回。当读到文件尾时,read( )返回-1。该方法可以引发IOException异常

示例程序InputStreamTest1.java

package com.fairy.io2;

import java.io.FileInputStream;
import java.io.InputStream;

/*
 * 读数据的逻辑
 * 1.open a stream 
 * 2.while more information 
 * 3.read information 
 * 4.close the stream
 */
public class InputStreamTest1 {
	public static void main(String[] args) throws Exception {
		InputStream is = new FileInputStream("C:/file1.txt");

		byte[] buffer = new byte[200];

		int length;

		while (-1 != (length = is.read(buffer, 0, 200))) {
			String str = new String(buffer, 0, length);

			System.out.println(str);
		}

		is.close();
	}
}

 

FileOutputStream(文件输出流)

输出流

• 写数据的逻辑为:

open a stream

while more information

write information

close the stream

• FileOutputStream 创建了一个可以向文件写入字节的类OutputStream,它常用的构造方法如下

– FileOutputStream(String filePath)

FileOutputStream(File fileObj)

FileOutputStream(String filePath, boolean append)

• 它们可以引发IOException或SecurityException异常。这里filePath是文件的全称路径,fileObj是描述该文件的File对象。如果append为true,文件以追加模式打开,即新写入的字节将附加在文件的末尾,而不是从头开始

• FileOutputStream的创建不依赖于文件是否存在。在创建对象时FileOutputStream在打开输出文件之前创建它。这种情况下你试图打开一个只读文件,会引发一个IOException异常

• 向文件中写数据,需用FileOutputStream定义的write()方法。它的最简单形式如下

– void write(int byteval) throws IOException

– 该方法按照byteval指定的数向文件写入字节。尽管byteval作为整数声明,但仅低8位字节可以写入文件。如果在写的过程中出现问题,一个IOException被引发

示例程序OutputStreamTest1.java

package com.fairy.io2;

import java.io.FileOutputStream;
import java.io.OutputStream;

/*
 * 写数据的逻辑:
 * 1.open a stream
 * 2.while more information
 * 3.write information
 * 4.close the stream
 */
public class OutputStreamTest1 {
	public static void main(String[] args) throws Exception {
		OutputStream os = new FileOutputStream("C:/file2.txt", true);

		String str = "Hello World";

		byte[] buffer = str.getBytes();

		os.write(buffer);

		os.close();
	}
}

 

ByteArrayInputStream(字节数组输入流)

• ByteArrayInputStream是把字节数组当成源的输入流。该类有两个构造方法,每个构造方法需要一个字节数组提供数据源

– ByteArrayInputStream(byte array[ ])

– ByteArrayInputStream(byte array[ ], int start, int numBytes)

– 这里,array是输入源。第二个构造方法创建了一个InputStream类,该类从字节数组的子集生成,以start指定索引的字符为起点,长度由numBytes决定

示例程序ByteArrayInputStreamTest1.java

package com.fairy.io2;

import java.io.ByteArrayInputStream;

public class ByteArrayInputStreamTest1 {
	public static void main(String[] args) throws Exception {
		String temp = "Hello World";

		byte[] b = temp.getBytes();

		ByteArrayInputStream is = new ByteArrayInputStream(b);

		for (int i = 0; i < 2; i++) {
			int c;

			while (-1 != (c = is.read())) {
				if (0 == i) {
					System.out.println((char) c);
				} else {
					System.out.println(Character.toUpperCase((char) c));
				}
			}

			System.out.println();

			is.reset();
		}

		is.close();
	}
} 

ByteArrayOutputStream(字节数组输出流) 

• ByteArrayOutputStream是一个把字节数组当作输出流的实现。ByteArrayOutputStream 有两个构造方法

– ByteArrayOutputStream( )

– ByteArrayOutputStream(int numBytes)

– 在第一种形式里,一个32位字节的缓冲区被生成。第二个构造方法生成一个numBytes大小的缓冲区。缓冲区保存在ByteArrayOutputStream的受保护的buf成员里。缓冲区的大小在需要的情况下会自动增加。缓冲区保存的字节数是由ByteArrayOutputStream的受保护的count域保存的 

示例程序ByteArrayOutputStreamTest1.java

package com.fairy.io2;

import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;

public class ByteArrayOutputStreamTest1 {
	public static void main(String[] args) throws Exception {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();

		String str = "Hello World";

		byte[] buffer = str.getBytes();

		baos.write(buffer);

		byte[] result = baos.toByteArray();

		for (byte b : result) {
			System.out.print((char) b + " ");
		}
		
		OutputStream os = new FileOutputStream("bytearray.txt");
		baos.writeTo(os);
		
		baos.close();
		os.close();
	}
}

– writeTo:将此字节数组输出流的全部内容写入到指定的输出流参数中

– reset:将此字节数组输出流的 count 字段重置为零,从而丢弃输出流中目前已累积的所有输出。通过重新使用已分配的缓冲区空间,可以再次使用该输出流。

 

 


过滤流

• 在InputStream类和OutputStream类子类中,FilterInputStream和FilterOutputStream过滤流抽象类又派生出DataInputStream和DataOutputStream数据输入输出流类等子类。

• 过滤流的主要特点是在输入输出数据的同时能对所传输的数据做指定类型或格式的转换,即可实现对二进制字节数据的理解和编码转换。

• 数据输入流DataInputStream中定义了多个针对不同类型数据的读方法,如readByte() 、 readBoolean() 、

readShort()、readChar()、readInt()、readLong()、readFloat()、readDouble()、readLine()等。

• 数据输出流DataOutputStream中定义了多个针对不同类型数据的写方法, 如 writeByte() 、writeBoolean() 、

writeShort()、writeChar()、writeInt()、writeLong()、writeFloat()、writeDouble()、writeChars()等。

• 过滤流在读/写数据的同时可以对数据进行处理,它提供了同步机制,使得某一时刻只有一个线程可以访问一个I/O流,以防止多个线程同时对一个I/O流进行操作所带来的意想不到的结果。

• 类FilterInputStream和FilterOutputStream分别作为所有过滤输入流和输出流的父类。

示例程序DataStreamTest1.java

package com.fairy.io2;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class DataStreamTest1 {
	public static void main(String[] args) throws Exception {
		DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(
				new FileOutputStream("data.txt")));

		byte b = 3;
		int i = 12;
		char ch = 'a';
		float f = 3.3f;

		dos.writeByte(b);
		dos.writeInt(i);
		dos.writeChar(ch);
		dos.writeFloat(f);

		dos.close();

		DataInputStream dis = new DataInputStream(new BufferedInputStream(
				new FileInputStream("data.txt")));

		System.out.println(dis.readByte());
		System.out.println(dis.readInt());
		System.out.println(dis.readChar());
		System.out.println(dis.readFloat());
		
		dis.close();
	}
}

 

基本的流类

• FileInputStream和FileOutputStream

节点流,用于从文件中读取或往文件中写入字节流。如果在构造FileOutputStream时,文件已经存在,则覆盖这个文件。

• BufferedInputStream和 BufferedOutputStream

过滤流,需要使用已经存在的节点流来构造,提供带缓冲的读写,提高了读写的效率。

• DataInputStream和DataOutputStream 过滤流,需要使用已经存在的节点流来构造,提供了读写Java中的基本数 据类型的功能。

• PipedInputStream和PipedOutputStream

管道流,用于线程间的通信。一个线程的PipedInputStream对象从另一个线程的PipedOutputStream对象读取输入。要使管道流有 用,必须同时构造管道输入流和管道输出流。


示例程序BufferedOutputStreamTest1.java

package com.fairy.io2;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;

public class BufferedOutputStreamTest1 {
	public static void main(String[] args) throws Exception {
		BufferedOutputStream bos = new BufferedOutputStream(
				new FileOutputStream("buffered.txt"));

		bos.write("http://www.google.com".getBytes());

		bos.close();
	}
}
 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值