zoukankan      html  css  js  c++  java
  • Java入门:Java IO概括

    I/O 问题是任何编程语言都无法回避的问题,可以说 I/O 问题是整个人机交互的核心问题,因为 I/O 是机器获取和交换信息的主要渠道。在当今这个数据大爆炸时代,I/O 问题尤其突出,很容易成为一个性能瓶颈。

    本文的目的是分析 I/O 的内在工作机制,以及java I/O类库的基本架构,以帮助初学者从总体上了解Java I/O。具体各个I/O类库的使用,请读者在遇到实际问题时,结合本文的讲解来理解掌握。

    1.什么是I/O

    描述Java的I/O机制,我们用从河中抽水的例子来解释读文件的过程。

    要将河水抽出来,首先我们需要一个抽水机,然后把抽水机丢到河流里。这里,河水相当于文件,我们需要建立一个抽水机,并将抽水机与河水关联起来:

    FileInputStream fis = new FileInputStream("E:/rivier.txt");

    fis就是抽水机,E:/rivier.txt就是河水。

    设备准备好了,就可以打开水龙头获得水啦,但获得的水需要存放,所以第二步,我们还需要先有一个盛水的容器:

    byte[] bottle = new byte[10];

    容器bottle是一个byte类型的数组,大小为10.之所以将容器定义为byte数组而不是其它数组类型,是因为我们使用的这个抽水机比较特殊,抽出来的水最小单位就是1个byte(你就当1滴水来理解吧)。

    接下来,将容器放到水龙头下面,打开水龙头,就开始将水抽进容器里了。

    fis.read(bottle);

    这样抽水机fis就抽出了10滴水(10个byte)放到bottle这个容器里面了。然后bottle里的数据就可以任意有我们处置了。

    Java为我们提供了两种类型的抽水机,第一种抽水机的名字叫做XXXInputStream,它抽水的单位是字节,当然盛水的容器自然就是字节数组byte[]。

    第二种抽水机的名字叫做XXXReader,它抽水的单位是字符,盛水容器就是字符数组char[]。

    也就是说,我们如果我们用第一种抽水机XXXInputStream,抽出来的是byte;如果用第二种抽水机XXXReader,抽出来的是char。(有关字节byte和字符char的区别,自己脑补...)

    这里的XXX表示抽的水是河水,还是湖水、海水、污水......,即XXX表示数据的来源。如FileInputStream,表示这个抽水机是专门从文件中读取数据的;ByteArrayInputStream,就是专门从字符数组也就是内存中读数据的。

    小结一下,要读一个文件,步骤如下:

    1. 实例化一个XXXInputStream对象(选择一种抽水机,指定水源)

    2. 确定接收数据的对象(准备容器)

    3. read()(打开水龙头)

    现在,通过上面的抽水机,用户可以从各种地方,按各种大小的被子来得到水。但用户觉得抽水机功能还是弱了点, 如果打开水龙头,就是热水,就是热咖啡就好啦!

    显然抽水机已经力不从心了,如果把加热,煮咖啡的功能设计到抽水机里面,那么抽水机会显得太庞杂,也增加了出故障时维修的难度。

    所以,我们换一种思路,在抽水机的水龙头下,接一根加热管:

    FileInputStream fis = new FileInputStream("e:/yellow_river.txt");//准备好抽水机
    ObjectInputStream ois= new ObjectInputStream(fis);//增加一个加热器

    这样,只需要调用加热管的水龙头,就可以获得热水啦:

    ois.readDouble();//读出来的就是一个double型的数据,不再是byte数据(即抽出的就是热水)

    所以,总的来说,在Java中读文件,就像抽水,首先,需要根据读取单位,根据读取源,选择合适的抽水机。如果需要,还可以在抽水机后添加管子,增强功能。

    请试着按照排水的例子,描述文件的机制。

    2. 实例理解

    现在我们结合上面的例子,来理解几个实例。

    1)按字节读文件FileInputStream

    FileInputStream fis = new FileInputStream("e:/in.txt");   //创建输入流对象(抽水机)
    while (fis.available() > 0) {   
        byte[] b = new byte[10];   //创建数组(盛水容器)
        int nResult = fis.read(b);   //读数据到数组,并且读到数据时,nResult被赋值为>-1的整数,表示实际读了多少个byte
        if (nResult == -1) //文件中的数据读完了,没数据可读了
            break;   
        System.out.println(new String(b));   
    }   
    fis.close();      //数据读完了,抽水机需要关掉

    2)按字符读文件FileReader:

    FileReader rdFile = new FileReader("e:/in.txt");   //实例化文件输入流对象(抽水机)
    while (rdFile.ready()) {   //输入流是否准备好读(抽水机是否准备好抽水)
        char[] chIn = new char[10];   //准备容器
        int nResult = rdFile.read(chIn);   //读数据
        if (nResult == -1) //如果没有读到数据break;   
        System.out.println(chIn);   
    }   
    rdFile.close();  //不抽水了,关掉抽水机

    FileReader满足XXXReader命名规则,从名字可以判断是按字符来读数据,并且数据来源是文件。

    3.带缓冲区的读

    还是用抽水的例子来讲解什么是缓冲区。我们在使用水的时候,可以有两种方法,一种是每次要用水,就去打开水龙头,等着它将容器装满。第二种方法是,家里有一个大水缸,先将大水缸装满,每次用水的时候,直接去水缸里取。当水缸里的谁不够用时,再打开水龙头将大水缸放满。

    不考虑水存放时间长了会变质的影响,显然第二种方法效率高。

    文件通常放在磁盘等设备中,读写速度远没有内存的速度快。上面FileInputStream或FileReader每次执行read()方法,都会去硬盘读取一次。如果事先将文件中的数据读取一定大小到内存中,以后每次read(),从这块内存中读,就会减少硬盘的读写次数,效率高得多。如果这块内存中的数据不够用了,再去硬盘继续读数据把这块内存填满,后面继续使用这块内存。这块内存就是缓冲区。

    用法示例:

    FileReader rdFile = new FileReader("e:/in.txt"); //创建字符文件输入流对象
    BufferedReader brdFile = new BufferedReader(rdFile);  //创建一个BufferedReader对象 
    String strLine;   
    while ((strLine = brdFile.readLine()) != null) {   
        System.out.println(strLine);
    }   
    brdFile.close();   

    例子中,将rdFile这个FileReader对象包装在BufferedReader对象brdFile里,直接操作brdFile对象,就可以实现带缓冲功能的读操作了。

    同样,按字节读可以使用BufferedInputStream类来对InputSteam进行包装。

    4. I/O体系结构

    我们已经了解了Java I/O 系统,并学会了一些简单的I/O操作,接下来请打开Java Doc,让我们看看Sun公司是怎样通过面向对象的思想,设计I/O系统的。

    总结一下:

    1. InputStream和OutputStream是按字节读写数据的抽象类,是所有字节输入输出流的基类。

    2. Reader和Writer是按字符读写数据的抽象类,是所有字符输入输出流的基类。

    3. 继承它们的都是针对特定数据源的“抽水机”或“排水机”,提供了read和write的基本实现。

    4. 构造方法一般都需要提供数据源。

    5. 不必记住每个类的具体用法,只需要掌握IO的总体结构,然后记住几个重要类的功能,至于具体的成员方法的用法,可以在使用的时候再去查看方法的申明定义或查看在线Java Doc。

    【实践练习】

    从网络获取天气数据,将获取到的数据在控制台打印输出。

    package WeatherDemo;
    
    import java.io.BufferedReader;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.net.SocketTimeoutException;
    import java.net.URL;
    import java.net.URLConnection;
    
    
    public class MyWeather {
    
        public MyWeather(String Cityid) throws IOException {
            String Ctiyid;
            URLConnection connectionData;
            StringBuilder sb;
            BufferedReader br;// 读取data数据流
            sb = new StringBuilder();
            
            URL url = new URL("http://api.k780.com:88/?app=weather.future&weaid=" + Cityid + "&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json");
            connectionData = url.openConnection();
            connectionData.setConnectTimeout(1000);
            
            try {
                br = new BufferedReader(new InputStreamReader(
                        connectionData.getInputStream(), "UTF-8"));            
                String line = null;
                while ((line = br.readLine()) != null)
                    sb.append(line);
            } catch (SocketTimeoutException e) {
                System.out.println("连接超时");
            } catch (FileNotFoundException e) {
                System.out.println("加载文件出错");
            }
            System.out.print(sb.toString());
            
        }
        public static void main(String[] args) {
            try {
                new MyWeather("101010100"); // 101010100(北京)就是你的城市代码
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    首先,需要在网络搜索获取天气信息的途径,这里提供本文作者自己找到的一篇博客:http://www.nohacks.cn/post-35.html,本代码使用了博客中“ 3.3  未来几天天气”里提到的api。

    有关URL的用法这里可不必关心,重点放在如何读取网络数据。

    【问题】

    1.new InputStreamReader(connectionData.getInputStream(), "UTF-8"))参数“UTF-8"作用是什么?不要此参数编译能否通过?看到什么结果?

    2.

    br = new BufferedReader(new InputStreamReader(
    connectionData.getInputStream(), "UTF-8"));

    能不能写成:

    br = new BufferedReader(connectionData.getInputStream());

    如果不能,为什么?

    3.为什么要用到StringBuilder sb,而不是String sb?

  • 相关阅读:
    poj 3068 Bridge Across Islands
    XidianOJ 1086 Flappy v8
    XidianOJ 1036 分配宝藏
    XidianOJ 1090 爬树的V8
    XidianOJ 1088 AK后的V8
    XidianOJ 1062 Black King Bar
    XidianOJ 1091 看Dota视频的V8
    XidianOJ 1098 突击数论前的xry111
    XidianOJ 1019 自然数的秘密
    XidianOJ 1109 Too Naive
  • 原文地址:https://www.cnblogs.com/bayes/p/5545917.html
Copyright © 2011-2022 走看看