论坛首页 Java企业应用论坛

Java IO浅析

浏览 35368 次
锁定老帖子 主题:Java IO浅析
精华帖 (15) :: 良好帖 (2) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-01-09   最后修改:2011-04-14

什么是流:

 

流是一个抽象的概念。当Java程序需要从数据源读取数据时,会开启一个到数据源的流。数据源可以是文件,内存或者网络等。同样,当程序需要输出数据到目的地时也一样会开启一个流,数据目的地也可以是文件、内存或者网络等。流的创建是为了更方便地处理数据的输入输出。

 

流分为字节流和字符流。字节流也称为原始数据,需要用户读入后进行相应的编码转换。而字符流的实现是基于自动转换的,读取数据时会把数据按照JVM的默认编码自动转换成字符。

 

字节流由InputStream和OutputStream处理,而字符流由Reader和Writer处理。Reader和Writer是Java后加入的处理类,出于让数据的处理更方便的目的。

 

字节流处理概述:

 

对于字节流处理的类都继承自InputStream和OutputStream这两个抽象类。

 

InputStream提供的最重要的方法是:

 

read();
read(byte[] b) ;
read(byte[] b, int off, int len) ;

 

用于从输入流中读取字节。

 

OutputStream提供的最重要的方法是:

 

write(int b);
write(byte[] b);
write(byte[] b, int off, int len) 
 

用于将字节写入输出流。

 

字节流处理类概述:

 

字节流的处理类有很多,他们都继承自InputStream或者OutputStream抽象类。

 

输入流:

 

先谈谈输入流,输入流中跟数据源直接接触的类有:FileInputStream和ByteArrayInputStream,他们分别实现了从文件或者内存中的字节数组读入数据到输入流。

 

其他的输入流处理类都是装饰类(Decorator模式),下面对他们进行一下简单介绍:

 

BufferedInputStream: 提供了缓冲功能。

DataInputStream: 允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。

PipedInputStream: 允许以管道的方式来处理流。当连接到一个PipedOutputStream后,它会读取后者输出到管道的数据。

PushbackInputStream: 允许放回已经读取的数据。

SequenceInputStream: 能对多个inputstream进行顺序处理。

 

输出流:

 

基本上每个输入流类都有一个相应的输出流类,提供相应的输出流处理。

同样,跟数据目的地直接接触的类有:FileOutputStream和ByteArrayOutputStream,前者实现了把数据流写入文件的功能,后者实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray()toString() 获取数据。

 

下面对其它的装饰类做一下简单介绍:

BufferedOutputStream: 提供了缓冲功能的输出流,在写出完成之前要调用flush来保证数据的输出。

DataOutputStream: 数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。然后,应用程序可以使用数据输入流将数据读入。

PipedOutputStream: 允许以管道的方式来处理流。可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入 PipedOutputStream 对象,并由其他线程从连接的 PipedInputStream 读取。

PrintStream: 为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。我们经常用到的System.out或者System.err都是PrintStream。

 

字符流处理概述:

 

所有的字符流操作类都继承自Reader或者Writer这两个抽象类。

 

Reader提供的重要方法有:

 

read(char[] cbuf);
read(char[] cbuf, int off, int len);
read(CharBuffer target);

 

他们提供了从流中读取数据到字符数组或者CharBuffer的功能。

 

Writer提供的重要方法有:

 

write(char[] cbuf);
write(char[] cbuf, int off, int len);
write(int c);
write(String str);
write(String str, int off, int len);

 

他们提供了把字符、字符数组或者字符串写入流中的功能。

 

字符流处理类概述:

 

输入流:

 

跟数据源直接接触的类:

CharArrayReader: 从内存中的字符数组中读入数据,以对数据进行流式读取。

StringReader:从内存中的字符串读入数据,以对数据进行流式读取。

FileReader:从文件中读入数据。注意这里读入数据时会根据JVM的默认编码对数据进行内转换,而不能指定使用的编码。所以当文件使用的编码不是JVM默认编码时,不要使用这种方式。要正确地转码,使用InputStreamReader。

 

装饰类:

BufferedReader:提供缓冲功能,可以读取行:readLine();

LineNumberReader: 提供读取行的控制:getLineNumber()等方法。

InputStreamReader: 字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。

 

输出流:

 

根数据目的相关的类:

CharArrayWriter:把内存中的字符数组写入输出流,输出流的缓冲区会自动增加大小。输出流的数据可以通过一些方法重新获取。

StringWriter: 一个字符流,可以用其回收在字符串缓冲区中的输出来构造字符串。

FileWriter:把数据写入文件。

 

装饰类:

BufferedWriter:提供缓冲功能。

OutputStreamWriter:字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。

PrintWriter: 向文本输出流打印对象的格式化表示形式。

 

流处理中的其它方法:

 

mark和reset用于重复读取某段的数据,如下代码:

 

