12. JAVA IO Party 2 (内存操作流、管道流、打印流、System类对IO的支持) ----- 学习笔记

12.5 内存操作流

        前面讲解中的输入和输出都是从文件中来的,当然,也可以将输出的位置设置在内存上。此时就要使用ByteArrayInputStream、ByteArrayOutputStream来完成输入和输出功能。

       ByteArrayInputStream主要完成将内容写入到内存中,而ByteArrayOutputStream的功能主要是将内存中的数据输出。如下图所示:

 

     ByteArrayInputStream类的主要方法如下所示:

public ByteArrayInputStream(byte[] buf)                              //将全部的内容写入到内存中
public ByteArrayInputStream(byte[] buf, int offset, int length)               //将指定范围的内容写入到内存中


   ByteArrayInputStream主要是使用构造方法将全部的内容读取到内存中,如果要想把内容从内存中取出,则可以使用ByteArrayOutputStream类!

   ByteArrayOutputStream类的主要方法如下所示:

public ByteArrayOutputStream()        //创建对象
public void write(int b)                  //将内容从内存中输出


范例: 使用内存操作流完成一个大写字母转换为小写字母的程序

package org.forfan06.bytearrayemo;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class ByteArrayDemo01{
    public static void main(String args[]){
        String str = "HELLO WORLD!";  //定义串都是大写字母的一个字符
        ByteArrayInputStream bis = null;     //声明一个内存的输入流
        ByteArrayOutputStream bos = null;    //声明一个内存的输出流
        bis = new ByteArrayInputStream(str.getBytes()); //向内存中输出内容
        bos = new ByteArrayOutputStream();  //准备从ByteArrayInputStream中读数据
        
        int temp = 0;
        while((temp = bis.read()) != -1){
            char c = (char) temp; //将读取的数字变为字符
            bos.write(Character.toLowerCase(c));  //将字符变为小写
        }
        String newStr = bos.toString();  //取出内容
        try{
            bis.close();
            bos.close();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

  • 内存操作流一般在生成一些临时信息时才会使用,而这些临时信息如果要保存在文件中,则代码执行完后肯定还要删除这个临时文件,那么此时使用内存操作流驶最合适的。。

12.6 管道流

管道流的主要作用是可以进行两个线程间的通信。如图所示,分为管道输出流PipedOutputStream和管道输入流PipedInputStream。 如果要进行管道输出,必须把输出流连到输入流上,在PipedOutputStream类上有如下方法用于连接管道。

public void connect(PipedInputStream snk) throws IOException

范例:验证管道流

package org.forfan06.pipeddemo;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
class Send implements Runnable{   //实现Runnable接口
    private PipedOutputStream pos = null;   //管道输出流
    public send(){
        this.pos = new PipedOutputStream(); //实例化输出流
    }
    public void run(){
        String str = "Hello World!!!";
        try{
            this.pos.write(str.getBytes()); //输出信息
        }catch(IOException e){
            e.printStackTrace();
        }
        try{
            this.pos.close();             //关闭输出流
        }catch(IOException e){
            e.printStackTrace();
        }
    }
    public PipedOutputStream getPos(){     //通过线程类得到输出流
        return pos;
    }
}
class Receive implements Runnable{   //实现Runnable接口
    private PipedInputStream pis = null;
    public Receive(){
        this.pis = new PipedInputStream();
    }
    public void run(){
        byte b[] = new byte[1024];
        int len = 0;
        try{
            len = this.pis.read(b);
        }catch(IOException e){
            e.printStackTrace();
        }
        try{
            this.pis.close();
        }catch(IOException e){
            e.printStackTrace();
        }
        System.out.println("接收的内容是: " + new String(b, 0, len));
    }
    public PipedInputStream getPis(){
        return pis;
    }
}
public class PipedDemo{
    public static void main(String args[]){
        Send s = new Send();
        Receive r = new Receive();
        try{
            s.getPos().connect(r.getPis());  //连接管道
        }catch(IOException e){
            e.printStackTrace();
        }
        new Thread(s).start();    //启动线程
        new Thread(r).start();
    }
}

  以上程序定义了两个线程对象,在发送的线程类中定义了管道输出流;在接收的线程类中定义了管道的输入流。在操作时只需要使用PipedOutputStream类中提供的connection()方法就可以将两个线程管道连接在一起,线程启动后会自动进入管道的输入、输出操作。

12.7 打印流

     12.7.1 打印流的基本操作

        在整个IO包中,打印流是输出信息最方便的泪,主要包含字节打印流PrintStream 和字符打印流PrintWriter。 打印流提供了非常方便的打印功能,可以打印任何的数据类型,如小数、整数、字符串等等。

    PrintStream类是OutputStream类的子类。PrintStream类的常用方法有:

public PrintStream(File file) throws FileNotFoundException               //通过一个File对象实例话PrintStream类
public PrintStream(OutputStream out)        //接收OutputStream对象,实例化PrintStream类
public PrintStream printf(Locale l, String format, Object...args)         //根据指定的Locale进行格式化输出
public PrintStream printf(String format, Object...args)              //根据本地环境格式化输出
public void print(boolean b)               //此方法被重载很多次,输出任意数据
public void println(boolean b)             //此方法被重载很多次,输出任意数据后换行


在PrintStream类中定义的构造方法可以清楚地发现,有一个构造方法可以直接接收OutputStream类的实例,这是因为与OutputStream类相比,PrintStream类可以更加方便地输出数据,这就好像将OutputStream类重新包装了一下,使之输出更加方便。如图所示:


从上图可以看出,把一个输出流的实例传递到打印流后,可以更加方便地输出内容,也就是说,是打印流把输出流重新装饰了一下,就像送别人礼物,需要把礼物包装一下才会更加好看,所以,这样的设计成为装饰设计模式

范例:使用PrintStream输出

package org.forfan06.printdemo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class PrintDemo01{
    public static void main(String args[]) throws Exception{
        PrintStream ps = null;
        //通过FileOutputStream实例化,意味着所有的输出是向文件中打印
        ps = new PrintStream(new FileOutputStream(new File("E:" + File.separator + "test.txt")));
        ps.print("hello ");
        ps.println("world!!!");
        ps.print("1 + 1 = " + 2);
        ps.close();
    }
}

     12.7.2 使用打印流进行格式化

在JDK1.5之后,Java又对PrintStream类进行了扩充,增加了格式化的输出方式,直接使用printf()方法可以完成操作。但是在进行格式化输出时需要指定其输出的数据类型,数据类型的格式化表示如下所示:

字符             描述

%s                                           表示内容为字符串

%d                                           表示内容为整数

%f                                           表示内容为小数

%c                                           表示内容为字符

下面用上面表中的内容进行格式化输出操作

范例:格式化输出

package org.forfan06.printdemo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class PrintDemo02{
    public static void main(String args[]) throws Exception{
        PrintStream ps = null;
        //通过FileOutputStream类进行实例化,意味着所有的输出是向文件中打印
        ps = new PrintStream(new FileOutputStream(new File("E:" + File.separator + "test.txt")));
        String name = "某某某";
        int age = 30;
        float score = 990.356f;
        char sex = 'M';
        //格式化输出,字符串使用%s、整数使用%d、小数使用%f、字符使用%c
        ps.printf("姓名:%s; 年龄:%d; 成绩:%f; 性别:%c", name, age, score, sex);
        //以上的%d、%f、%c都可以使用%s替代,效果一样
        //ps.printf("姓名:%s; 年龄:%s; 成绩:%s; 性别:%s", name, age, score, sex);
        ps.close();
    }
}

12.8 System类对IO的支持

System表示系统类,此类在讲解Java常用类库时已经介绍过,实际上在Java中System类也对IO给予了一定的支持,在System类中定义了如下的3个常量。这3个常量在IO操作中有着非常大的作用

public static final PrintStream out     //对应系统标准输出,一般是显示器
public static final PrintStream err              //错误信息输出
public static final <span style="color:#ff0000;">InputStream</span> in              //对应着标准输入,一般是键盘
  • System类中提供的in、out、err3个常量也符合命名规则。这些都是Java历史发展的产物。

     12.8.1 System.out

     System.out是PrintStream的对象,在PringStream中定义了一些列的print()和println()方法,所以前面使用的System.out.print()或System.out.println()语句调用的实际上就是PrintStream类的方法。

     既然此对象表示的是向显示器上输出,而PrintStream又是OutputStream类的子类,所以可以直接利用此对象向屏幕上输出信息。

范例:使用OutputStream向屏幕上输出

package org.forfan06.systemdemo;
import java.io.IOException;
import java.io.OutputStream;
public class SystemDemo01{
    public static void main(String args[]){
        OutputStream out = System.out;   //此时的输出流是向屏幕上输出
        try{
            out.write("hello world!!!".getBytes());
        }catch(IOException e){
            e.printStackTrace();
        }
        try{
            out.close();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

以上信息是直接使用OutputStream类向屏幕上进行输出的,也就是说,

OutputStream的哪个子类为其实例化,就具备了向哪里输出的能力。

如果是使用了FileOutputStream类则表示向文件输出;如果使用了System.out则表示向显示器输出。 这里就完全显示出了Java的多态性好处,根据子类的不同完成的功能也不同!!!!

     12.8.2 System.err

System.err表示的是错误信息输出,如果程序出现错误,则可以直接使用System.err进行输出。 演示代码如下:

范例:错误信息输出

package org.forfan06.systemdemo;
public class SystemDemo02{
    public static void main(String args[]){
        String str = "hello";  
        try{
            System.out.println(Integer.parseInt(str));   //想把字符串变为整数数据,肯定会产生NumberFormatException异常      
        }catch(Exception e){
            System.err.println(e);
            //若使用out输出是一样的效果
            //System.out.println(e);
        }
    }
}

  • 一般来讲System.out是将信息显示给用户看,是正常的信息显示;而System.err的信息正好相反,是不希望用户看到的,会直接在后台打印,是专门显示错误的。

     12.8.3 System.in

          System.in实际上是一个键盘的输入流,其本身是InputStream类型的对象(所以System.in输入流是属于字节流!!!)。 那么此时就可以利用System.in完成从键盘读取数据的功能。

范例: 从键盘上读取数据

package org.forfan06.systemdemo;
import java.io.InputStream;
public class SystemDemo04{
    public static void main(String args[]) throws Exception{
        InputStream input = System.in;  //从键盘接收数据
        byte b[] = new byte[1024];  //开辟空间,接收数据
        System.out.println("请输入内容: ");
        int len = input.read(b);
        System.out.println("输入的内容为:" + new String(b, 0, len));
        input.close();
    }
}

上面程序虽然实现了从键盘中输入数据的功能,但是还存在两个问题:

  1. 程序制定了输入数据的长度,如果现在输入的数据超出了其长度范围,则只能输入部分数据
  2. 如果指定的byte数组长度为奇数, 则还有可能出现中文乱码

为了验证以上两个问题,可以将程序中的byte数组长度减少并设置为奇数。(1个中文字符等于两个字节!)


 范例:不指定byte数组大小

package org.forfan06.systemdemo;
import java.io.InputStream;
public class SystemDemo05{
    public static void main(String args[]) throws Exception{
        InputStream input = System.in;
        StringBuffer buf = new StringBuffer(); 
        System.out.println("请输入内容:");
        int temp = 0;
        while((temp = input.read()) != -1){
            char c = (char) temp;
            if(c == '\n'){
                break;
            }
            buf.append(c);
        }
        System.out.println("输入的内容为:" + buf);
        input.close();
    }
}

此时如果输入的全部是字母,则正常显示;但是如果输入的中文,则会产生乱码。这是因为数据是以一个个字节的方式读进来的,一个汉字分两次读取的,所以造成了乱码。

     指定大小会出现空间限制;不指定大小则输入中文时又会产生乱码,那么怎么样的输入数据形式才是最合理的呢???

         最好的输入方式是将全部输入的数据暂时放到一块内存中,然后一次性从内存中读取出数据。这样所有的数据只读了一次,则不会造成乱码,而且不会受长度的限制。如果要完成这样的操作则要使用12.9章中的BufferedReader类!!!

     12.8.4 输入/输出重定向

通过System类也可以改变System.in的输入流来源以及System.out和System.err两个输出流的输出位置。这些操作方法如下所示:

public static void setOut(PrintStream out)           //重定向“标准”输出流
public static void setErr(PrintStream err)           //重定向“标准”错误输出流
public static void setIn(InputStream in)            //重定向“标准”输入流


(1)为System.out输出重定向

package org.forfan06.systemdemo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class SystemDemo06{
    public static void main(String args[]) throws Exception{
        String path = "E:" + File.separator + "test.txt";
        System.setOut(new PrintStream(new FileOutputStream(path)));  //System.out输出重定向
        system.out.print("www.csdn.net");  //输出时不再像屏幕上输出,而是向指定的重定向位置输出
        System.out.println(", forfan06");
    }
}

此时输出信息保存到“E:\test.txt”文件中!!!


(2)为用户保存错误信息,利用此概念,可以把错误信息保存在临时文件里面!!!

package org.forfan06.systemdemo;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.io.PrintStream;
public class SystemDemo07{
    public static void main(String args[]) throws Exception{
        String str = "hello";
        try{
            System.out.println(Integer.parseInt(str));
        }catch(Exception e){
            try{
                String path = "E:" + File.separator + "err.log";
                System.setOut(new PrintStream(new FileOutputStream(path))); //输出重定位
            }catch(FileNotFoundException e1){
                e1.printStackTrace();
            }
            System.out.println(e);  //输出错误信息,保存到文件中
        }
    }
}

(3)为System.err输出重定向

package org.forfan06.systemdemo;
import java.io.File;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
public class SystemDemo08{
    public static void main(String args[]) throws Exception{
        ByteArrayOutputStream bos = null;  //定义内存输出流
        bos = new ByteArrayOutputStream();  //实例化内存输出流
        System.setErr(new PrintStream(bos)); //System.err输出重定向
        System.err.print("www.csdn.net");   //错误输出不再向屏幕上输出,而是向内存的位置输出
        System.err.println(", forfan06");
        System.out.println(bos);  //打印错误信息
    }
}

  • setOut()方法只负责System.out的输出重定向;setErr()方法只负责System.err的输出重定向。两者不可混用
  • 虽然System类中提供了setErr()这个错误输出的重定向方法,但是在一般情况下,不要使用这个方法修改System.err的重定向。因为从概念上讲,System.err的错误信息是不希望用户看到的。

(4)为System.in输入重定向

package org.forfan06.systemdemo;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class SystemDemo09{
    public static void main(String args[]) throws Exception{
        System.setIn(new FileInputStream("E:" + File.separator + "test.txt")); //设置输入重定向
        InputStream input = System.in; //从文件中接收数据
        byte[] b= new byte[1024];  //开辟空间,接收数据
        int len = input.read(b); 
        System.out.println("输入的内容是:" + new String(b, 0, len));
        input.close();
    }
}

12.9 BufferedReader类

   BufferedReader类用于从缓冲区中读取内容,所有的输入字节数据都将放在缓冲区中。常用方法如下:

public BufferedReader(Reader in)         //构造方法,接收一个Reader类的实例
public String readLine() throws IOException     //一次性从缓冲区中将内容全部读取出来
BufferedReader类中定义的构造方法只能接收字符输入流的实例,所以必须使用字符输入流和字节输入流的转换类InputStreamReader将字节输入流System.in变为字符流。

BufferedReader buf = null;
buf = new BufferedReader(new InputStreamReader(System.in));

代码说明,BufferedReader类只能接收字符流的缓冲区,因为每一个中文要占两个字节,所以需要将System.in这个字节的输入流变为字符的输入流。

     12.9.1 键盘输入数据的标准格式

         将System.in变为字符流放入到BufferedReader后,可以通过readLine()方法等待用户输入信息。

范例:从键盘输入数据

<span style="font-size:14px;"><strong>package org.forfan06.bufferedreaderdemo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class BufferedReaderDemo01{
    public static void main(String args[]){
        BufferedReader buf = null;
        buf = new BufferedReader(new InputStreamReader(System.in)); //实例化BufferedReader
        String str = null;
        System.out.print("请输入内容:");
        try{
            str = buf.readLine();
        }catch(IOException e){
            e.printStackTrace();
        }
        System.out.println("输入的内容是:" + str);
    }
}</strong></span>

此时,程序没有了长度的限制,也可以正确地接收中文字符了。以上代码就是键盘输入数据的标准格式!!!!!!!!

tips:

1, InputStreamReader类有一个构造方法:

public InputStreamReader(InputStream in)     //create an InputStreamReader that uses the default charset.  in - > An InputStream

2, System.in的定义:可以看出System.in是InputStream类型。可以从这两点观察BufferedReader类的初始化!!!

public static final InputStream in;

      12.9.2 相关操作实例

1, 实例操作一: 加法操作

    要求从键盘输入两个数字,然后完成两个整数的加法操作。因为从键盘接收过来的内容全部是采用字符串的形式存放的,所以直接使用字符串通过包装类Integer类将字符串变为基本数据类型。

(1)完成最基本的功能

范例:输入两个数字,并让两个数字相加

package org.forfan06.execdemo;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class ExecDemo01{
    public static void main(String args[]) throws Exception{
        int i = 0;
        int j = 0;
        BufferedReader buf = null;
        buf = new BufferedReader(new InputStreamReader(System.in));
        String str = null;
        System.out.println("请输入第一个数字:");
        str = buf.readLine();
        i = Integer.parseInt(str); //将字符串变为int型
        System.out.println("请输入第二个数字:");
        str = buf.readLine();
        j = Integer.parseInt(str);
        System.out.println(i + " + " + j + " = " + (i + j));
    }
}

上面程序存在的问题:

  1. 如果输入的字符串不是数字,则肯定无法转换,会出现NumberFormatException异常。所以在转换时应该使用正则表达式进行验证:如果验证成功了,则表示可以进行转换;如果验证失败了,则表示无法进行转换,此时就要等待用户重新输入期待的数据类型:数字。
  2. 只能输入整数
  3. 代码重复:只要输入数据,则肯定是用BufferedReader类,重复出现了readLine()方法的调用。

(2)对类进行合理的划分

     对于输入数据,最常见的可能是整数、小数、日期、字符串,所以此时最好将其设计一个专门的输入数据类,完成输入数据的功能

范例:完成一个专门处理输入数据的类,只能得到整数和字符串

package org.forfan06.execdemo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class InputData{
    private BufferedReader buf = null;
    public InputData(){   //在类的构造方法中实例化BufferedReader对象
        this.buf = new BufferedReader(new InputStreamReader(System.in));
    }
    public String getString(String info){   //从getString方法中得到字符串的信息
        String temp = null;
        System.out.print(info); //打印信息
        try{
            temp = this.buf.readLine();
        }catch(IOException e){
            e.printStackTrace();
        }
        return temp;
    }
    public int getInt(String info, String err){  //得到一个整数的输入数据
        int temp = 0;
        String str = null;
        boolean flag = true;   //定义一个循环的处理标志符
        while(flag){
            str = this.getString(info);
            if(str.matches("^\\d+$")){  //判断输入的是否是数字
                temp = Integer.parseInt(str);
                flag = flase;
            }else{
                System.out.println(err);
            }
        }
        return temp;
    }
}

范例:测试上面专门处理输入的类!!

package org.forfan06.execdemo;
public class ExecDemo02{
    public static void main(String args[]) throws Exception{
        int i = 0;
        int j = 0;
        InputData input = new InputData();
        i = input.getInt("请输入第一个数字:", "输入的数据必须是数字,请重新输入");
        j = imput.getInt("请输入第二个数字:", "输入的数据必须是数字,请重新输入");
        System.out.println(i + " + " + j + " = " + (i + j));
    }
}

使用以上程序将输入数据的操作定义成了一个类,以后只要是想得到输入数据,则直接从该类中得到即可。

(3)对输入数据类进一步扩充

开发中,最常见的输入数据类型就是整数、小数、字符串、日期。 这里进一步扩充上面的处理输入数据的类InputData, 输入各种类型的数据!!

package org.forfan06.execdemo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.text.ParseException;
public class InputData{
    private BufferedReader buf = null;
    public InputData(){
        this.buf = new BufferedReader(new InputStreamReader(System.in));
        //BufferedReader buf = new BufferedReader(new InputStreamReader(InputStream in));
    }
    public String getString(String info){
        String temp = null;
        System.out.print(info);
        try{
            temp = this.buf.readLine();
        }catch(IOException e){
            e.printStackTrace();
        }
        return temp;
    }    
    public int getInt(String info, String err){
        int temp = 0;
        String str = null;
        boolean flag = true;
        while(flag){
            str = this.getString(info);
            if(str.matches("^\\d+$")){
                temp = Integer.parseInt(str);
                flag = false;
            }else{
                System.out.println(err);
            }
        }
        return temp;
    }
    public float getFloat(String info, String err){
        float temp = 0;
        String str = null;
        boolean flag = true;
        while(flag){
            str = this.getString(info);
            if(str.matches("^\\d+.?\\d+$")){
                temp = Flagt.parseFloat(str);
                flag = false;
            }else{
                System.out.println(err);
            }
        }
        return temp;
    }
    public Date getDate(String info, String err){
        Date d = null;
        String str = null;
        boolean flag = true;
        while(flag){
            str = this.getString(info);
            if(str.matches("^\\d{4}-\\d{2}-\\d{2}$")){
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                try{
                    d = sdf.parse(str);
                }catche(ParseException e){
                    e.printStackTrace();
                }
                flag = false;
            }else{
                System.out.println(err);
            }
        }
        retrun d;
    }
}

以上程序可以实现整数、小数、字符串、日期类型数据的输入。在得到日期类型时使用了SimpleDateFormat类,并制定了日期的转换模板,将一个字符串变味了一个Date类型的数据,这点在开发中较为常用。

  • 对于实际的开发来讲,很难一次性开发出完整的类射击,所以在编写时一定要首先完成基本功能的实现,然后再对实现功能的代码结构进行优化,这样就可以设计一个比较合理的类

2, 实例操作二: 菜单显示

   菜单显示在系统中是经常出现的,下面使用IO操作完成一个简单的菜单程序,显示效果如下:

=====xxx系统=====

[1]、增加数据

[2]、删除数据

[3]、修改数据

[4]、查看数据

[0]、系统退出


请选择:

     如果用户输入的编号不正确,则要给出错误提示,并等待用户重新选择

    可以使用switch完成以上功能,以上程序本身需要接收输入数据,而且需要显示,在以后还可能在程序中加入具体的操作。为了应对这种情况,中间最好加入一个操作类,即菜单类调用操作类。而具体的实际操作由操作类完成。本程序的输入数据程序依然使用之前编写的InputData类完成。

范例: 完成操作类:

package org.forfan06.execdemo;
public class Operate{
    public static void add(){
        System.out.println("**选择的是增加操作**");
    }
    public static void delete(){
        System.out.println("**选择的是删除操作**");
    }
    public static void update(){
        System.out.println("**选择的是更新操作**");
    }
    public static voie find(){
        System.out.println("**选择的是查看操作**");
    }
    
}

      操作类的代码比较简单,因为程序本身的功能要求只是实现菜单,如果要完成具体的操作,直接修改此类即可。

范例:菜单显示类,接收选择的数据,同时使用switch判断是哪个操作

package org.forfan06.execdemo;
public class Menu{
    public Menu(){
        while(true){
            this.show();  //无限制调用菜单的显示
        }
    }
    public void show(){
        System.out.println("=====xxx系统=====");
        System.out.println("[1]、增加数据");
        System.out.println("[2]、删除数据");
        System.out.println("[3]、修改数据");
        System.out.println("[4]、查看数据");
        System.out.println("[0]、系统退出\n");
        InputData input = new InputData();
        int i = input.getInt("请选择:", "请输入正确的选项!");
        switch (i){
            case 1:{
                Operate.add();
                break;
            }
            case 2:{
                Operate.delete();
                break;
            }
            case 3:{
                Operate.update();
                break;
            }
            case 4:{
                Operate.find();
                break;
            }
            case 0:{
                System.exit(1);
                break;
            }
            default:{
                System.out.println("请选择正确的操作!");
            }
        }
    }
}

        以上的菜单类因为菜单的内容要不断地显示,所以使用循环打印的方式,每一次操作完成后都会重新显示出所有的菜单内容以供用户选择

范例: 编写住方法验证以上的菜单程序

package org.forfan06.execdemo;
public class ExecDemo03{
    public static void main(String args[]) throws Exception{
        new Menu();
    }
}

12.10 Scanner类

     12.10.1 Scanner类简介

     在JDK1.5之后Java提供了专门的输入数据类,此类不只可以完成输入数据操作,也可以方便地对输入数据进行验证。此类存放在java.util包中。其方法如下表所示:

注意:

=====Scanner类可以接收任意的输入流=====

在Scanner类中提供了一个可以接收InputStream类型的构造方法,这就表示只要是字节输入流的子类都可以通过Scanner类进行方便的读取。

     12.10.2 使用Scanner类输入数据

1, 实例操作一:实现基本的数据输入

     最简单的数据输入直接使用Scanner类的next()方法即可。

范例:输入数据

package org.forfan06.scannerdemo;
import java.util.Scanner;
public class ScannerDemo01{
    public static void main(String args[]){
        Scanner scan = new Scanner(System.in);  //从键盘接收数据
        System.out.print("请输入数据:");
        String str = scan.next();
        System.out.println("输入的数据为:" + str);
    }
}


上面程序存在的问题:

  如果输入了带有空格的内容,则只能取出空格之前的数据。空格后面的数据没有了。造成这种结果是因为Scanner类将空格当作了一个分隔符,所以为了保证程序的正确,可以将分隔符好修改为“ \n (回车)”

范例:修改输入数据的分隔符

package org.forfan06.scannerdemo;
import java.util.Scanner;
public class ScannerDemo02{
    public static void main(String args[]){
        Scanner scan = new Scanner(System.in);   //从键盘接收数据
        scan.useDelimiter("\n");
        System.out.println("请输入数据:");
        String str = scan.next();
        System.out.println("输入的数据是:" + str);
    }
}

这段程序完成了字符串内容的输入,并且也接收了包含空格的字符串等。

         如果要输入int或float类型的数据,在Scanner类中也有支持,但是在输入之前最好先使用hasNextXxx()方法进行验证。例如:

范例: 输入int、float类型的数据

package org.forfan06.scannerdemo;
import java.util.Scanner;
public class ScannerDemo03{
    public static void main(String args[]){
        Scanner scan = new Scanner(System.in);   //从键盘接收数据
        scan.useDelimiter("\n");
        System.out.println("请输入整数:");
        if(scan.hasNextInt()){
            int i = scan.nextInt();
            System.out.println("整数数据:" + i);
        }else{
            System.out.println("输入的不是整数!!!");
        }
        System.out.println("请输入小数:");
        if(scan.hasNextFloat()){
            float j = scan.nextFloat();
            System.out.println("小数数据:" + j);
        }else{
            System.out.println("输入的不是小数!!!");
        }
    }
}

2, 实例操作二: 实现日期格式的数据输入

   在Scanner类中没有提供专门的日期格式输入操作,所以,如果想要得到一个日期类的数据,则必须自己编写正则表达式验证,并手工转化。一下代码演示了具体的操作:

范例:Scanner类得到日期

package org.forfan06.scannerdemo;
import java.util.Scanner;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.text.ParseException;
public class ScannerDemo04{
    public static void main(String args[]){
        Scanner scan = new Scanner(System.in);
        System.out.print("输入日期(yyyy-MM-dd):");
        String str = null;
        Date date = null;
        if(scan.hasNext("^\\d{4}-\\d{2}-\\d{2}$")){
            str = scan.next("^\\d{4}-\\d{2}-\\d{2}$"); //接收日期格式的字符串
            try{
                date = new SimpleDateFormat("yyyy-MM-DD").parse(str);
            }catch(ParseException e){
                e.printStackTrace();
            }
        }else{
            System.out.println("输入的日期格式错误!");
        }
        System.out.println(date);
    }
}

3, 实例操作三:从文件中得到数据

      如果要从文件中取得数据,则直接将File类得实例传入到Scanner的构造方法中即可。

例如,现在要显示“e:\test.txt”中的内容,则可以采用一下的代码:

范例:读取文件中的内容

package org.forfan06.scannerdemo;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class ScannerDemo05{
    public static void main(String args[]){
        File f = new File("E:" + File.separator + "test.txt");
        Scanner scan = null;
        try{
            scan = new Scanner(f);
        }catch(FileNotFoundException e){
            e.printStackTrace();
        }
        StringBuffer str = new StringBuffer();
        while(scan.hasNext()){   //判断是否还有内容
            str.append(scan.next()).append("\n");
        }
        System.out.println(str);
    }
}

从Scanner类的操作中可以发现,Scanner类有默认的分隔符。这样如果在文件中存在换行,则表示一次输入结束,所以在本程序采用循环的方式读取,并在每次读完一行之后加入换行符,因为读取时内容需要反复修改,所以使用StringBuffer类以提升操作性能。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值