一、理解流的概念
流是对计算机中输入输出进行的抽象。流是指一连串流动的字符,是以先进先出方式发送信息的通道,在java中流的实现建立在四个抽象类的基础上:InputStream、OutputStream、Reader和Write。其中InputStream/OutputStream设计成输入/输出字节流类,而Reader/Writer设计为输入/输出字符流设计。字节流类和字符流类形成分离的层次结构。一般说来**,处理字符或字符串时应使用字符流类,处理字节或二进制文件对象时应用字节流类。**
InputStream、OutputStream、Reader和Writer这些都是抽象类,任何输入输出都是都可以抽象成为这几个流,流的来源可以是网络,硬盘等等,所以这些抽象类有很多不同的实现类。这里我们主要学习的是以硬盘作为流的来源和目的。输入和输出是以内存作为参照的,也就是凡是流入内存的就是输入,从内存流出的就是输出,记住这点,就不会混乱了。
二、文件字节流类实现
字节流是从InputStream和OutputStream派生出来的一系列类,这一系列流以字节(byte)为基本的处理单位,在命名特点上类名是通常以Stream结尾,如标准的FileInputStream、FileOutputStream、带缓存的BufferedOutputStream、BufferedInputStream等。
我们先看看输入流InputStream,它是一个抽象类,定义了Java流在处理字节输入数据的行为,因此所有的字节输入流都扩展于它。该类下的所有方法都有可能抛出IOException异常。常用的一些方法介绍如下:
int available();//返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数。
void close();//关闭此输入流并释放与该流关联的所有系统资源。
void mark(int readlimit);//在此输入流中标记当前的位置。
boolean markSupported();//测试此输入流是否支持 mark 和 reset 方法。
abstract int read();//从输入流中读取数据的下一个字节。
int read(byte[] b);//从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
int read(byte[] b, int off, int len);//将输入流中最多 len 个数据字节读入 byte 数组。
void reset();//将此流重新定位到最后一次对此输入流调用 mark 方法时的位置。
long skip(long n);//跳过和丢弃此输入流中数据的 n 个字节。
从这些方法上大致可以看出字节输入流的常规处理方法。
**1、文件输入流FileInputStream。**就是把硬盘中的文件内容读取到内存中,我们先在E:盘中新建一个abc.txt文件,并在文件中输入几个英文字符,然后我们再打印在控制台上,示例代码如下:
public void input(){
File file=new File("e://abc.txt");
InputStream input=null;//定义
try{
input=new FileInputStream("e://abc.txt");
//用于保存每次读取出来的数据,一个字节8位
int temp=0;
temp=input.read();
//当文件读取到最后一个适合会返回-1
while(temp!=-1){
//输出出来
System.out.println((char)temp);
//继续读取
temp=input.read();
}
}catch(FileNotFoundException e){
// TODO Auto-generated catch block
e.printStackTrace();
}catch(IOException e){
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try{
input.close();//关闭文件,释放资源
}catch(IOException e){
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
在main方法中调用这个方法,查看控制台是否能读入文件的内容并打印,这里要注意的是,文件流操作完毕后必须要关闭流,否则只要程序没有结束,这个文件会一直占用。
**2、文件输出流FileOuputStream。**就是把内存中的信息输出到硬盘指定的文件中。示例代码如下:
//写入文件
public void output(){
try{
//释放追加信息
OutputStream output=new FileOutputStream("e://abc.txt",true);
/*output.write('I');//一个英文=一个字节
output.write(' ');
output.write('L');
output.write('o');
output.write('v');
output.write('e');
output.write(' ');
output.write('Y');
output.write('o');
output.write('u');*/
output.write('我');//一个汉字=2个字节
output.write('爱');
output.write('中');
output.write('国');
// 关闭文件
// 清空内存缓存
output.flush();
output.close();
}catch(FileNotFoundException e){
// TODO Auto-generated catch block
e.printStackTrace();
}catch(IOException e){
// TODO Auto-generated catch block
e.printStackTrace();
}
}
由上面的代码可见每次只能输出一个字节。我们尝试先输出普通的英文字符,打开abc.txt文件,查看是否已经把内容正确的输出到文件中。然后再尝试输出中文字符,结果发现中文发生了乱码,因为一个中文是使用两个字节保存的,可见字节流对字符的处理并不强大。
三、实例
下面我们自己写一个实现文件复制功能的方法copy(String srcpath,String tarpath),然后我们尝试一下复制一张图片,看看能否复制成功。
public class StuFileStream{
public static void main(String []args)throws Exception{
StuFileStream stream=new StuFileStream();
stream.copy("e://P1080092.jpg", "d://aa.jpg");
}
public void copy(String srcpath,String tarpath){
InputStream input=null;
OutputStream output=null;
try{
input=new FileInputStream(srcpath);
output=new FileOutputStream(tarpath);
// 用于保存每次读取出来的数据(一个字节8位)
int temp = 0;
temp = input.read();//
// 当文件读取到最后一个适合会返回-1;
while (temp != -1) {
// 写到目标文件里
output.write(temp);
temp = input.read();// 继续读取
}
} catch (Exception e) {
// TODO: handle exception
}finally{
//关闭资源
try {
input.close();
output.flush();
output.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}