is = new BufferedInputStream(new FileInputStream("res/input.data"));
assertTrue(is.available() > 0);
assertTrue(is.markSupported());

// The read limit has no effect.
is.mark(0);

int first = is.read();
int second = is.read();

is.reset();
int firstAgain = is.read();
int secondAgain = is.read();

assertEquals(first, firstAgain);
assertEquals(second, secondAgain);

 

Writer或者OutputStream中的flush(): 刷新该流的缓冲,用于确保数据的输出。

 

close(): 关闭流并释放与之关联的所有系统资源。

   发表时间:2009-01-10  
楼主写的非常的棒
0 请登录后投票
   发表时间:2009-01-10  
条理清晰!谢谢楼主!
0 请登录后投票
   发表时间:2009-01-10  
事实上,一直想研究这么一个主题:
在java里面的一些稍微有点规模的和网络通讯相关框架,都实现了自己IO包,比如Hassian代码里实现了一批HassianOutputStream之类的基于原有java基础io库封装的Hassian专用io库,那么楼主是否研究过,如果你想设计一个网络通讯程序,那么实现自己的io库又是基础的基础,你打算怎么思考几个问题:
1、我是否需要封装自己特有的io组件?是否用标准io库就能满足?
2、这个库该怎么设计,应该在原有标准io库基础上多封装哪些额外的东西?

希望针对这个问题探讨一下
1 请登录后投票
   发表时间:2009-04-10  
写的真好!!
0 请登录后投票
   发表时间:2009-04-10  
这是我看过的关于java IO文章中最清晰的一篇了
0 请登录后投票
   发表时间:2009-04-10  
网络流能reset么?网络流发过去就没了,怎么从头读?
0 请登录后投票
   发表时间:2009-07-13   最后修改:2009-07-13
PipedInputStream
SequenceInputStream
PipedOutputStream
这三个类应该不是装饰类,它们并没有实现FilterInputStream或者FilterOutputstream接口
看一下他们的源代码
/*
 * @(#)PipedInputStream.java	1.43 06/06/19
 *
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package java.io;

/**
 * A piped input stream should be connected
 * to a piped output stream; the piped  input
 * stream then provides whatever data bytes
 * are written to the piped output  stream.
 * Typically, data is read from a <code>PipedInputStream</code>
 * object by one thread  and data is written
 * to the corresponding <code>PipedOutputStream</code>
 * by some  other thread. Attempting to use
 * both objects from a single thread is not
 * recommended, as it may deadlock the thread.
 * The piped input stream contains a buffer,
 * decoupling read operations from write operations,
 * within limits.
 * A pipe is said to be <a name=BROKEN> <i>broken</i> </a> if a
 * thread that was providing data bytes to the connected
 * piped output stream is no longer alive.
 *
 * @author  James Gosling
 * @version 1.40, 12/01/05
 * @see     java.io.PipedOutputStream
 * @since   JDK1.0
 */
public class PipedInputStream extends InputStream {
    boolean closedByWriter = false;
    volatile boolean closedByReader = false;
    boolean connected = false;

	/* REMIND: identification of the read and write sides needs to be
	   more sophisticated.  Either using thread groups (but what about
	   pipes within a thread?) or using finalization (but it may be a
	   long time until the next GC). */
    Thread readSide;
    Thread writeSide;

    private static final int DEFAULT_PIPE_SIZE = 1024;

    /**
     * The default size of the pipe's circular input buffer.
     * @since   JDK1.1
     */
    // This used to be a constant before the pipe size was allowed
    // to change. This field will continue to be maintained
    // for backward compatibility. 
    protected static final int PIPE_SIZE = DEFAULT_PIPE_SIZE;

    /**
     * The circular buffer into which incoming data is placed.
     * @since   JDK1.1
     */
    protected byte buffer[];

    /**
     * The index of the position in the circular buffer at which the
     * next byte of data will be stored when received from the connected
     * piped output stream. <code>in&lt;0</code> implies the buffer is empty,
     * <code>in==out</code> implies the buffer is full
     * @since   JDK1.1
     */
    

/*
 * @(#)SequenceInputStream.java	1.33 06/06/07
 *
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package java.io;

import java.io.InputStream;
import java.util.Enumeration;
import java.util.Vector;

/**
 * A <code>SequenceInputStream</code> represents
 * the logical concatenation of other input
 * streams. It starts out with an ordered
 * collection of input streams and reads from
 * the first one until end of file is reached,
 * whereupon it reads from the second one,
 * and so on, until end of file is reached
 * on the last of the contained input streams.
 *
 * @author  Author van Hoff
 * @version 1.33, 06/07/06
 * @since   JDK1.0
 */
public
class SequenceInputStream extends InputStream {
    Enumeration e;
    InputStream in;

