在变量、数组和对象中存储的数据是暂时存在的,程序结束后他们就会丢失。为了能够永久地保存程序创建的数据,可以将其保存在磁盘文件中,这样就可以再其他程序中使用他们。Java的I/O技术可以将数据保存到文本文件、二进制文件甚至是ZIP压缩文件中,以达到永久性保存数据的要求。
流是一组有主的数据序列,根据操作的类型,可分为输入流和输出流两种。I/O(Input/Output,输入/输出)流提供了一条通道程序,可以使用这条通道把源中的字节序列送到目的地。虽然I/O流通常与磁盘文件存取有关,但是程序的源和目的地也可以使键盘、鼠标、内存或显示器窗口等。
Java由数据流处理输入/输出模式,程序从指向源的输入流中读取源中的数据,源可以使文件、网络、压缩包或其他数据源。
输出流的志向是数据要到达的目的地,程序通过向输出流中写入数据把信息传递到目的地。输出流的目标可以是文件、网络、压缩包、控制台和其他数据输出目标。
Java语言定义了许多类专门负责各种方式的输入/输出,这些类都被放在java.io包中。其中,所有输入流类都是抽象类InputStream(字节输入流)或抽象类Reader(字符输入流)的子类;而所有输出流都是抽象类OutputStream(字节输出流)或抽象类Writer(字符输出流)的子类。
InputStream类是字节输入流的抽象类,是所有字节输入流的父类。
该类中所有方法遇到错误时都会引发IOException异常。其方法有:
方法 | 功能描述 |
---|---|
read() | 从输入流中读取数据的下一个字节。返回0~255范围内的int字节值。如果因为已经到达流尾而没有可用的字节,则返回值为-1。 |
read(byte[] b) | 从输入流中读入一定长度的字节,并以整数的形式返回字节数。 |
mark(int readlimit) | 在输入流的大年位置放置一个标记,readlimit参数告知此输入流在标记位置失效前允许读取的字节数。 |
reset() | 将输入指针返回到当前所做的标记处。 |
skip(long n) | 跳过输入流上的n个字节并返回实际跳过的字节数。 |
markSupported() | 如果当前流支持mark()/reset()操作就返回true。 |
close() | 关闭此输入流并释放与该流关联的所有系统资源。 |
注意:并不是所有的InputStream类的子类都支持InputStream中定义的所有方法,如skip()、mark()、reset()等方法只对某些子类有用。
Java中的字符是Unicode编码,是双字节的。InputStream是用来处理字节的,并不适合处理字符文本。Java为自富文本的输入串门提供了一套单独的类Reader,但Reader类并不是InputStream类的替换者,只是在处理字符串时简化了编程。Reader类是字符输入流的抽象类,所有字符输入流的实现都是它的子类。Reader类的具体层次结构如图所示:
OutputStream类是字节输出流的抽象类,此抽象类是表示输出字节流的所有类的超类。
OutputStream类中所有的方法均返回void,在遇到错误时会引发IOException异常。其方法有:
方法 | 功能描述 |
---|---|
write(int b) | 将指定的字节写入此输出流 |
write(byte[] b) | 将b个字节从指定的byte数组写入此输出流 |
write(byte[] b,int off,int len) | 将制定byte数组中从偏移量off开始的len个字节写入此输出流 |
flush() | 彻底完成输出并清空缓存区 |
close | 关闭输出流 |
Writer类是字符输出流的抽象类,所有字符输出类的实现都是它的子类。Writer类的层次结构如图所示:
程序运行期间,大部分数据都在内存中进行操作,当程序结束或关闭是,这些数据将消失。如果需要将数据永久保存,可使用文件输入输出流与指定的文件建立连接,将需要的数据永久保存,可使用文件输入/输出流与指定的文件建立连接,将需要的数据永久保存到文件中。
File类是java.io包中唯一代表磁盘文件本身的对象。File类定义了一些与平台无关的方法来操作文件,可以通过调用File类中的方法,实现创建、删除、重命名文件等操作。File类的对象主要用来获取文件本身的一些信息,如文件所在的目录、文件的长度、文件读写权限等。数据类可以将数据写入到文件中,文件也是数据流最常用的数据媒体。
方法 | 返回值 | 说明 |
---|---|---|
getName() | String | 获取文件的名称 |
canRead() | boolean | 判断文件是否为可读的 |
canWrite() | boolean | 判断文件是否可被写入 |
exits() | boolean | 判断文件是否存在 |
length() | long | 获取文件的长度(以字节为单位) |
getAbsolutePath() | String | 获取文件的绝对路径 |
getParent() | String | 获取问价你的父路径 |
isFile() | boolean | 判断文件是否存在 |
isDirectory() | boolean | 判断文件是否为一个目录 |
isHidden() | boolean | 判断文件是否为隐藏文件 |
lastModified() | long | 获取文件最后修改时间 |
FileInputStream与FileOutputStream类都用来操作磁盘文件。如过读取需求比较简单,则可以使用FileInputStream类,该类继承自InputStream类。FileOutputStream类与之对应。
使用FileOutputStream类想文件中写入数据与使用FileInputStream类从文件中将内容读取出来,都存在一点不足,即这两个类都只提供了对字节或字节数组的读取方法。由于汉子在文件中占用两个字节,如果使用字节流,读取不好可能会出现乱码现象,此时采用字符流Reader或Writer类就可以避免。
FileReader和FileWriter字符流对应了FileInputStream和FileOutputStream类。FileReader流顺序地读取文件,只要不关闭流,每次调用read()方法就顺序地读取源中其余的内容,直到源的末位或流被关闭。
FileReader和FileWriter字符流的应用实例:
public class FileDemo {
public void FileReader(){
File file = new File("F:\\io\\io.txt");
//字符流读取文件信息
try {
char[] charArray = new char[1024];
//创建一个char数组,用于读取打印文本信息
FileReader fr = new FileReader(file);
int length = fr.read(charArray);
for(int i = 0 ; i < length ; i++){
System.out.print(charArray[i]);
}
fr.close();//关闭流
} catch (FileNotFoundException e) {
System.out.println("文件没有找到" + e);
} catch (IOException e) {
System.out.println("文件读取失败" + e);
}
}
public void FileWriter(){
File file = new File("F:\\io\\io_1.txt");
try {
FileWriter fw = new FileWriter(file,true);
String s = "生产快乐的地方!";
fw.write(s, 0, s.length());//将字符串写入文件
fw.close();
} catch (IOException e) {
System.out.println("文件写入异常" + e);
}
}
public static void main(String[] args) {
FileDemo fd = new FileDemo();
fd.FileReader();
fd.FileWriter();
}
}
缓存是I/O的一种性能优化。缓存流尾I/O流增加了内存缓存区。有了缓存区,使得在流上执行skip()、mark()、reset()方法都成为可能。
BufferedInputStream类可以对所有InputStream类进行带缓存区的包装以达到性能的优化。使用BufferedOutputStream输出信息和用OutputStream输出信息完全一样,只不过BufferedOutputStream有一个flush()方法用来将缓存区的数据强制输出完。
BufferedReader与BufferedWriter类分别继承Reader类与Writer类。这两个类同样具有内部缓存机制,并可以以行为单位进行输入/输出。
public class FileDemo {
/**
*带缓存的输入/输出流
*/
public void BufferedRW(){
File file = new File("F:io\\io.txt");
File fileW = new File("F:\\io\\io_2.txt");
try {
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
//读取文件并使其存入缓存区
FileWriter fw = new FileWriter(fileW);
BufferedWriter bw = new BufferedWriter(fw);
//缓冲流
String info = br.readLine();
//用来接收缓冲流读取的字符串
while(info != null){
bw.write(info);
//写入信息
bw.newLine();
info = br.readLine();
//换行继续读取信息
}
br.close();
bw.close();
//输入/输出流关闭
} catch (FileNotFoundException e) {
System.out.println("文件没有找到" + e);
} catch (IOException e) {
System.out.println("文件读写失败" + e);
}
}
/**
*有2个文本文件x和y,
*将x文件中的信息和y中的信息全部写入z文件中,
*并且y中的信息在x的后面
*/
public void fileXYZ(){
File fileX = new File("F:\\io\\io.txt");
File fileY = new File("F:\\io\\io_1.txt");
File fileZ = new File("F:\\io\\io_Z.txt");
try {
FileReader frX = new FileReader(fileX);
BufferedReader brX = new BufferedReader(frX);
//读取x文件中的信息
FileReader frY = new FileReader(fileY);
BufferedReader brY = new BufferedReader(frY);
//读取y文件中的信息
FileWriter fw = new FileWriter(fileZ);
BufferedWriter bw = new BufferedWriter(fw);
//创建z文件的缓冲流
String infoX = brX.readLine();
String infoY = brY.readLine();
while(infoX != null){
bw.write(infoX);
bw.newLine();
infoX = brX.readLine();
}//读取并写入x文件中信息
while(infoY != null){
bw.write(infoY);
bw.newLine();
infoY = brY.readLine();
}//读取并写入y文件中信息
brX.close();
brY.close();
bw.close();
//关闭流
} catch (FileNotFoundException e) {
System.out.println("文件没有找到" + e);
} catch (IOException e) {
System.out.println("文件读写失败" + e);
}
}
public static void main(String[] args) {
FileDemo fd = new FileDemo();
fd.BufferedRW();
fd.fileXYZ();
}
}