戴长秀
对文件进行读写是日常中最常见的一种操作,java语言作为时下比较热门的一种语言,提供了大量的类对文件进行读写操作,如何编写出有效的文件读写代码,本文就此谈谈,以求共勉。
一、 基本概念
1、 文件
文件是存储在磁盘上数据的集合。输入(I)就是要从文件中读取数据,输出(O)就是把数据保存于文件,使得数据具有“永久性”。当然输入输出(I/O)不仅是面向文件,还可以面向键盘、显示器、网络、内存等。
2、 流
流是数据传输的抽象描述,Java语言不能直接对 I/O 设备进行操作,而是在程序和设备之间加入了一种中间介质,这种中间介质被称作流。
3、 输入流/输出流
根据流的流向分为输入流和输出流,输入流是指将数据从文件、标准输入、或其他外部输入设备中加载到内存,输出流是将内存中的数据保存到文件或传输给输出设备。输入输出流还可以理解为以程序为基准的,向程序中输入数据的流称为输入流,从程序输出数据的流称为输出流。
4、 流的分类
从不同的分类方法流可以流可以分成不同的类型,从流的内容划分,流可以分成:
(1)面向字符的流:以字符为单位读写数据
(2)面向字节的流:以字节为单位读写数据
(3)面向对象的流:以对象为单位读写若干个字节的数据
Java语言将文件看作是字节或字符序列的集合,Java语言提供了非常丰富的类来处理文件及文件数据,这些类主要位于“java.io”包中,在使用这些类的时候必须先导入该包:import java.io.*;。
二、 文件读写操作
对文件进行读写操作,以不同的单位进行读写,使用的流类不同,以字符为单位进行读写使用的类有Reader和Writer类及其子类,以字符为单位进行读写使用的类有InputStream和OutputStream类及其子类。
1、 以字符为单位读写文件
Java语言提供了处理以16位的Unicode码表示字符的流类,即以Reader和Writer 为基类派生出的一系列类。从Reader和Writer派生出的一系列类,以16位的Unicode码表示的字符为基本处理单位,无论是什么调试运行环境都可以正确的读取字母、汉字、标点符号等。常用的字符流主要有:
(1)Reader和Writer;抽象类,不能实例化
(2)FileReader和FileWriter;建立与文件对应的输入/输出流
(3)BufferedReader和BufferedWriter。带缓冲的输入/输出流,从内存开辟一块缓冲区存放数据,带缓冲的输入/输出流要先从其它输入/输出流中读写字符到缓冲区,然后再从缓冲区中读写字符。
Reader和Writer是两个抽象类,它们只是提供了一系列用于字符流处理的方法,不能生成这两个类的实例,只能通过使用由它们派生出来的子类对象来处理字符流,即不能使用new Reader()或new Writer(),但是可以Readerrin=new FileReader(String name);或者Writer wout=new FileWriter(String name);使用输入/输出流时会抛出IO异常和文件未找到异常,必须要捕获这些异常。在Reader类中提供了读取字符的方法:
(1)public int read(); 从文件中读取一个字符,返回值为读取的字符的整型值,当返回值为-1时,表示到达文件末尾
(2)public int read(char cbuf[]);读取一系列字符到数组cbuf[]中,返回值为实际读取的字符的数量,当返回值为-1时,表示到达文件末尾
(3)public abstract int read(char cbuf[],intoff,intlen);读取len个字符,从数组cbuf[]的下标off处开始存放,返回值为实际读取的字符数量,该方法必须由子类实现,当返回值为-1时,表示到达文件末尾
在Writer类中提供了写入字符的方法:
(1)public void write(int c);将整型值c的低16位写入当前文件中
(2)public void write(char cbuf[]);将字符数组cbuf[]写入当前文件中
(3)public abstract void write(char cbuf[],intoff,intlen);字符数组cbuf[]中从索引为off的位置处开始的len个字符写入当前文件中
(4)public void write(String str);将字符串str中的字符写入当前文件中
(5)public void write(String str,intoff,intlen);将字符串str中从索引off开始处的len个字符写入当前文件中
(6)public writer append(CharSequencecsq);将字符序列csq添加到当前文件中
(7)public writer append(char c);将字符c添加到当前文件中
(8)public abstract void flush(); 强制输出,使得数据立即写入文件中
例:以字符为单位从指定的“c:/file1.txt”文件中读取,然后写入“c:/file2.txt”文件,核心代码如下:
不带缓冲的:
try{
FileReader fin=new FileReader(“c:/file1.txt”);
FileWriterfout=new FileWriter(“c:/file2.txt”);
int c;
While((c=fin.read())>0) out.write(c);
fin.close();fout.close();
}catch(Exception e){}
带缓冲的:
try{
FileReader fin=new FileReader(“c:/file1.txt”);
FileWriterfout=new FileWriter (“c:/file2.txt”);
BufferedReaderbfin=new BufferedReader(fin);
BufferedWriterbfout=new BufferedWriter(fout);
char c[]=new char[1024];
while((inti=bfin.read(c))>0) bfout.writer(c);
fin.close();fout.close();bfin.close();bfout.close();
}catch(Exception e){}
2、 以字节为单位读写文件
Java语言提供了以字节为单位读写文件的类,它们都是从InputStream和OutputStream派生出来的一系列类,这些类流以字节(byte)为基本处理单位,在使用InputStream和OutputStream类及其子类的时候会抛出异常,必须捕获异常。
常用的字节流主要有:
(1)InputStream和OutputStream;抽象类,不能实例化,同Reader和Writer类类似。
(2)FileInputStream和FileOutputStream;建立与文件对应的输入/输出流。
(3)DataInputStream和DataOutputStream;提供读取基本类型的方法,先从其他流中一个一个字节读写到缓冲区,再从缓冲区一个一个字节读写。
(4)BufferedInputStream和BufferedOutputStream。同以字符为单位带缓冲的输入/输出流类似
以字节为单位读写文件时读写的结果值与代码的调试运行环境有关系,不同的环境使用的字符编码不一样,所以读取的结果值也不相同。如果调试运行环境的字符编码为GBK编码,由于GBK编码中字母、标点符号、数字各占一字节,汉字占2字节,所以当以一个字节读写数据时能正确的读写字母或标点符号或数字的ascii编码,但不能够读写完整的汉字编码,只能读写汉字的GBK编码的其中一个字节。
在InputStream类中读取数据的方法有:
(1)int read()从输入流中读取下一个字节。返回 0 到 255 范围内的int字节值。如果已经到达流末尾而没有可用的字节,则返回值 -1。read()方法读取一个字节,因此只能识别asccii码字符,而无法识别双字节的汉字
(2)int read(byte[] b)输入流中读取多个字节,放入字节数组b中,返回值为读取的字节数,如果无数据可用则返回-1.
(3)int read(byte[] b,intoff,intlen) 从输入流中读取参数len个字节,放入字节数组b中,数据的放置位置从数组b的off位置开始
在OutputStream类中写入数据的方法有:
(1)void write(int b) 将参数b指定的字节写入输出流,通常将b的低8位写入输出流,而忽略b的高24位
(2)void write(byte[] b) 将字节数组b写入输出流
(3)void write(byte[] b,intoff,intlen) 将参数字节数组b从参数off指定的位置开始写入len个字节到输出流
例:以字节为单位从指定的“c:/file1.txt”文件中读取,然后写入“c:/file2.txt”文件,核心代码如下:
不带缓冲的:
try{
FileInputStream fin=new FileInputStream (“c:/file1.txt”);
FileOutputStreamfout=new FileOutputStream(“c:/file2.txt”);
int c;
While((c=fin.read())>0) out.write(c);
fin.close();fout.close();
}catch(Exception e){}
带缓冲的:
try{
FileInputStream fin=new FileInputStream (“c:/file1.txt”);
FileOutputStreamfout=new FileOutputStream (“c:/file2.txt”);
BufferedInputStreambfin=new BufferedInputStream(fin);
BufferedOutputStreambfout=new BufferedOutputStreamr(fout);
byteb[]=new byte[1024];
while((inti=bfin.read(b))>0) bfout.writer(b);
fin.close();fout.close();bfin.close();bfout.close();
}catch(Exception e){}
三、 文件对话框
上述中无论是以字符为单位还是以字节为单位进行文件读写,都是事先在代码中指定文件路径及文件名,文件的读写操作非常不灵活,于是Java语言提供了文件对话框类,方便用户进行文件读写操作,常用的有FileDialog类。FileDialog类调用Windows的操作系统中的API,即调用Windows操作系统中的“保存”对话框(“另存为”文件对话框和保存对话框是一样的)和“打开”对话框。java.awt.FileDialog类是java.awt.Dialog类的子类。文件对话框是一个独立的、可移动的窗口,给用户提供选择文件的操作,结合文件对话框用户在进行文件读写操作时可以根据需要选择相应的文件进行读写。
//以字节为单位读文件核心代码
byte []b1=new byte[1024];
byte []b2=new byte[1024];
dialog=new FileDialog(app);
dialog.setMode(FileDialog.LOAD);
dialog.setVisible(true);
try{
FileInputStream fin=new FileInputStream(dialog.getDirectory()+dialog.getFile());
BufferedInputStreambfin=new BufferedInputStream(fin);
intbytenumber=bfin.read(b1);
String str=new String(b1,0,bytenumber);
fin.close();bfin.close();
}catch(IOException e){ }
//以字节为单位写文件核心代码
dialog.setMode(FileDialog.SAVE);
dialog.setVisible(true);
try{
FileOutputStreamfout=new FileOutputStream(dialog.getDirectory()+dialog.getFile(),true);
BufferedOutputStreambfout=new BufferedOutputStream(fout);
b2=str.getBytes();
bfout.write(b2);
bfout.flush();
fout.close();bfout.close();
}catch(IOException e){ }
总之,无论是以字节为单位还是以字符为单位进行读写文件,都要充分考虑各个流类的特点,结合文件对话框类,选择最合适的流类进行文件读写,以便达到高效、有效地实现文件读写操作。
时间:Dec 5, 2013 3:13:00 PM
录入者:冯春苑