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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 曹昌豪 中级黑马   /  2012-5-28 13:17  /  3381 人查看  /  6 人回复  /   1 人收藏 转载请遵从CC协议 禁止商业使用本文

现在抽时间系统的总结下前面的要点内容,集合比较的顺利,也写的很好,但是IO这块怎么就没什么概念呢,这个样子,集合这块:
集合分两大接口,Collection和Map,按照存储对象形式不同分的,Collection接口的子接口List和set。这是根据存储时顺序分的,下面的实现类是按照具体功能分的,Map也是一样,总结完集合这块就没什么了。但是io这块也会用就是没什么概念,总结不出它的体系结构来,哪位大侠给支招,不胜感激!!!

6 个回复

倒序浏览
Java用于操作流的对象都在io包中:
流按操作数据分为:字节流和字符流
流按流向分为:输入流,输出流
编码表:
只要是字符都有编码,常见的编码表有
ascii
gb2312
gb2312扩容后为gbk
国际标准码表:unicode都用2个字节
unicode优化、简化后为utf-8码表,部分字符用2个字节
gbk到utf-8可能产生乱码,因此基于字节流产生字符流,基于字节流,融合了编码表,
也可以指定编码方式。

io流中包括4个基类:
字节流抽象基类
InputStream
OutputStream
字符流抽象基类
Reader
Writer

需求:在硬盘上,创建一个文件并写入一些文字数据。
找到一个专门用于操作文件的Writer子类对象。FileWriter。
import java.io.*;
创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件,而且该文件被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。明确数据要存放的目的地。
public static void main(String[] args) throws IOExpression{
抛出IOExpression
FileWriter fw = new FileWriter("demo.txt");
//写入字符串,写入到流中,不直接写入文件
fw.write("abcde");
//刷新流对象中的缓冲中数据
fw.flush();   ××
//关闭流资源关闭之前会刷新一次内部的缓冲中的数据,将数据刷到目的地中,和
flush区别:刷新后,流可继续使用,close刷新后,会将流关闭,将资源到底层关掉
fw.close();
fw.write("haha"); //已关闭,会抛出异常
}

io异常的处理方式:
import java.io.*;
class  FileWriterDemo2
{
    public static void main(String[] args)
    {
        FileWriter fw = null;
        try
        {
            fw = new FileWriter("k:\\demo.txt"); //windows写两个目录分隔符,转义字符
            fw.write("abc");
        }
        catch (IOException e)
        {
            System.out.println(e.toString());
        }
        finally
        {
            try
            {
                if(fw!=null)
                    fw.close();
            }
            catch (IOException e)
            {
                System.out.println(e.toString());
            }
            
        }
    }
}

文件续写:
FileWriter fw  = new FileWriter("k:\\demo.txt",true); //传递一个true参数,代表续写
文本文件读取方式:
第一种:
    public static void main(String[] args)
    {
        FileReader fr = new FileReader("demo.txt");
        int ch = fr.read();
        System.out.println("ch=" + (char)ch); //将ch转换为char
        while(true)
        {
            int ch = fr.read();
            if(ch == -1)
            {
                break;
            }
        fr.close();
    }
第二种:
    public static void main(String[] args)
    {
        FileReader fr = new FileReader("demo.txt");
        //定义一个字符串数组
        char[] buf = new char[1024]; //2k
        int num = fr.read(buf); //返回读到字符个数
        System.out.println("num="+num+" "+new String(buf));
        while((num=fr.read(buf))!=-1)
        {
            System.out.println(new String(buf,0,num)); //读完后再全打出去
        }
        fr.close();
    }

评分

参与人数 1技术分 +1 收起 理由
攻城狮 + 1 赞一个!

查看全部评分

回复 使用道具 举报
io总结

--io概述
简单的说,就是提供了一系列对介质进行读写操作功能的类
--io流的分类
*按方向:分为输入流和输出流
*按单位:分为字节流和字符流
*按功能:分为节点流和处理流--实际上处理流的实现就是使用装饰设计模式(Decorator),和适配器设计模式(Adapter)而已
--io包中最顶层抽象类
*InputStrem--读取字节
*OutputStream--写入字节
*Reader--读取字符
*Writer--写入字符
*在字节流中使用byte[] buffer作为中间数据,字符流中使用char[] buffer作为中间数据,这样能避免频繁的和硬盘操作
--节点流和处理流
   节点流,是直接接到一个介质的流类型
   处理流,不是直接接到一个介质,而是接到一种节点流或者是一个处理流来增强处理功能
   所以,首先有节点流再有处理流
   
--常用的节点流
父 类    InputStream                      OutputStream                      Reader                   Writer

文 件   *FileInputStream                FileOutputStrean                  FileReader               FileWriter           -----对文件进行处理的节点流
数 组   *ByteArrayInputStream      ByteArrayOutputStream      CharArrayReader    CharArrayWriter -----对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)
                      *比如ByteArrayOutputStream baos=new ByteArrayOutputStream();
                      *然后往里面写东西;
                      *最后使用baos.toByteArray();方法返回字节数据
                      或者
                      *ByteArrayInputStream bais=new ByteArrayInputStream(一个存在的byteArray,或者baos.toByteArray())
                      *然后就可以读取数组里面的内容了
字符串   *无                无       StringReader  StringWriter       -----对字符串进行处理的节点流
管 道   *PipedInputStream            PipedOutputStream  PipedReader  PipedWriter       -----对管道进行处理的节点流


--常用处理流(关闭处理流使用关闭里面的节点流)
父 类     InputStream                     OutputStream                       Reader                               Writer
缓冲流    *BufferedImputStrean  BufferedOutputStream         BufferedReader                BufferedWriter    -----需要父类作为参数构造,增加缓冲功能,避免频繁读写硬盘,可以初始化缓冲数据的大小,由于带了缓冲功能,所以就写数据的时候需要使用flush方法咯
转换流    *                                                                       InputStreamReader          OutputStreamWriter-需要inputStream或OutputStream作为参数,实现从字节流到字符流的转换
数据流    *DataInputStream            DataOutputStream                                                                                            -提供将基础数据类型写入到文件中,或者读取出来,为什么要有这个流呢?看这样的分析,
                       *如果没有这种流的话,有一个long,本身只占8个字节,如果我要写入到文件,需要转成字符串,然后在转成字符数组,那空间会占用很多
                       *但是有了这种流之后就很方便了,直接将这8个字节写到文件就完了。。是不是既节约了内存空间有让程序写起来更加方便简单了呐
                       *写倒是很简单,但是读取的时候就注意了,根据读取的数据类型,指针会往下移,所以你写的顺序必须要和读的顺序一致才能完成你正确的需求
       *ObjectInputStream          ObjectOutputStream
       *顺便研究序列化---将对象所在的类型全部转换成二进制,然后写入到介质中去
       *transient关键字--修饰成员变量,不写入该成员变量
       *Serializable接口--表示接口,怎样实现的呢,在序列化之前,首先判断  (对象 instanceof Serializable)如果返回true则执行序列化,否者抛出异常,并且里面有一个ID,是用来快速查找某个对象的时候使用的
       *Externalizable接口--外部化接口;他是Serializable接口的子接口,能手动控制序列化的方式
       为什么要用writeUTF()--因为这种方式是按照utf-8来写入的,而默认方式是utf-16只是节省空间而已


--字节流读取中文的问题
*由于java使用的是unicode编码,每一个中文字符是占用两个字节的,所以没有只读出其中一个字节并使用的话当然是乱码咯,
*虽然普通的英文字符也是两个字节的,但是读取的时候将高8位去掉也能回去正确的英文字符,所以没有问题
*所以最好还是使用字符流的方式读取好点

--java.io中专门提供用于打印的流(这类流在写入的时候有自动flush的功能,所以你不需要没打印一个东西都flush一次)--------注意他们也是属于处理流,只不过这里单独列出来分析而已
*PrintStream--继承自-->FilterOutputStream--继承自-->OutputStream,(它的构造函数需要OutputStream对象)
*PrintWriter---继承自-->Writer(它的构造函数需要Writer对象)
System.In====InputStream
System.Out===PrintStream
这种流的print方法不会抛出异常,这是JSP技术中常用的流,如果在JSP页面的打印会抛出异常的话,那JSP也太难写了点!注意理解这样的设计思路

--看这样的代码
PrintStream ps=new PrintStream(new OutputStream("c://..."));
System.setOut(ps);
System.Out.println("jfdajsflkajdf");//这样将不会在打印到命令行窗口,而是指定的PrintStream目标文件里面去

评分

参与人数 1技术分 +1 收起 理由
攻城狮 + 1 赞一个!

查看全部评分

回复 使用道具 举报
是不是感觉很痛苦,流对象有很多,不知道该用哪一个?
流操作的基本规律:
         通过三个明确来完成。
         1.明确:源和目的。
            源:输入流。   InputStream   Reader
                   目的:输出流。 OutputStream  Writer
              2.明确:操作的数据是否是纯文本。
           是:用字符流。
           否:用字节流。
         3.当体系明确后,在明确要使用哪个具体的对象。通过设备来进行区分。
           源设备:内存,硬盘,键盘
           目的设备:内存,硬盘,控制台。
例如:
将一个文本文件中的数据存储到另一个文件中。(复制文件)
   源:文本文件。InputStream Reader 因为是源所以使用读取流。
   是不是操作文本文件:
   是:这时就选择Reader.这样体系就明确了。
  接下来明确对象:要是用该体系的哪些对象。
   明确设备:硬盘。(硬盘上的一个文件)
   Reader体系中可以操作文件的对象是FileReader.
  是否需要提供效率:
   是:加入Reader体系中缓冲区 BufferedReader.

从这个规律上入手,试着分析一下。
并从多个方面考虑,加上反复应用,对于IO流的理解与应用会有很大的提高。

评分

参与人数 1技术分 +1 收起 理由
攻城狮 + 1 赞一个!

查看全部评分

回复 使用道具 举报
个人觉得IO流好好地去理解IO流的工作原理,接下来写程序就好办了;  
回复 使用道具 举报
本帖最后由 胡团乐 于 2012-5-28 18:22 编辑

io:
字节流:InputStream(读取) OutputStream(写入)
字符流:FileReader(读取)  FileWriter(写入)
缓冲字符流:BufferedReader(读取)  BufferedWriter(写入)
缓冲字节流:BufferedInputStream(读取)  BufferedOutputStream(写入)
转换流:InputStreamReader(读取 字节->字符) OutputStreamReader(写入 字节->字符)
输入字节流InputStreamIO
1.InputStream 是所有的输入字节流的父类,它是一个抽象类。
2.ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,
它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。PipedInputStream 是从与其它线程共用的管道中读取数据;
3.ObjectInputStream 和所有FilterInputStream 的子类都是装饰流(装饰器模式的主角)。

输出字节流OutputStream
1.OutputStream 是所有的输出字节流的父类,它是一个抽象类。
2.ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。
PipedOutputStream 是向与其它线程共用的管道中写入数据,
3.ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流。
字符输入流Reader
1.Reader 是所有的输入字符流的父类,它是一个抽象类。
2.CharReader、StringReader 是两种基本的介质流,它们分别将Char 数组、String中读取数据。PipedReader 是从与其它线程共用的管道中读取数据。
3.BufferedReader 很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象。
4.FilterReader 是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号。
5.InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader 可以说是一个达到此功能、
常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。

字符输出流Writer
1.Writer 是所有的输出字符流的父类,它是一个抽象类。
2.CharArrayWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。PipedWriter 是向与其它线程共用的管道中写入数据,
3.BufferedWriter 是一个装饰器为Writer 提供缓冲功能。
4.PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。
5.OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类;
字符流与字节流转换
转换流的特点:
1.其是字符流和字节流之间的桥梁
2.可对读取到的字节数据经过指定编码转换成字符
3.可对读取到的字符数据经过指定编码转换成字节
何时使用转换流?
1.当字节和字符之间有转换动作时;
2.流操作的数据需要编码或解码时。
具体的对象体现:
1.InputStreamReader:字节到字符的桥梁
2.OutputStreamWriter:字符到字节的桥梁
这两个流对象是字符体系中的成员,它们有转换作用,本身又是字符流,所以在构造的时候需要传入字节流对象进来。

评分

参与人数 1技术分 +1 收起 理由
攻城狮 + 1 赞一个!

查看全部评分

回复 使用道具 举报
 ------- <a  target="blank">android培训</a>、<a  target="blank">java培训</a>、期待与您交流! ----
关于IO接口原理,里面东西比较复杂,细节比较多,很容易让初学者搞混淆,本人现将主要的内容尽可能详细的总结如下,大家可以参考,如有不足,敬请斧正!
第一节、关于InputStream和OutputStream***********************************************************************

1、InputStream和OutputStream都是以字节为单位的抽象流类,规定了字节流所有的输出和输入的基本操作。
InputStream:以字节为单位从数据源中读取数据,其继承层次结构大致如下:
public abstract int read ()throws IOException :从输入流中读取数据的下一个字节,返回读到的字节值,若遇到流的末尾,返回—1。

