您的位置:首页 > 编程语言 > Java开发

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

2014-07-22 11:07 691 查看

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();
}
}


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

程序制定了输入数据的长度,如果现在输入的数据超出了其长度范围,则只能输入部分数据
如果指定的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));
}
}


上面程序存在的问题:

如果输入的字符串不是数字,则肯定无法转换,会出现NumberFormatException异常。所以在转换时应该使用正则表达式进行验证:如果验证成功了,则表示可以进行转换;如果验证失败了,则表示无法进行转换,此时就要等待用户重新输入期待的数据类型:数字。
只能输入整数
代码重复:只要输入数据,则肯定是用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类以提升操作性能。


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: