现在的位置: 首页 > 综合 > 正文

37、Java IO流

2018年02月05日 ⁄ 综合 ⁄ 共 9995字 ⁄ 字号 评论关闭

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

2、输入/输出流:输入/输出时,数据在通信通道中流动。所谓“数据流(stream)”指的是所有数据通信通道之中,数据的起点和终点。信息的通道就是一个数据流。只要是数据从一个地方“流”到另外一个地方,这种数据流动的通道都可以称为数据流;输入/输出是相对于程序来说的。程序在使用数据时所扮演的角色有两个:一个是源,一个是目的。若程序是数据流的源,即数据的提供者,这个数据流对程序来说就是一个“输出数据流”(数据从程序流出)。若程序是数据流的终点,这个数据流对程序而言就是一个“输入数据流”(数据从程序外流向程序)

3、在java.io包中提供了60多个类(流)。
      从功能上分为两大类:输入流和输出流。两种基本的流:输入流(Input Stream)和输出流(Output Stream)。可从中读出一系列字节的对象称为输入流。而能向其中写入一系列字节的对象称为输出流。
      从流结构上可分为字节流(以字节为处理单位或称面向字节)和字符流(以字符为处理单位或称面向字符)。
      字节流的输入流和输出流基础是InputStream和OutputStream这两个抽象类,字节流的输入输出操作由这两个类的子类实现。字符流是Java1.1版后新增加的以字符为单位进行输入输出处理的流,字符流输入输出的基础是抽象类Reader和Writer

4、字节流和字符流:Java 2 定义了两种类型的流:字节流和字符流。字节流(byte stream)为处理字节的输入和输出提供了方便的方法。例如使用字节流读取或写入二进制数据。字符流(character stream)为字符的输入和输出处理提供了方便。它们采用了统一的编码标准,因而可以国际化。当然,在某些场合,字符流比字节流更有效;Java的原始版本(Java 1.0)不包括字符流,因此所有的输入和输出都是以字节为单位的。Java 1.1中加入了字符流的功能;需要声明:在最底层,所有的输入/输出都是字节形式的。基于字符的流只为处理字符提供方便有效的方法;字节流类(Byte
Streams)
字节流类用于向字节流读写8位二进制的字节。一般地,字节流类主要用于读写诸如图象或声音等的二进制数据。字符流类(Character Streams)字符流类用于向字符流读写16位二进制字符。

Byte Stream Character Stream
InputStream Reader
OutputStream Writer

5、输入流:读数据的逻辑为:
      open a stream
      while more information
      read information
      close the stream

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

public class InputStreamTest
{
	public static void main(String[] args) throws Exception
	{
		InputStream is = new FileInputStream("d:/abc/ss.txt");
		
		byte[] buffer = new byte[200];
		
		int length = 0;
		
		while(-1 != (length = is.read(buffer,0,200)))
		{
			String str = new String(buffer,0,length);
			System.out.println(str);
		}
		
		is.close();
	}
}

输出流:写数据的逻辑为:
      open a stream
      while more information
      write information
      close the stream

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

public class OutputStreamTest
{
	public static void main(String[] args) throws Exception
	{
		OutputStream os = new FileOutputStream("d:/abc/ss.txt",true);
		
		String str = "hello world";
		byte[] buffer = str.getBytes();
		
		os.write(buffer);
		os.close();
	}
}

6、流的又一种分类:

      节点流:从特定的地方读写的流类,例如:磁盘或一块内存区域。
      过滤流:使用节点流作为输入或输出。过滤流是使用一个已经存在的输入流或输出流连接创建的。

7、字节流:字节流类为处理字节式输入/输出提供了丰富的环境。一个字节流可以和其他任何类型的对象并用,包括二进制数据。这样的多功能性使得字节流对很多类型的程序都很重要。字节流类以InputStream和OutputStream为顶层类,他们都是抽象类(abstract);抽象类InputStream和OutputStream定义了实现其他流类的关键方法。最重要的两种方法是read()和write(),它们分别对数据的字节进行读写。两种方法都在InputStream和OutputStream中被定义为抽象方法。它们被派生的流类重写。
    每个抽象类都有多个具体的子类,这些子类对不同的外设进行处理,例如磁盘文件,网络连接,甚至是内存缓冲区;要使用流类,必须导入java.io包

8、InputStream:三个基本的读方法
      abstractint 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。      因为第二个read方法依靠第三个read方法来实现,而第三个read方法又依靠第一个read方法来实现,所以说只有第一个read方法是与具体的I/O设备相关的,它需要InputStream的子类来实现。

InputStream的类层次:

 

InputStream中包含一套字节输入流需要的方法,可以完成最基本的从输入流读入数据的功能。当Java程序需要外设的数据时,可根据数据的不同形式,创建一个适当的InputStream子类类型的对象来完成与该外设的连接,然后再调用执行这个流类对象的特定输入方法来实现对相应外设的输入操作。
InputStream类子类对象自然也继承了InputStream类的方法。常用的方法有:读数据的方法read(),获取输入流字节数的方法available(),定位输入位置指针的方法skip()、reset()、mark()等。