    /**
     * Initializes a newly created <code>SequenceInputStream</code>
     * by remembering the argument, which must
     * be an <code>Enumeration</code>  that produces
     * objects whose run-time type is <code>InputStream</code>.
     * The input streams that are  produced by
     * the enumeration will be read, in order,
     * to provide the bytes to be read  from this
     * <code>SequenceInputStream</code>. After
     * each input stream from the enumeration
     * is exhausted, it is closed by calling its
     * <code>close</code> method.
     *
     * @param   e   an enumeration of input streams.
     * @see     java.util.Enumeration
     */
    public SequenceInputStream(Enumeration<? extends InputStream> e) {
	this.e = e;
	try {
	    nextStream();
	} catch (IOException ex) {
	    // This should never happen
	    throw new Error("panic");
	}
    }

    /**
     * Initializes a newly
     * created <code>SequenceInputStream</code>
     * by remembering the two arguments, which
     * will be read in order, first <code>s1</code>
     * and then <code>s2</code>, to provide the
     * bytes to be read from this <code>SequenceInputStream</code>.
     *
     * @param   s1   the first input stream to read.
     * @param   s2   the second input stream to read.
     */
    public SequenceInputStream(InputStream s1, InputStream s2) {
	Vector	v = new Vector(2);

	v.addElement(s1);
	v.addElement(s2);
	e = v.elements();
	try {
	    nextStream();
	} catch (IOException ex) {
	    // This should never happen
	    throw new Error("panic");
	}
    }

   

/*
 * @(#)PipedOutputStream.java	1.28 06/06/07
 *
 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

package java.io;

import java.io.*;

/**
 * A piped output stream can be connected to a piped input stream 
 * to create a communications pipe. The piped output stream is the 
 * sending end of the pipe. Typically, data is written to a 
 * <code>PipedOutputStream</code> object by one thread and data is 
 * read from the connected <code>PipedInputStream</code> by some 
 * other thread. Attempting to use both objects from a single thread 
 * is not recommended as it may deadlock the thread.
 * The pipe is said to be <a name=BROKEN> <i>broken</i> </a> if a
 * thread that was reading data bytes from the connected piped input 
 * stream is no longer alive.
 *
 * @author  James Gosling
 * @version 1.28, 06/07/06
 * @see     java.io.PipedInputStream
 * @since   JDK1.0
 */
public
class PipedOutputStream extends OutputStream {

	/* REMIND: identification of the read and write sides needs to be
	   more sophisticated.  Either using thread groups (but what about
	   pipes within a thread?) or using finalization (but it may be a
	   long time until the next GC). */
    private PipedInputStream sink;

    /**
     * Creates a piped output stream connected to the specified piped 
     * input stream. Data bytes written to this stream will then be 
     * available as input from <code>snk</code>.
     *
     * @param      snk   The piped input stream to connect to.
     * @exception  IOException  if an I/O error occurs.
     */
    public PipedOutputStream(PipedInputStream snk)  throws IOException {
	connect(snk);
    }
    
    /**
     * Creates a piped output stream that is not yet connected to a 
     * piped input stream. It must be connected to a piped input stream, 
     * either by the receiver or the sender, before being used. 
     *
     * @see     java.io.PipedInputStream#connect(java.io.PipedOutputStream)
     * @see     java.io.PipedOutputStream#connect(java.io.PipedInputStream)
     */
    public PipedOutputStream() {
    }
    
    /**
     * Connects this piped output stream to a receiver. If this object
     * is already connected to some other piped input stream, an 
     * <code>IOException</code> is thrown.
     * <p>
     * If <code>snk</code> is an unconnected piped input stream and 
     * <code>src</code> is an unconnected piped output stream, they may 
     * be connected by either the call:
     * <blockquote><pre>
     * src.connect(snk)</pre></blockquote>
     * or the call:
     * <blockquote><pre>
     * snk.connect(src)</pre></blockquote>
     * The two calls have the same effect.
     *
     * @param      snk   the piped input stream to connect to.
     * @exception  IOException  if an I/O error occurs.
     */
    public synchronized void connect(PipedInputStream snk) throws IOException {
        if (snk == null) {
            throw new NullPointerException();
        } else if (sink != null || snk.connected) {
	    throw new IOException("Already connected");
	}
	sink = snk;
	snk.in = -1;
	snk.out = 0;
        snk.connected = true;
    }

    /**
     * Writes the specified <code>byte</code> to the piped output stream. 
     * <p>
     * Implements the <code>write</code> method of <code>OutputStream</code>.
     *
     * @param      b   the <code>byte</code> to be written.
     * @exception IOException if the pipe is <a href=#BROKEN> broken</a>,
     *		{@link #connect(java.io.PipedInputStream) unconnected},
     *		closed, or if an I/O error occurs.
     */
    public void write(int b)  throws IOException {
        if (sink == null) {
            throw new IOException("Pipe not connected");
        }
	sink.receive(b);
    }

   
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics