在电脑上对数据的存储有三种方式,一种是外存,一种是内存,一种是缓存。比如电脑上的硬盘,磁盘,U盘等都是外存,在电脑上有内存条,缓存是在CPU里面的。外存的存储量最大,其次是内存,最后是缓存,但是外存的数据的读取最慢,其次是内存,缓存最快。这里总结从外存读取数据到内存以及将数据从内存写到外存中。对于内存和外存的理解,我们可以简单的理解为容器,即外存是一个容器,内存又是另外一个容器。那又怎样把放在外存这个容器内的数据读取到内存这个容器以及怎么把内存这个容器里的数据存到外存中呢?在Java中提供了输入输出相关的类,这些类在java.io包中,java中将输入输出抽象称为流,就好像水管,将两个容器连接起来。将数据冲外存中读取到内存中的称为输入流,将数据从内存写入外存中的称为输出流。在次以文件输入流和文件输出流为例说明数据的读取和写入的操作。
查阅API文档可知,文件输入流FileInputStream只有一个构造器FilterInputStream(InputStream in),它传入一个InputStream类型的参数。知道了构造方法,就可以实例化一个FileInputStream类的对象。要将数据从硬盘上读取到内存中,首先要定义一个FileTest类,再定义一个方法readFile(),给该方法传入一个要读取某个文件路径的字符串形参,最后返回一个字符串值。在方法中首先需要一个FileInputStream类的对象,所以要实例化一个FileInputStream类的对象:java.io.FileInputStream fis = new java.io.FileInputStream(path);在实例化对象时会提示有异常错误,这里先不讨论异常机制,就按固定的格式:try{ }catch(Exception ct){ct.printStackTrace();}处理就行了。创建对象之后就可以用该类的方法对数据读取了。首先要读取文件的长度,可以用方法available(),然后读取文件中的数据,可以用read()读取,该方法只能一个字节一个字节的读取数据。最后要实例化一个byte数组,它的作用是将读取到的数据保存到数组中,还需要一个whlie循环将所有数据读取到数组中,还需要注意的是read()方法当读取完最后一个字节,在读取一遍时,这时返回的结果是-1。最后读取完之后别忘了用close()方法将输入流关闭。具体代码如下:
/**
* 读入给定路径文件的数据
* @param path:给定的路径
* @return:返回字符串类型的数据
*/
public String readFile(String path){
try{
//创建文件输入流对象
java.io.FileInputStream fis = new java.io.FileInputStream(path);
//获取文件的长度
int len = fis.available();
//根据文件的长度创建一个字节数组,保存从文件读取到的数据
byte[] bt = new byte[len];
//读入一个字节
int bj = fis.read();
int i=0;
while (bj!=-1){
//将读取的字节放入到数组中
bt[i]=(byte)bj;
//继续读取下一个字节
bj = fis.read();
i++;
}
要把数据从内存中写入到外存中的指定的文件里的方法和上面的方法差不多。与之对应的有一个FileOutputStream类,该类有五个构造方法,这里使用FileOutputStream(String name)这个构造方法实例化一个对象。首先要定义一个writeFile()方法,再给该方法传入指定的文件路径和要写出的数据的两个字符串形参。然后实例化一个java.io.FileOutputStream fs = new java.io.FileOutputStream(path);跟上面一样也会报出异常错误,处理方法和上面是一样的。再将要写出的字符串前要先把字符串转化为字节数组,在String类中有一个方法getBytes()
可以将字符串转化为字节数组。然后要遍历得到的字节数组,将字节数组中的每个元素依次写出。最后别忘了要用fs.flush();和fs.close()两个方法分别将输出流中的字节强制输出和关闭输出流。具体代码如下:
/**
* 将数据写入指定文件
* @param path:指定的文件
* @param content:写入的数据
*/
public void writeFile(String path,String content){
try{
//创建输出流对象
java.io.FileOutputStream fs = new java.io.FileOutputStream(path);
//将字符串转成字节数组
byte[] b = content.getBytes();
//遍历数组
for (int i=0;i<b.length;i++){
//写入数据
fs.write(b[i]);
}
//强制写出输出流中所有字节
fs.flush();
//关闭流
fs.close();
}catch(Exception et){
et.printStackTrace();
}
}
上面两个方法写完之后,先调用第一个方法在调用第二个方法就可以完成文件的复制。但是这种复制存在两个问题,第一是复制的速度太慢,第二是有些文件复制之后是乱码,不能查看。要解决这两个问题,首先要分析上面两个方法的执行过程,看到第一个方法用到了数组,第二个方法要把字符串转化为字节数组。所以可以考虑不要用数组,并且不要把字符串转化为字节数组。所以要一边读入数据一边写出数据,这样不仅把前面的两个问题解决了,而且代码还简洁了不少,具体代码如下所示:
/**
* 文件复制的方法
* @param srcPath
* @param destPath
* @return
*/
public boolean copyFile(String srcPath, String destPath) {
try{
//创建输入流对象
java.io.FileInputStream fis = new java.io.FileInputStream(srcPath);
//创建输出流对象
java.io.FileOutputStream fos = new java.io.FileOutputStream(destPath);
//读入一个字节的数据
int rd = fis.read();
while (rd!=-1){
//将内存中的数据写到硬盘的文件
fos.write(rd);
//继续读入数据
rd = fis.read();
}
//关闭输入流
fis.close();
//强制写出输出流中剩余数据
fos.flush();
//关闭输出流
fos.close();
return true;
}catch(Exception ct){
ct.printStackTrace();
}
return false;
}
经过上面的代码的修改之后,复制文件基本没有问题,但是当复制比较大的文件时速度还是很慢,这时就需要输入输出缓冲流,他们分别是BufferedInputStream和BufferedOutputStream。
他们的使用入一下代码所示:
/**
* 文件复制的方法
*
* @param srcPath
* @param destPath
* @return
*/
public boolean copyFile(String srcPath, String destPath) {
try{
//创建输入流对象
java.io.FileInputStream fis = new java.io.FileInputStream(srcPath);
//创建输出流对象
java.io.FileOutputStream fos = new java.io.FileOutputStream(destPath);
//创建输入缓冲流
java.io.BufferedInputStream bis = new java.io.BufferedInputStream(fis);
//创建输出缓冲流
java.io.BufferedOutputStream bos = new java.io.BufferedOutputStream(fos);
//读入一个字节的数据
int rd = bis.read();
while (rd!=-1){
//将内存中的数据写到硬盘的文件
bos.write(rd);
//继续读入数据
rd = bis.read();
}
//关闭输入流
fis.close();
//强制写出输出流中剩余数据
fos.flush();
//关闭输出流
fos.close();
return true;
}catch(Exception ct){
ct.printStackTrace();
}
return false;
}
|