IO流主要分为字节流(8位)和字符流(16位),字节流又分为输入流InputStream和输出流OutputStream,字符流又分为输入流Reader和输出流Writer。其中除了RandomAccessFile不是抽象类外,InputStream,OutputStream,Reader,Writer都是抽象类。关系如下:
输入流常用方法:
1>public abstract int read()
从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。
2>public int read(byte[] b)
从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。以整数形式返回实际读取的字节数。在输入数据可用、检测到文件末尾或者抛出异常前,此方法一直阻塞。
3>public int read(byte[] b,int off,int len)
将输入流中最多 len 个数据字节放入 byte 数组,将读取的第一个字节存储在元素b[off]
中,下一个存储在b[off+1]
中,依次类推。读取的字节数最多等于len
。尝试读取 len 个字节,但读取的字节也可能小于该值。以整数形式返回实际读取的字节数。在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。
4>public long skip(long n)
跳过和丢弃此输入流中数据的 n 个字节。出于各种原因,skip 方法结束时跳过的字节数可能小于该数,也可能为 0。
5>public void mark(int readlimit)
这个方法用于在流的当前位置做个标记,参数readLimit指定这个标记的“长度“,如果从标记处开始往后,已经获取或者跳过了readLimit个字节,那么这个标记失效,不允许再重新回到这个位置(通过reset方法)。mark 的常规协定是:如果方法 markSupported 返回 true,那么输入流总是在调用 mark 之后记录所有读取的字节,并时刻准备在调用方法 reset 时(无论何时),再次提供这些相同的字节。但是,如果在调用 reset 之前可以从流中读取多于 readlimit 的字节,则不需要该流记录任何数据。
6>public void reset()
将此流重新定位到最后一次对此输入流调用 mark 方法时的位置。
7>public boolean markSupported()
测试此输入流是否支持 mark
和 reset
方法。比如InputStream不支持标记,而BufferedInputStream支持。
8>public void close()
关闭此输入流并释放与该流关联的所有系统资源。
输出流常用方法:
1>public abstract void write(int b)
将指定的字节写入此输出流。write
的常规协定是:向输出流写入一个字节。要写入的字节是参数b
的八个低位。b
的 24 个高位将被忽略。
2>public void write(byte[] b)
将 b.length
个字节从指定的 byte 数组写入此输出流。write(b)
的常规协定是:应该与调用write(b, 0, b.length)
的效果完全相同。
3>public void write(byte[] b,int off,int len)
将指定 byte 数组中从偏移量 off
开始的 len
个字节写入此输出流。write(b, off, len)
的常规协定是:将数组b
中的某些字节按顺序写入输出流;元素b[off]
是此操作写入的第一个字节,b[off+len-1]
是此操作写入的最后一个字节。
4>public void close()
关闭此输出流并释放与此流有关的所有系统资源。close
的常规协定是:该方法将关闭输出流。关闭的流不能执行输出操作,也不能重新打开。
一、字节流
顾名思义是以字节形式进行读和写,即以Byte数组形式输入和输出。常用类关系如下:
1、InputStream特有方法:
1>public int available()
返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。
InputStream中的read方法返回int类型,是因为如果文件的二进制表示中存在连续的8个1(十进制为-1),那么会视为已经到文件末尾,结束流的读取。如果使用强制类型转化(值不变的原则),由8位1的byte类型转为32位1的int类型,值还是-1,照样会当成已到达文件末尾。解决方法是在高位补0而不是补1(可通过按位与0xFF实现),此时由-1变为255,不会视作到达文件末尾。此时read方法读到的是255而不是-1,唯一要注意的是此时长度由原来的8位变成了32位。
2、OutputStream方法:
1>public void flush()
刷新此输出流并强制写出所有缓冲的输出字节。flush
的常规协定是:如果此输出流的实现已经缓冲了以前写入的任何字节,则调用此方法指示应将这些字节立即写入它们预期的目标。字节流不需要显示调用flush()方法就可以写入目的地,而字符流一定要显示调用flush()方法才能将内存中的数据写入目的地。
OutputStream中的write方法写流时只写低8位的二进制(byte类型),即使传入的是32位(int类型)也会只截取低8位,这样就解决了InputStream的read方法8位byte类型转换成32int类型的问题。
3、BufferedInputStream与BufferedOutputStream
缓冲流可以提高读写效率,用法与字符缓冲流相同。
二、字符流
顾名思义是以字符形式进行读和写,即以Char数组或String形式输入和输出。常用类关系如下:
1、Reader特有方法:
1>public boolean ready()
判断是否准备读取此流。如果保证下一个 read() 不阻塞输入,则返回 True,否则返回 false。注意,返回 false 并不保证阻塞下一次读取。
2、Writer特有方法:
1>public Writer append(char c)
将指定字符添加到此 writer。
2>public Writer append(CharSequence csq)
将指定字符序列添加到此 writer。
3>public Writer append(CharSequence csq,int start,int end)
将指定字符序列的子序列添加到此 writer。
3、BufferedReader与BufferedWriter:
缓冲流的作用是缓冲要读或写的对象,以提高提写效率。好比如果饮水机只是一滴一滴的水流,那么为了提高喝水的效率,我们不会一直在饮水机旁滴一滴水喝一滴水,而是放一个杯子,等一杯水满了之后再去喝,而这个杯子就起到了缓冲的作用。所以其构造方法的参数就是要提高读写效率的流对象,如果没有该流对象,缓冲流将失去存在的意义。调用close()关闭缓冲流其实就是关闭对应的要提高读写效率的流对象,所以不需要对要提高读写效率的流对象进行关闭。
1>BufferedReader常用子类:
①LineNumberReader
常用方法:
❶public int getLineNumber()
获取所读内容的行号
❷public void setLineNumber(int lineNumber)
设置当前内容行号,下一行的行号将从lineNumber+1开始。
2>BufferedReader常用方法:
public String readLine()
读取一个文本行。通过下列字符之一即可认为某行已终止:换行 ('\n')、回车 ('\r') 或"\r\n",当读到末尾时返回null。注意:不会将换行符与内容一起读入。
3>BufferedWriter常用方法:
public void newLine():写入一个行分隔符。行分隔符字符串由系统属性 line.separator 定义,在Windows系统中换行是用"\r\n"表示,而在Linux系统中换行是用"\n"表示的。
三、RandomAccessFile
RandomAccessFile只能操作文件,提供对文件的读写功能,与普通的输入输出流不一样的是RamdomAccessFile可以任意地访问文件的任何地方,这就是“Random”的意义所在。因此它可用于分段写入,比如其与多线程相结合可应用于“下载”这样一个功能。
构造方法是:
1、RandomAccessFile(File file, String mode) ;
2、RandomAccessFile(String name, String mode)。
mode的值有四个:
"r":以只读文方式打开指定文件。如果你写的话会有IOException。
"rw":以读写方式打开指定文件,不存在就创建新文件,如果存在则不会覆盖。
"rws":相对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
"rwd":相对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。
RandomAccessFile的对象包含一个记录指针,用于标识当前流的读写位置,这个位置可以向前移动,也可以向后移动。RandomAccessFile包含两个方法来操作文件记录指针:
1、long getFilePoint()
记录文件指针的当前位置。
2、void seek(long pos)
将文件记录指针定位到pos位置,可以往前定位,也可以往后定位。
3、skipBytes(int n)
跳过n个字节,只能往后跳,不能往前跳。
RandomAccessFile包含InputStream的三个read方法,也包含OutputStream的三个write方法。同时RandomAccessFile还包含一系列的readXxx和writeXxx方法完成输入输出。
四、其他IO流
1、转换流
转换流的主要作用:
1>字节流向字符流进行转换
2>按指定的字符编码集读写文件
InputStreamReader
用于将字节流转换为字符流,是字节流通向字符流的桥梁。如果不指定字符集编码,该解码过程将使用平台默认的字符编码。构造方法有:
①InputStreamReader isr = new InputStreamReader(InputStream in):构造一个默认编码集的InputStreamReader类的对象。
②InputStreamReader isr = new InputStreamReader(InputStream in,String charset):构造一个指定编码集的InputStreamReader类的对象。
OutputStreamWriter
用于将字节流转换为字符流,是字节流通向字符流的桥梁。如果不指定字符集编码,该解码过程将使用平台默认的字符编码。构造方法有:
①OutputStreamWriter osw = new OutputStreamWriter(OutputStream out):构造一个默认编码集的OutputStreamWriter类的对象。
②OutputStreamWriter osw = new OutputStreamWriter(OutputStream out,String charset);//构造一个指定编码集的OutputStreamWriter类的对象.
2、打印流
字节打印流PrintStream:
常用构造方法有:
1>public PrintStream(File file);创建具有指定文件且不带自动行刷新的新打印流。
2>public PrintStream(File file,String encoding);创建具有指定文件名称和字符集且不带自动行刷新的新打印流。
3>public PrintStream(String fileName);创建具有指定文件且不带自动行刷新的新打印流。
4>public PrintStream(OutputStream out);创建新的打印流。此流将不会自动刷新。
5>public PrintStream(OutputStream out,boolean autoFlush);创建新的打印流。autoFlush如果为 true,则每当写入 byte 数组、调用其中一个 println 方法或写入换行符或字节 ('\n') 时都会刷新输出缓冲区。
字符打印流PrintWriter:
常用构造方法有:
1>public PrintWriter(File file);使用指定文件创建不具有自动行刷新的新PrintWriter。
2>public PrintWriter(File file,String encoding);创建具有指定文件和字符集且不带自动刷行新的新PrintWriter。
3>public PrintWriter(String fileName);创建具有指定文件名称且不带自动行刷新的新PrintWriter。
4>public PrintWriter(Writer out);创建不带自动行刷新的新PrintWriter。
5>public PrintWriter(Writer out,boolean autoFlush);创建新的打印流。autoFlush如果为 true,则每当调用 println、printf或format方法将刷新输出缓冲区时都会刷新输出缓冲区。
6>public PrintWriter(OutputStream out,boolean autoFlush);创建新的打印流。autoFlush如果为 true,则每当调用 println、printf或format方法将刷新输出缓冲区时都会刷新输出缓冲区。
3、合并流SequenceInputStream
用于多个文件合并成一个文件,构造方法:
1>public SequenceInputStream(Enumeration<? extends InputStream> e);将e中的N个输入流合并,当成一个流来处理。
2>public SequenceInputStream(InputStream s1,InputStream s2);将输入流s1和s2合并,当成一个流来处理。
4、对象流ObjectInputStream和ObjectOutputStream
要读或写的对象需要实现Serializable标记接口(接口中没有需要实现类重写的方法就叫作"标记接口"),注意static和transient的成员变量不会被序列化。
5、管道流PipedInputStream和PipedOutputStream
用于多线程的IO流,构造方法是:
1>public PipedInputStream(PipedOutputStream src,int pipeSize):创建一个 PipedInputStream
,使其连接到管道输出流 src
,并对管道缓冲区使用指定的管道大小。
2>public PipedOutputStream(PipedInputStream snk):创建连接到指定管道输入流的管道输出流。写入此流的数据字节稍后将用作 snk 的输入。
6、数据流DataInputStream和DataOutputStream
用于操作基本数据类型,如果写时用writerUTF()方法,那么读时一定要用readUTF()方法才能读取正确,否则由于解码问题会出现乱码。
7、数组流
字节数组流ByteArrayInputStream和ByteArrayOutputStream:
用“流的思想”操作内存中的字节数组,由于都是操作的数组,并没有操作底层资源(如硬盘),所以调用close()方法是无效的,也就是说即使调用了close()之后依然可以调用其他方法而不会抛IO异常,所以不需要关闭流。
构造方法分别是:
1>public ByteArrayInputStream(byte[] buf,int offset,int length):读取数组buf中从offset开始长度为length的内容。
2>public ByteArrayOutputStream(int size):创建一个byte 数组输出流,它具有指定大小的缓冲区容量(以字节为单位),可使用public void writeTo(OutputStream out)方法写到其他目的地。
字符数组流CharArrayReader和CharArrayWriter:
构造方法分别是:
1>public CharArrayReader(char[] buf,int offset,int length):读取数组buf中从offset开始长度为length的内容。
2>public CharArrayWriter(int initialSize):创建一个字符数组输出流,它具有指定大小的缓冲区容量(以字符为单位),可使用public void writeTo(Writer out)方法写到其他目的地。