9、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的类层次

 

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

10、缓冲字节流:对于字节流,缓冲流(buffered stream),通过把内存缓冲区连到输入/输出流扩展一个过滤流类。该缓冲区允许Java对多个字节同时进行输入/输出操作,提高了程序性能。因为缓冲区可用,所以可以跳过、标记和重新设置流。缓冲字节流类是BufferedInputStream 和BufferedOutputStream。若处理的数据量较多,为避免每个字节的读写都对流进行,可以使用过滤流类的子类缓冲流。缓冲流建立一个内部缓冲区,输入输出数据先读写到缓冲区中进行操作,这样可以提高文件流的操作效率。

BufferedInputStream:缓冲输入/输出是一个非常普通的性能优化。Java 的BufferedInputStream 类允许把任何InputStream 类“包装”成缓冲流并使它的性能提高
      BufferedInputStream 有两个构造方法
     –BufferedInputStream(InputStream inputStream)
     –BufferedInputStream(InputStream inputStream, int bufSize)
     –第一种形式创建BufferedInputStream流对象并为以后的使用保存InputStream参数in,并创建一个内部缓冲区数组来保存输入数据。
     –第二种形式用指定的缓冲区大小size创建BufferedInputStream流对象,并为以后的使用保存InputStream参数in。

      缓冲一个输入流同样提供了在可用缓冲区的流内支持向后移动的必备基础。除了在任何InputStream类中执行的read()和skip()方法外,BufferedInputStream 同样支持mark() 和reset()方法。BufferedInputStream.markSupported()返回true是这一支持的体现;当创建缓冲输入流BufferedInputStream时,一个输入缓冲区数组被创建,来自流的数据填入缓冲区,一次可填入许多字节。

     –public void mark(intreadlimit):在此输入流中标记当前的位置。对reset方法的后续调用会在最后标记的位置重新定位此流,以便后续读取重新读取相同的字节
     –public void reset():将此流重新定位到对此输入流最后调用mark方法时的位置

BufferedOutputSrteam:缓冲输出流BufferedOutputStream类提供和FileOutputStream类同样的写操作方法,但所有输出全部写入缓冲区中。当写满缓冲区或关闭输出流时,它再一次性输出到流,或者用flush()方法主动将缓冲区输出到流;BufferedOutputStream与任何一个OutputStream相同,除了用一个另外的flush() 方法来保证数据缓冲区被写入到实际的输出设备。BufferedOutputStream通过减小系统写数据的时间而提高性能。

    不像缓冲输入,缓冲输出不提供额外的功能,Java中输出缓冲区是为了提高性能的。下面是两个可用的构造方法
     –BufferedOutputStream(OutputStream outputStream)
     –BufferedOutputStream(OutputStream outputStream, int bufSize)
     –第一种形式创建了一个使用512字节缓冲区的缓冲流。
     –第二种形式,缓冲区的大小由bufSize参数传入。

     用flush()方法更新流;要想在程序结束之前将缓冲区里的数据写入磁盘,除了填满缓冲区或关闭输出流外,还可以显式调用flush()方法。flush()方法的声明为:
    –publicvoidflush()throwsIOException

    –在调用完BufferedOutputStream后一定要flush或者将其close掉,否则缓冲区中的字节不会输出来

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

public class BufferedOutputStreamTest
{
	public static void main(String[] args) throws Exception
	{
		OutputStream os = new FileOutputStream("1.txt");
		
		BufferedOutputStream bos = new BufferedOutputStream(os);
		
		bos.write("http;//www.google.com".getBytes());
		
		bos.close();
		os.close();
	}
}

11、字节数组输入流:ByteArrayInputStream

    ByteArrayInputStream是把字节数组当成源的输入流。该类有两个构造方法,每个构造方法需要一个字节数组提供数据源
   –ByteArrayInputStream(byte array[ ])
   –ByteArrayInputStream(byte array[ ], int start, int numBytes)
   –这里,array是输入源。第二个构造方法创建了一个InputStream类,该类从字节数组的子集生成,以start指定索引的字符为起点,长度由numBytes决定

import java.io.ByteArrayInputStream;

public class ByteArrayInputStreamtest
{
	public static void main(String[] args)
	{
		String temp = "abcd";
		byte[] b = temp.getBytes();
		
		ByteArrayInputStream in = new ByteArrayInputStream(b);
		
		for(int i = 0; i < 3; i++)
		{
			int c;
			while(-1 != (c = in.read()))
			{
				if(0 == i)
				{
					System.out.println((char)c);
				}
				else
				{
					System.out.println(Character.toUpperCase((char)c));
				}
			}
			System.out.println("-----");
			in.reset();
		}
	}
}

