锁定老帖子 主题: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 数组。缓冲区会随着数据的不断写入而自动增长。可使用
下面对其它的装饰类做一下简单介绍: BufferedOutputStream: 提供了缓冲功能的输出流,在写出完成之前要调用flush来保证数据的输出。 DataOutputStream: 数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。然后,应用程序可以使用数据输入流将数据读入。 PipedOutputStream: 允许以管道的方式来处理流。可以将管道输出流连接到管道输入流来创建通信管道。管道输出流是管道的发送端。通常,数据由某个线程写入 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: 字节流通向字符流的桥梁:它使用指定的
输出流:
根数据目的相关的类: CharArrayWriter:把内存中的字符数组写入输出流,输出流的缓冲区会自动增加大小。输出流的数据可以通过一些方法重新获取。 StringWriter: 一个字符流,可以用其回收在字符串缓冲区中的输出来构造字符串。 FileWriter:把数据写入文件。
装饰类: BufferedWriter:提供缓冲功能。 OutputStreamWriter:字符流通向字节流的桥梁:可使用指定的 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(): 关闭流并释放与之关联的所有系统资源。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-01-10
楼主写的非常的棒
|
|
返回顶楼 | |
发表时间:2009-01-10
条理清晰!谢谢楼主!
|
|
返回顶楼 | |
发表时间:2009-01-10
事实上,一直想研究这么一个主题:
在java里面的一些稍微有点规模的和网络通讯相关框架,都实现了自己IO包,比如Hassian代码里实现了一批HassianOutputStream之类的基于原有java基础io库封装的Hassian专用io库,那么楼主是否研究过,如果你想设计一个网络通讯程序,那么实现自己的io库又是基础的基础,你打算怎么思考几个问题: 1、我是否需要封装自己特有的io组件?是否用标准io库就能满足? 2、这个库该怎么设计,应该在原有标准io库基础上多封装哪些额外的东西? 希望针对这个问题探讨一下 |
|
返回顶楼 | |
发表时间:2009-04-10
写的真好!!
|
|
返回顶楼 | |
发表时间:2009-04-10
这是我看过的关于java IO文章中最清晰的一篇了
|
|
返回顶楼 | |
发表时间:2009-04-10
网络流能reset么?网络流发过去就没了,怎么从头读?
|
|
返回顶楼 | |
发表时间: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<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); } |
|
返回顶楼 | |
浏览 35407 次