`
andyhu1007
  • 浏览: 199504 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论
阅读更多

什么是流:

 

流是一个抽象的概念。当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(): 关闭流并释放与之关联的所有系统资源。

分享到:
评论
7 楼 jiyanliang 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);
    }

   
6 楼 unsid 2009-04-10  
网络流能reset么?网络流发过去就没了,怎么从头读?
5 楼 jiyanliang 2009-04-10  
这是我看过的关于java IO文章中最清晰的一篇了
4 楼 DoubleEO 2009-04-10  
写的真好!!
3 楼 unsid 2009-01-10  
事实上,一直想研究这么一个主题:
在java里面的一些稍微有点规模的和网络通讯相关框架,都实现了自己IO包,比如Hassian代码里实现了一批HassianOutputStream之类的基于原有java基础io库封装的Hassian专用io库,那么楼主是否研究过,如果你想设计一个网络通讯程序,那么实现自己的io库又是基础的基础,你打算怎么思考几个问题:
1、我是否需要封装自己特有的io组件?是否用标准io库就能满足?
2、这个库该怎么设计,应该在原有标准io库基础上多封装哪些额外的东西?

希望针对这个问题探讨一下
2 楼 njuptsoz 2009-01-10  
条理清晰!谢谢楼主!
1 楼 yanlv1983 2009-01-10  
楼主写的非常的棒

相关推荐

    JavaNIO浅析IO模型Java开发Java经验技巧共1

    在Java传统的IO模型中,IO操作基于流(Stream)进行,数据通常是单向流动的,且以字节或字符为单位。而NIO引入了通道(Channel)和缓冲区(Buffer)的概念,数据可以在通道间双向传输,并通过缓冲区进行批量读写,提高了...

    Java NIO:浅析IO模型_动力节点Java学院整理

    Java NIO:浅析IO模型 Java NIO是Java语言中用于高性能I/O操作的API,理解IO模型是学习Java NIO的基础。本文将从同步和异步的概念开始,然后介绍阻塞和非阻塞的区别,接着介绍阻塞IO和非阻塞IO的区别,最后介绍五种...

    java 声音技术浅析

    Java声音技术浅析 在Java世界里,多媒体技术的集成一直是开发者关注的焦点,其中声音技术尤为关键。本文将深入探讨Java对声音处理的支持,包括Applet中的声音播放、Java应用程序中的声音处理以及JavaX中Sound包的...

    浅析Java IO相关知识点

    Java IO(Input/Output)是Java编程语言中用于处理输入输出操作的重要部分,涉及与外部设备、文件系统、网络通信的交互。理解Java IO的工作原理和相关知识点对于开发者来说至关重要,尤其是在进行系统级编程和高性能...

    高性能IO模型浅析

    ### 高性能IO模型浅析 #### 一、同步阻塞IO (Blocking IO) 同步阻塞IO是最传统也是最简单的IO模型。在这种模型下,当应用程序(用户线程)发起IO请求时,它将被完全阻塞,直到IO操作完成。这种阻塞发生在内核空间...

    浅析Java.IO输入输出流 过滤流 buffer流和data流

    Java.IO包是Java语言中用于处理输入输出的核心包之一,提供了一系列用于读取和写入数据流的类和接口,这些流支持不同的数据类型(字节或字符)以及不同的数据源(如文件、网络连接等)。本文将重点探讨Java.IO中的...

    Java 反射机制浅析

    2. **序列化与反序列化**:序列化框架如Java的`java.io.Serializable`接口,通常利用反射来处理类的字段。 3. **ORM框架**:如Hibernate,使用反射来映射数据库记录到Java对象。 4. **测试工具**:JUnit等测试框架...

    Socket高性能IO模型浅析

    (3)IO多路复用(IOMultiplexing):即经典的Reactor设计模式,有时也称为异步阻塞IO,Java中的Selector和Linux中的epoll都是这种模型。(4)异步IO(AsynchronousIO):即经典的Proactor设计模式,也称为异步非...

    JAVA Socket超时浅析 转.doc

    // 其他IO异常处理 } finally { // 关闭Socket socket.close(); } ``` 5. 抓包示例 为了更好地理解Socket的超时行为,可以使用网络抓包工具(如Wireshark)来观察TCP报文交互。通过抓包,你可以看到SYN、SYN+...

    JAVA高级编程资料

    此外,JAVA NIO(New IO)提供了一种非阻塞I/O模型,通过选择器(Selector)和通道(Channel)提高网络通信的效率。 文件与流是JAVA操作数据的重要手段。JAVA的File类提供了文件操作的基本功能,如创建、删除、...

    浅析Java_web程序之客户端和服务器端交互原理.doc

    在Java中,可以通过`java.net.Socket`类创建和管理TCP连接,`java.io.InputStream`和`java.io.OutputStream`用于读写数据,`PrintWriter`用于向客户端发送响应。 总的来说,Java Web程序中的客户端和服务器端交互...

    浅析若干Java序列化工具编程开发技术共13页.pdf.z

    标题中的“浅析若干Java序列化工具编程开发技术”表明,这份资料主要关注的是Java编程中的序列化技术,这是Java开发中的一个重要概念。序列化是将对象的状态转换为可存储或可传输的形式的过程,这对于持久化数据、...

    浅析几种Java播放音频技术及实例.zip

    在Java编程语言中,播放音频是一项常见的需求,无论是游戏开发、音乐播放软件还是教育应用,都需要音频处理功能。本文将深入探讨几种Java播放音频的技术,并通过实例解析它们的使用方法。 1. Java Sound API(Java...

    Java基础知识点 - 内容比较全面

    4. **Java IO流相关知识**:IO流分为字节流和字符流,进阶有缓冲流、转换流、对象流等。NIO(New Input/Output)提供了非阻塞I/O操作,更适用于高并发场景。 5. **JVM ClassLoader机制**:ClassLoader负责加载类到...

    浅析《Java程序设计》的微课设计与实现.zip

    在本压缩包中,主要包含了一份关于“浅析《Java程序设计》的微课设计与实现”的PDF文档,这显然是一份深入探讨如何利用微课技术来教授Java编程的资料。微课是一种短小精悍的教学模式,通常涵盖一个特定的主题或技能...

    浅析Comet技术在Java Web实时系统开发中的应用.pdf

    Java的非阻塞IO(Non-blocking IO)技术在这种情况下尤为重要,它能有效地处理长时间的连接,避免线程资源的过度消耗。 非阻塞IO是Java提供的一种高效处理大量并发连接的技术,通过Java的NIO库实现。在非阻塞模式下...

    深入浅析Java Object Serialization与 Hadoop 序列化

    深入浅析Java Object Serialization与 Hadoop 序列化 序列化是指将结构化对象转化为字节流以便在网络上传输或者写到磁盘永久存储的过程。Java 中的序列化是通过实现 Serializable 接口来实现的,而 Hadoop 序列化则...

    浅析《Java程序设计》课程的整体教学设计.zip

    3. 高级主题:涵盖异常处理、多线程、集合框架、IO流等内容,增强学生的编程技巧。 4. 项目实践:安排实际的编程项目,让学生运用所学知识解决实际问题。 三、教学方法 1. 案例驱动:以生动的实例引入新概念,使...

    浅析Comet技术在Java Web实时系统开发中的应用.docx

    Java通过非阻塞I/O(Non-Blocking IO)解决了这个问题。非阻塞I/O允许服务器在一个线程中处理多个连接,提高了处理大量并发连接的效率。Java的NIO(New I/O)库提供了这样的功能,使得服务器可以在不阻塞其他连接的...

Global site tag (gtag.js) - Google Analytics