public int read (byte[] b) throws IOException:从输入流中读取B.length个字节的数据并存储到缓冲区b中,返回的是实际读到的字节数

public int read (byte[] b,int off ,int len )throws IOException:读取len个字节的数据,并从数组b的off位置开始写入到这个数组中

public void close() throws IOExceptiom:关闭此输入流并释放所有系统资源

public int available() IOException:返回此输入流的下一个方法调用可以不受阻塞地从此输入读取的估计字节数

public skip(long n) throws IOException:跳过河丢弃此输入流中数据的n个字节,返回的是字节数


2、outputStream常用方法介绍:
public abstract void write(int b)throws IOException:将制定的字节写入此输出流

public void write(byte[] b)throws IOException:将b.length个字节从指定的byte数组写入此输出流

public void write(byte[] b,int off,int len)throws IOException:将指定byte数组中从off开始的len个字节写入此输出流

public void flush() throws IOException:刷新此输出流,并强制写出所有缓冲的输出字节

public void close ()throws IOExceptoin:关闭此输出流,并释放与此输出流有关的所有系统资源




第二节、下面介绍字符输出流,用法的差别不大,只是针对的操作类型不同而已,大家可以对比记忆**********************
reader 和writer 都是以字符为操作对象的流类。
1、Reader  常用方法介绍:
public int read ()throws IOException:读取单个字符,返回作为整数读取的字符,如果已达到流的末尾则返回-1

public int read(char[] abcd)throws IOException:将字符读入数组,返回读取的字符数

public abstract int read (char[] abcd,int off,int len)throws IOExcrption:读取len 个字符的数据,并从数组ancd的off 位置开始写入到
这个数组中

public abstract void close()throws IOException:关闭该流并释放与之并联的所有系统资源

public long skip(long n)throws IOException:跳过n个字符



2、write常用方法介绍。
Public void write(int c)throws IOException:写入单个字符

public void write (char[] abcd)throws IOException:写入字符数组

public abstract void write(char[]abcd,int off,int len)throws IOException:写入字符数组的某一部分

public void write(String str)throws IOExcrption:写入字符串

public void write(String str,int off ,int len)throws IOException:写入字符串的某一部分

public abstract void close ()throws IOException:关闭此流,但是先刷新它

public abstract void flush()throws IOException:刷新该流的缓冲,将缓冲的数据全部写到目的地




第三节、关于文件流***************************************************************************

文件流是指那些专门用于操作数据源中的文件的流,主要有FileInputStream、FileOutPut、FileReader、FileWriter
四个类,根据分组先介绍FileInputStream、FileOutPutStream

FileInputStream、FileOutPutStream是以字节位操作单位的文件输入流和文件输出流,利用这两个类可以对文件
进行读写操作。。。。。
下面用例子来读取指定文件的数据。。。。


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/** 用FileInputStream来读取数据源中的数据 */
public class FileInputStreamTest {

        public static void main(String[] args) {
               
                FileInputStream fin = null;
                try {
                        // step1: 创建一个连接到指定文件的FileInputStream对象
                        fin = new FileInputStream("D:\\IOTest\\source.txt");
                        System.out.println("可读取的字节数: " + fin.available() + "字节");
                        // step2: 读数据: 一次读取一个字节的数据,返回的是读到的字节.
                        int i = fin.read();
                        while (i != -1) { // 若遇到流的末尾,会返回-1
                                System.out.print((char) i);
                                i = fin.read(); // 再读
                        }
                } catch (FileNotFoundException e) {
                        e.printStackTrace();
                } catch (IOException e) { // 捕获IO异常
                        e.printStackTrace();
                } finally {
                        // step3: 关闭输入流
                        try {
                                if (null != fin) {
                                        fin.close();
                                }
                        } catch (IOException e) {
                                e.printStackTrace();
                        }
                }
        }
}
“D:\\IOTest\soruce.txt”的内容如下:abc   你好吗   中国   i1234
运行以上这个程序,在控制台的输出结果为:abc   ??????   ???   i1234
下面给出阐释:乱码的原因是FileInputStream、FileOutPutStream是用字节流读取文件内容的,而汉语一个字是两个字节
因此才会出现乱码,解决办法就是使用转换流进行转换在输出,关于转换流会在本人连载的帖子中给出


--- <a  target="blank">android培训</a>、<a  target="blank">java培训</a>、期待与您交流! --------
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马