A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 真真姐 中级黑马   /  2012-4-24 13:32  /  2934 人查看  /  5 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

输入输出流的类旁多,种类复杂,互相之间的关系也很交错。
请哪个高手,能够给童鞋们分享分享,哪些常见,哪些重要,如果能给大家分析清楚,他们的用处与区别,我带头加分
比如:主要是这六种,能不能那个详细的给介绍介绍

评分

参与人数 1技术分 +1 收起 理由
贠(yun)靖 + 1

查看全部评分

5 个回复

倒序浏览
从本质上讲,wirter/reader和inputstream/outputstream的最大区别在于encode和decode.

inputstream/outputstream   直接对byte[]进行操作,不会更改任何信息,原原本本的反应数据内容。
writer/reader在操作时会进行decode/encode.   它会根据你的系统属性file.encoding来decode数据。比如你从文件中读取一行,用reader.readLine()返回的string是经过decode的数据。如果你的文件的encoding不等于你的file.encoding的值,就会产生编码错误。

Reader支持16位的Unicode字符输出,InputStream支持8位的字符输出。
Reader和InputStream分别是I/O库提供的两套平行独立的等级机构,

InputStream、OutputStream是用来处理8位元的流,
Reader、Writer是用来处理16位元的流。
而在JAVA语言中,byte类型是8位的,char类型是16位的,所以在处理中文的时候需要用Reader和Writer。

值得说明的是,在这两种等级机构下,还有一道桥梁InputStreamReader、OutputStreamWriter负责进行InputStream到Reader的适配和由OutputStream到Writer的适配。
区别:

InputStream、OutputStream直接操作byte数组。
Reader、Writer在操作时会进行decode、encode,会根据你的系统属性编码格式对数据进行编码或解码。但是当文件的编码格式与当前系统的不一致时,就需要做编码的转换。                  不知有没有 帮助
回复 使用道具 举报
在电脑上对数据的存储有三种方式,一种是外存,一种是内存,一种是缓存。比如电脑上的硬盘,磁盘,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;
}
回复 使用道具 举报
在电脑上对数据的存储有三种方式,一种是外存,一种是内存,一种是缓存。比如电脑上的硬盘,磁盘,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;
}
回复 使用道具 举报
主要就是inputstream和outputstream这两个
其他都属于包装的 ,掌握好上面两个流的用法, 其他的就都会了,
如FileInputStream和FileOutputStream 看开头的单词就知道了,
用来操纵磁盘文件。这些类的构造函数允许你指定它们所连接的文件。
reader和writer是字符流 跟上面两个字节流不一样的就是一个字符一个字符的读写
使用方法都是一样的
详细的子类可以看一下http://www.docin.com/p-351719748.html这个文档

评分

参与人数 2技术分 +1 黑马币 +2 收起 理由
真真姐 + 2 给的链接给力
贠(yun)靖 + 1

查看全部评分

回复 使用道具 举报
楼上哥几个说的很细致。不过上代码,要上得好看点哦,看起来不容易啊。我说一下我对流的认识吧:
java.io中定义了很多流类型(类或抽象类)来实现输入/输出功能;我们可以从不同的角度对其进行分类(这里我从实际实用的角度来分析分类)

首先你得知道你要进行输入还是输出吧!所以
1,根据数据流向的不同,分为输入流和输出流。
        输入流主要由InputStream和Reader作为基类,这一类输入流(包括其派生类),是将数据读到内存中。
       输出流主要是由OutputStream和Writer作为基类,这一类输出流(包括其派生类),是将内存中数据写入到磁盘中。

确定了是输入还是输出操作之后,你是不是就要考虑要以什么样的单位来处理流了吧!所以
2,根据数据处理单位不同,分为字节流和字符流。
     字节流操作的最小数据单元是8位的字节,主要是由InputStream和OutputStream作为基类。
     字符流操作的最小数据单元是16位的字符。主要是由Reader和Writer作为基类。

接着,你是不是该确定你要怎么样输入和输出吧,也就是直接(节点式)还是间接(包装式),所以
3,根据你的对流的包装方式,分为节点流和处理流。
    节点流是从一个特定的数据源(节点)读写数据,没有对流包装。图为:
      
     处理流是连接在已存在的节点流或处理流之上,再对流的又一次包装,就像管子外再套个管子来输入输出水一样,进而达到更为方便强大的
     读写功能。图为:
   
    比如PrintStream,BufferedReader都是处理流(对流进行了包装)。
对于这么多的流(类或者子类)你看他们的继承树,用起来就爽多了。
   

评分

参与人数 2技术分 +1 黑马币 +3 收起 理由
职业规划-刘倩老师 + 1
真真姐 + 3 兄弟给的很直观

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马