ByteArrayInputStream实现mark()和reset()方法。然而,如果mark()不被调用,reset() 在流的开始设置流指针——该指针是传递给构造方法的字节数组的首地址
该例先从流中读取每个字符,然后以小写字母形式打印。然后重新设置流并从头读起,这次在打印之前先将字母转换成大写字母

12、字节数组输出流:ByteArrayOutputStream:

     ByteArrayOutputStream是一个把字节数组当作输出流的实现。ByteArrayOutputStream有两个构造方法
    –ByteArrayOutputStream()
    –ByteArrayOutputStream(intnumBytes)
    –在第一种形式里,一个32位字节的缓冲区被生成。第二个构造方法生成一个numBytes大小的缓冲区。缓冲区保存在ByteArrayOutputStream的受保护的buf成员里。缓冲区的大小在需要的情况下会自动增加。缓冲区保存的字节数是由ByteArrayOutputStream的受保护的count域保存的

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

public class ByteArrayOutputStreamTest
{
	public static void main(String[] args) throws Exception
	{
		ByteArrayOutputStream f = new ByteArrayOutputStream();
		String str = "hello world welcome";
		byte[] buffer = str.getBytes();
		
		f.write(buffer);
		
		byte[] result = f.toByteArray();
		
		for(int i = 0; i < result.length;i++)
		{
			System.out.println((char)result[i]);
		}
		
		OutputStream os = new FileOutputStream("text.txt");
		
		f.writeTo(os);
		
		f.close();
		os.close();
	}
}

该例用writeTo()这一便捷的方法将f 的内容写入test.txt
–writeTo:将此字节数组输出流的全部内容写入到指定的输出流参数中
–reset:将此字节数组输出流的count字段重置为零,从而丢弃输出流中目前已累积的所有输出。通过重新使用已分配的缓冲区空间,可以再次使用该输出流

这里要注意的一点是,对于字节数组输出流,输出的目的地是这个流类自己维护的一个内存字节数组(叫做缓冲区空间),而不是我们指定的,我们仅能指定这个空间的大小(类比FileOutputStream,它的目的地是我们指定的,如磁盘文件“text.txt”),程序中这一句:f.write(buffer);是将buffer这个字节数组写到字节数组输出流中(即f自己维护的缓冲区),这相当于将一个字节数组写到另一个字节数组中。而f.writeTo(os);是将f维护的缓冲区(即字节数组输出流)写到文件输出流中,即写到了磁盘文件中。

13、数据文件流:DataInputStream与DataOutputStream:

提供了允许从流读写任意对象与基本数据类型功能的方法。
•字节文件流FileInputStream和FileOutputStream只能提供纯字节或字节数组的输入/输出,如果要进行基本数据类型如整数和浮点数的输入/输出。则要用到过滤流类的子类二进制数据文件流DataInputStream和DataOutputStream类。这两个类的对象必须和一个输入类或输出类联系起来,而不能直接用文件名或文件对象建立
 流类分层:把两种类结合在一起从而构成过滤器流,其方法是使用一个已经存在的流来构造另一个流。(Pattern Of Decorator)
  比如:FileInputStream fin = new FileInputStream(“employee.dat”);
  DataInputStream din = new DataInputStream(fin);
  double s = din.readDouble();

继承自FilterInputStream和FilterOutputStream的类,比如DataInputStream和BufferedInputStream,可以把它们结合进一个新的过滤流(也即继承自FilterInputStream和FilterOutputStream的类)中以构造你需要的流。如:DataInputStream din = new DataInputStream(new BufferedInputStream (new FileInputStream(“employee.dat”)));

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 DataStream1
{
	public static void main(String[] args) throws Exception
	{
		DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(
				new FileOutputStream("text.txt")));
		byte b =3;
		int i =12;
		char ch = 'a';
		float f =3.4f;
		
		dos.writeByte(b);
		dos.writeInt(i);
		dos.writeChar(ch);
		dos.writeFloat(f);
		
		dos.close();
		
		DataInputStream dis = new DataInputStream(new BufferedInputStream(
				new FileInputStream("text.txt")));
		System.out.println(dis.readByte());
		System.out.println(dis.readInt());
		System.out.println(dis.readChar());
		System.out.println(dis.readFloat());
		
		dis.close();
	}
}

     使用数据文件流的一般步骤
    –(1)建立字节文件流对象;
    –(2)基于字节文件流对象建立数据文件流对象;
    –(3)用流对象的方法对基本类型的数据进行输入/输出。

DataInputStream类的构造方法如下
–DataInputStream(InputStream in)创建过滤流FilterInputStream对象并为以后的使用保存InputStream参数in。
DataOutputStream类的构造方法如下
–DataOutputStream(OutputStream out)创建输出数据流对象,写数据到指定的OutputStream

由于DataOutputStream写入的为二进制信息,所以我们无法使用记事本查看内容;该程序使用DataInputStream将刚才写入文件的二进制信息读取出来显示在命令行中;注意:读取的顺序一定要与写入的顺序完全一致,否则会发生错误

14、I/O流的链接

 

抱歉!评论已关闭.