------Java培训、Android培训、iOS培训、Net培训、期待与您交流! -------
一、IO流简介
Java的IO流是实现输入/输出的基础,它可以方便地实现数据的输入/输出操作,在Java中把不同的输入/输出源(键盘、文件、网络连接等)抽象称为“流”(Stream),通过流的方式允许Java程序使用相同的方式来访问不同的输入/输出源。
Java 把所有的流类型(类和抽象类)都放在Java.io包中,用以实现输入/输出功能。
二、字节流和字符流
字节流可以处理所有类型的数据,操作的数据单元是8位的字节,如MP3、图片、文字、视频等。在读取时,读到一个字节就返回一个字节。在Java中对应的类都以“Stream”或“Reader”结尾。
字符流仅能够处理纯文本数据,操作的数据单元是16位的字符,如txt文本等。在读取时,读到一个或者多个字节,先查找指定的编码表,然后将查到的字符返回。在Java中对应的类都以“Reader” 或“Writer”结尾。
Java的IO流的40多个类都是从以下4个抽象基类派生的:
InputStream/Reader:所有输入流的基类,前者是字节输入流,后者是字符输入流;
OutputStream/Writer:所有输出流的基类,前者是字节输出流,后者是字符输出流;
(1)InputStream/Reader
InputStream和Reader是所有输入流的抽象基类,本身不能创建实例来执行输入,但它们将作为所有输入流的模板,所以它们的方法是所有输入流都可以使用的方法。InputStream和Reader分别有一个用于读取文件的输入流:FileInputStream和FileReader,它们都是节点流——会直接与指定文件关联。
在InputStream里包含以下三个方法:
①int read():从输入流中读取单个字节,返回所读取的字节数据(字节数据可直接转换为int类型);
②int read(byte[]b):从输入流中最多读取b.length个字节的数据,并将其存储在字节数组b中,返回实际读取的字节数;
③int read(byte[]b ,int off, int len):从输入流中最多读取len个字节的数据,并将其存储在数组b中,放入数组b中时,并不是从数组的起点开始,而是从off位置开始,返回实际读取的字节数。
示例:
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamTest {
public static void main(String[] args) throws IOException {
//创建字节输入流
FileInputStream fis = new FileInputStream("FileInputStreamTest.java");
{
//创建 一个长度为1024的数组
byte[] bbuf = new byte[1024];
int hasRead ;
//循环从输入流中取出数据
while ((hasRead = fis.read(bbuf)) >0 ) {
//取出数组中的字节,将字节数组转换成字符串输入
System.out.println(new String(bbuf , 0 , hasRead));
}
}
}
}
运行结果:
将输出上面程序源代码。
在Reader里包含了以下三个方法:
①int read():从输入流中读取单个字符,返回所读取的字符数据(字符数据可直接转换为int类型);
②int read(char[]cbuf):从输入流中最多读取cbuf.length个字符的数据,并将其存储在字符数组cbuf中,返回实际读取的字符数;
③int read(char[]cbuf ,int off, int len):从输入流中最多读取len个字符的数据,并将其存储在字符数组cbuf中,放入数组cbuf中时,并不是从数组的起点开始,而是从off位置开始,返回实际读取的字符数。
示例:
import java.io.FileReader;
import java.io.IOException;
public class FileReaderText {
public static void main(String[] args) throws IOException {
//创建FileReader对象
FileReader fw = new FileReader("F:/eclipse/File/FileWriter.txt");
//读取字符并输出
while (fw.read() != -1){
System.out.print((char)fw.read());
}
fw.close();
}
}
运行结果:
One dream.
上面程序最后使用了fw.close()来关闭该文件输入流,程序里打开的文件IO资源不属于内存里的资源,垃圾回收机制无法回收该资源,使用应该关闭文件IO资源。
(2)OutputStream/Writer
OutputStream和Writer也非常相似,两个流都提供了
①void write(int c):将指定的字节/字符输出到输出流中,其中c既可以代表字节,也可以代表字符;
②void write(byte[]/char[] buf):将字节数组/字符数组中的数据输出到指定输出流中;
③void write(byte[]/char[]buf ,int off, int len):将字节数组/字符数组中从off位置开始,长度为len的字节/字符输出到输出流中。
示例:下面程序使用FileInputStream来执行输入,并使用FileOutputStream来执行输出,用以实现复制FileOutputStreamTest.java文件的功能。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutStreamTest {
public static void main(String[] args) {
try {
//创建字节输入流
FileInputStream fis = new FileInputStream("FileOutStreamTest.java");
//创建字节输出流
FileOutputStream fos = new FileOutputStream("newFile.txt");
byte[] cbuf = new byte[1024];
int hasRead =0;
//循环从输入流中取出数据
while ((hasRead = fis.read(cbuf)) >0 )
{
//取出数组中的字节,将字节数组转换成字符串输入
fos.write(cbuf , 0 , hasRead);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果:
在看到系统当前路径下多了一个文件:newFile.txt,该文件的内容和FileOutputStreamTest.java文件的内容完全相同。
如果希望看到直接输出字符串内容,则使用Writer会有更好的效果,如下程序:
import java.io.FileWriter;
import java.io.IOException;
public class FileWriteText {
public static void main(String[] args) throws IOException {
//创建FileReader对象
FileWriter fw = new FileWriter("poem.txt");
//写入字符串
fw.write("One \r\n");
fw.write("dream \r\n");
fw.write(". \r\n");
}
}
运行结果:
将会在当前目录下输出一个poem.txt文件,文件内容就是程序中输出的内容。
三、带缓存的输入/输出流
缓存可以说是I/O流的一种性能优化。缓存流为I/O流增加了内存缓存区。
(1)BufferedInputStream类与BufferedOutputStream类
BufferedInputStream类可以对任意的InputStream类进行带缓冲区的包装以达到性能的优化。
BufferedInputStream类有两个构造函数:
①BufferedInputStream(InputStream in):构造函数创建了一个带有32个字节的缓存流;
②BufferedInputStream(InputStream in , int size):构造函数按指定的大小创建缓存区。
从构造函数可以看出,BufferedInputStream对象位于InputStream类对象之前,下图描述字节数据读取文件的过程:
示例:
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class MyBufferedInputStream {
public static void main(String[] args) throws IOException {
File f = new File("F:/eclipse/File/FileWriter.txt");
//创建FileInputStream对象
FileInputStream in = new FileInputStream(f);
//创建BufferedInputStream对象
BufferedInputStream bis = new BufferedInputStream(in);
byte[] bytes = new byte[10];
//将字节流数据读取到byte数组中,再将其转换我字符串形式
do{
bis.read(bytes);
System.out.print(new String(bytes));
}while (bis.read() != -1) ;
//关闭BufferedInputStream
bis.close();
}
}
运行结果:
One dream.
使用BufferedOutputStream输出信息和向OutputStream输入信息完全一样,不过BufferedOutputStream有一个flush()方法用来讲缓冲区的数据强制输出完。
BufferedOutputStream类也有两个构造方法:
①BufferedOutputStream(OutputStream in):构造函数创建了一个带有32个字节的缓存区;
②BufferedOutputStream(outputStream in , int size):构造函数按指定的大小创建缓存区。
示例:
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class MyBufferedOutputStream {
public static void main(String[] args) throws IOException {
//创建FileOutStream对象,并指定目录路径
FileOutputStream out = new FileOutputStream("F:/eclipse/File/FileWriter.txt");
//创建BufferedOutputStream对象
BufferedOutputStream bos = new BufferedOutputStream(out);
//定义s类型的字符串
String s = "I have one dream.";
//将字符串传递到bos对象李
bos.write(s.getBytes());
//刷新缓存
bos.flush();
//关闭BufferedOutputStream
bos.close();
}
}
运行结果:
将在FileWriter.txt文件显示程序中的内容。
(2)BufferedReader类与BufferedWriter类
BufferedReader类与BuffferedWriter类分别继承Reader类与Writer类。这两个类同样具有内部缓存机制,并可以行为单位进行输入/输出。
根据BufferedReader类的特点,总结出下图所示的字符数据读取文件的过程:
BufferedReader类常用的方法如下:
①read()方法:读取单个字符;
②readLine()方法:读取一个文本行,并将其返回为字符串;若无数据可读,则返回null;
③write(String s , int off ,int len)方法:写入字符串的某一部分;
④flush()方法:刷新该流的缓存;
⑤newLine()方法:写入一个行分隔符。
在使用BufferedWriter类的Write()方法时,数据并没有立刻被写入至输出流中,而是首先进入缓冲区中。如果想立刻将缓冲区中的数据写入输出流中,要调用flush()方法。
示例:向指定的磁盘文件中写入数据,并通过BufferedReader类将文件中的信息分行显示。
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class MyBuffer {
public static void main(String[] args) {
//定义字符串数组
String str[] = {"I","have","a","dream","."};
//创建文件对象
File file = new File("D://work.txt");
try {
//创建FileWriter类对象
FileWriter fw = new FileWriter(file);
//创建BufferedWriter类对象
BufferedWriter bufw = new BufferedWriter(fw);
//遍历循环数组
for (int i = 0; i < str.length; i++) {
//将字符串数组中元素写入到磁盘文件中
bufw.write(str[i]);
//将数组中的单个元素以单行的形式写入文件
bufw.newLine();
}
//将BufferedWriter关闭
bufw.close();
//将FileWriter关闭
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
//创建FileReader类对象
FileReader fr = new FileReader(file);
//创建BufferedReader类对象
BufferedReader bufr = new BufferedReader(fr);
//创建字符串对象
String s= null;
//声明int型变量
int i = 0;
//如果文件的文本行数不为null,则进入循环
while ((s=bufr.readLine()) != null) {
//将变量做自增运算
i++;
//输出文件数据
System.out.println("第"+i+"行:"+s);
}
//将BufferedReader关闭
bufr.close();
//将FileReader关闭
fr.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果:
第1行:I
第2行:have
第3行:a
第4行:dream
第5行:.