缓冲流与扫描

/ Java SE / 0 条评论 / 468浏览

上一节留了一个问题,就是如果是一个一个字节地从键盘读取会出现数组越界和乱码的问题,先把上一节的代码贴上:

package language;

import java.io.InputStream;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 22:15 2019/1/27
 * @Description:
 */
public class ScannerTest {
    public static void main(String[] args) throws Exception{
        InputStream inputStream = System.in;
        byte[] data = new byte[1024];
        System.out.println("请输入数据");
        int len = inputStream.read(data);
        System.out.println("输入的数据为:"+new String(data,0,len));
        inputStream.close();
    }
}

出现问题原因分析:

我们先来解决数组越界问题,将接收的数组变为不定长度:

package language;

import java.io.InputStream;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 22:15 2019/1/27
 * @Description:
 */
public class ScannerTest {
    public static void main(String[] args) throws Exception{
        InputStream inputStream = System.in;
        StringBuffer buffer = new StringBuffer();
        System.out.println("请输入数据");
        int temp = 0;
        while ((temp = inputStream.read()) != -1){
            if (temp == '\n'){
                break;
            }
            buffer.append((char)temp);
        }
        System.out.println("输入的数据为:"+buffer);
        inputStream.close();
    }
}

这样虽然能解决数组越界的问题,但是中文乱码却不能处理,因为其中是一个字节一个字节的读,把汉字拆分了,如果说读取的时候是四个字节四个字节的读,可以暂时有效地处理中文乱码,但是如何判断截止条件呢?如果中间有其他英文字符出现又如何区分呢?这是个棘手的问题。接下来就学一下缓冲输入流,看如何解决乱码问题。

缓冲输入流

缓冲输入流是开发之中经常被使用的工具,其主要功能就是解决字符乱码问题。

如果想要完整的处理数据,那么就需要到缓冲区,对缓冲区的操作有两种流:

其中BufferedReader是我们要关注的重点,因为它可以输出String类型的数据,一旦能将数据变为字符串那么一切都好说,毕竟String类的功能那么强大。

继承结构:

java.lang.Object
    java.io.Reader
        java.io.BufferedReader

类定义:

public class BufferedReader extends Reader

构造函数:

public BufferedReader(Reader in)
public BufferedReader(Reader in, int sz)

主要方法:

读取单个字符:public int read() throws IOException
读取固定长度字符:public int read(char[] cbuf, int off, int len) throws IOException
读取一行的文本:<font color=red>public String readLine() throws IOException</font>

在实例化BufferedReader的时候需要传入一个Reader对象,但是System.in是InputStream类型,中间需要将字节流转换成字节流,这就需要用到InputStreamReader类进行转换。

package language;

import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 22:15 2019/1/27
 * @Description:
 */
public class ScannerTest {
    public static void main(String[] args) throws Exception{
        /*
         * System.in 是InputStream类
         * BufferedReader传入参数类型为Reader
         * 需要用InputStreamReader类将字节流转换为字符流
         */
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        System.out.print("请输入数据:");
        String str = bufferedReader.readLine();  //  读取一行数据,以换行为终止条件(\n)
        System.out.println("你输入的数据是:"+str);
        bufferedReader.close();
    }
}

用上面的方法同样可以读取文本文件,先将文本文件中的数据读入缓存区,然后再进行读取,下面是测试代码:

package language;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 22:15 2019/1/27
 * @Description:
 */
public class ScannerTest {
    public static void main(String[] args) throws Exception{
        File file = new File("D:"+File.separator+"test.txt");   // 即将读取的文本文件

        BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
        String str;
        while ((str = bufferedReader.readLine()) != null) { //  读取一行数据,以换行为终止条件(\n)
            System.out.println(str);
        }
        bufferedReader.close();
    }
}

以后读取数据可以不再使用InputStream,用缓冲输入流更加方便。

扫描:Scanner

这个类相信很多人都不陌生,因为平常的输入都会使用到它,现在来详细的学一下它。

它处在java.util包中,是一个工具类,从jdk1.5开始。

继承结构:

java.lang.Object
    java.util.Scanner

类定义:

public final class Scanner extends Object implements Iterator<String>, Closeable

构造方法:

扫描文件:public Scanner(File source) throws FileNotFoundException
从输入流扫描:public Scanner(InputStream source)
扫描字符串:public Scanner(String source)
从可读字节通道扫描:public Scanner(ReadableByteChannel source)

主要方法:

获取分隔匹配正则表达式:public Pattern delimiter()
判断是否有内容(默认正则):public boolean hasNext()
判断是否有内容(自定义正则):public boolean hasNext(Pattern pattern)
判断是否有Xxx类型的数据:public boolean hasNextXxx()
返回读取的内容(默认正则):public String next()
返回读取的内容(自定义正则):public String next(Pattern pattern)
返回Xxx类型的数据:public Xxx nextXxx()
设置默认分隔正则表达式:public Scanner useDelimiter(Pattern pattern)

为了熟悉上面方法的使用,下面用三个例子来演示:

扫描字符串:

package language;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Scanner;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 22:15 2019/1/27
 * @Description:
 */
public class ScannerTest {
    public static void main(String[] args) throws Exception{
        Scanner scanner = new Scanner("你好啊! 哈哈 也是 yes");
        scanner.useDelimiter(" ");
        while (scanner.hasNext()){
            System.out.println(scanner.next());
        }
        scanner.close();
    }
}

输出结果:

你好啊!
哈哈
也是
yes

扫描流(键盘输入):

package language;

import java.util.Scanner;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 22:15 2019/1/27
 * @Description:
 */
public class ScannerTest {
    public static void main(String[] args) throws Exception{
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入姓名:");
        String name = scanner.next();
        System.out.println("请输入年龄:");
        int age = scanner.nextInt();
        System.out.println("请输入身高:");
        float height = scanner.nextFloat();
        System.out.printf("name=%s,age=%d,height=%5.2f",name,age,height);
        scanner.close();
    }
}

输出结果:

请输入姓名:
beifnegtz
请输入年龄:
21
请输入身高:
1.777777777
name=beifnegtz,age=21,height= 1.78

扫描文本文件:

package language;

import java.io.File;
import java.util.Scanner;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 22:15 2019/1/27
 * @Description:
 */
public class ScannerTest {
    public static void main(String[] args) throws Exception{
        File file = new File("D:"+File.separator+"test.txt");   //  要扫描的文件
        Scanner scanner = new Scanner(file);        //  创建文件扫描对象
        scanner.useDelimiter("\n");     //  以换行为分隔符
        while (scanner.hasNext()){
            System.out.println(scanner.next());
        }
        scanner.close();
    }
}

使用Scanner进行流读取确实比InputStream方便多了,因为它支持各种类型的读取,如同PrintStream对象支持各种类型的输出一样。当然使用Scanner类的优势也只是在于文本数据的读取,如果是二进制文件或者数据还得使用BufferedInputStream或者InputStream。

总结:Scanner类是对InputStream类的功能补充;BufferedReader是对Reader类功能的补充;PrintStream是对OutputStream类功能的补充;PrintWriter是对Writer类的功能补充。

微信公众号浏览体验更佳,在这里还有更多优秀文章为你奉上,快来关注吧!

北风IT之路