跳到主要内容
  1. 所有文章/
  2. Java基础知识笔记汇总/

常用输入输出

·📄 2901 字·🍵 6 分钟

概述 #

Java语言体系中,对数据流的主要操作都封装在java.io包中,通过java.io包中的类可以实现计算机对数据的输入、输出操作。在编写输入、输出操作代码时,需要用import语句将java.io包导入到应用程序所在的类中,才可以使用java.io中的类和接口。

输入 #

使用Scanner类 #

构造方法中可以传入输入流,文件,文件路径等作为参数:

image-20220221094009115.png

image-20220221093043383.png

public class Demo {
    public static void main(String[] args) {
        Scanner in=new Scanner(System.in);
        while(in.hasNextInt()){
            int i=in.nextInt();
            System.out.println("输出"+i);
        }
        in.close();
    }
}
//idea下使用 ctrl+D 可以取消输入

扫描仪也可以使用除空格之外的分隔符。 也就说可以使用正则表达式来指定分隔符

image-20220221093717300.png

此示例从字符串读取几个项目:

     String input = "1 fish 2 fish red fish blue fish";
     Scanner s = new Scanner(input).useDelimiter("\\s*fish\\s*");
     System.out.println(s.nextInt());
     System.out.println(s.nextInt());
     System.out.println(s.next());
     System.out.println(s.next());
     s.close();

打印以下输出:

     1
     2
     red
     blue

使用BufferedReader和InputStreamReader #

构造方法中可以显式指定缓冲区的大小

image-20220221094611416.png

使用流来读取时,每次最多可以识别一行的数据(即分隔符默认是 \n),识别不了空格,因此自己需要再次对获得的数据进行处理。

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

public class Demo {
    public static void main(String[] args) throws IOException {
        //使用转换流将字节流转为字符流,使用缓冲流转为字符缓冲流
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        while(true){
            String str=br.readLine();
            if(str.equals("END")){
                break;
            }
            System.out.println("->"+str);
        }
        br.close();
    }
}
/*
123
->123
4 123
->4 123
END
*/

请注意:

(1read方法:读取单个字符。 返回:作为一个整数(其范围从 0 到 65535 (0x00-0xffff))读入的字符,如果已到达流末尾,则返回 -1

(2)readLine方法:读取一个文本行。通过下列字符之一即可认为某行已终止:换行 (’\n’)、回车 (’\r’) 或回车后直接跟着换行。 返回:包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回null

  //使用转换流将字节流转为字符流,使用缓冲流转为字符缓冲流
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        String str;
        while((str=br.readLine())!=null){
            System.out.println(str);
        }
//idea下使用 ctrl+D 可以取消输入

使用Console类 #

使用 Console 类没有关闭输入流的操作,但是一般很少用,系统可能不支持。

image-20220221100220749.png

import java.io.Console;

public class Demo {
    public static void main(String[] args) {
        Console console = System.console();
        if (console == null) {
            throw new IllegalStateException("Console is not available!");
        }
        String str;
        while(true){
            str = console.readLine("请输入");
            if("END".equals(str))break;
            System.out.println(str);
        }
    }
}

image-20220221100535704.png

使用StreamTokenizer类 #

基本方法 #

image-20220221101011874.png

了解了上面的这些方法,那么阅读StreamTokenizer源码就很简单了,通过StreamTokenizer

private StreamTokenizer() {
 
    // 将a-z的字符作为一个普通单词要素,即可以正常将这些字符解析
    wordChars('a', 'z');
    // 将A-Z的字符作为一个普通单词要素,即可以正常将这些字符解析
    wordChars('A', 'Z');
    // 将ASCII码表中160-255的字符作为一个普通单词要素,即可以正常将这些字符解析。一个单词(String)是通过多个单词要素(char)组成的
    wordChars(128 + 32, 255);
 
    // StreamTokenizer默认认为空白符就是分隔符
    // 将ASCII码表中0-' '的字符作为空白分隔符,因为StreamTokenizer默认认为空白符就是分隔符,所以这些字符也就变成了分隔符
    whitespaceChars(0, ' ');
 
    // 将/字符作为注解符,也就是说当一个token中包括/时,/后面的字符全部不再解析
    commentChar('/');
 
    // 指定 " 为分隔符
    quoteChar('"');
    // 指定 ' 为分隔符 
    quoteChar('\'');
 
    //当stream tokenizer遭遇到一个单词为双精度的浮点数时,会把它当作一个数字,而不是一个单词。
    parseNumbers();
}

区分whitespaceChars和quoteChar #

两个都是指定分隔符,但是两个指定的分隔符是有区别的,whitespaceChars指定的分隔符是空白分隔符,

我们就可以这样理解:

通过st.whitespaceChars('"', '"'); 指定 " 为空白分隔符,只要是分隔符是 " ,不管有多少个,会把所有的这个"看成是一个分隔符将字符串成功分割

image-20220221101411204.png

但是使用quoteChar('"'); 系统是不会将多个"看成是一个分隔符的

image-20220221101441190.png

它只适合单个分隔符的情况

image-20220221101509946.png

因此,我们最好使用 st.whitespaceChars('a', 'a'); 来设置分隔符。

使用方法 #

使用StreamTokenizer时要注意它默认设置是有很多字符不是单词要素的,所以会读取解析不了,如有需要需要自己用wordChars方法手动设置。我们可以简单的理解为StreamTokenizer只能读取26个英文字母、汉字、数字(只是简单的理解,他其实还可以读入别的字符,只是那些字符在算法题中几乎用不到)。其他的符号都是不可以读入的,需要我们自己用wordChars()方法设置。

普通使用

StreamTokenizer st =new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); 
 
st.nextToken(); // 获取下一组标记   默认是按照空格分割的   回车,tab是结束符 
int i=(int) st.nval;     //st.navl默认解析出的格式是double
 
st.nextToken();     
double j=st.nval; 
 
st.nextToken();     
String s=st.sval;

多组输入

public class Main {
    public static void main(String[] args) throws IOException {
 
        StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        //PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        int a, b;
        while(in.nextToken() != StreamTokenizer.TT_EOF)  // 表示读到了文件末尾
        {
            a = (int)in.nval;
            in.nextToken();
            b = (int)in.nval;
            //out.println(a + b);
            System.out.println("a + b = "+(a+b));
        }
        //out.flush();
    }
}

image-20220221102040248.png

输出 #

Formatter类 #

三种方式:

        // 一般方式
        System.out.println("x = " + x + ", y = " + y);
        // printf()方式
        System.out.printf("x = %d, y = %f\n", x, y);
        // format()方式
        System.out.format("x = %d, y = %f\n", x, y);

在下面的源码中可以看到,format与printf是等价的,它们只需要一个简单的格式化字符串,加上一串参数即可,每个参数对应一个格式修饰符。

public PrintStream printf(String format, Object ... args) {
    return format(format, args);
}

在format的具体代码中,其实就是调用Formatter的format方法:formatter.format(Locale.getDefault(), format, args);

public PrintStream format(String format, Object ... args) {
    try {
        synchronized (this) {
            ensureOpen();
            if ((formatter == null)
                || (formatter.locale() != Locale.getDefault()))
                formatter = new Formatter((Appendable) this);
            formatter.format(Locale.getDefault(), format, args);
        }
    } catch (InterruptedIOException x) {
        Thread.currentThread().interrupt();
    } catch (IOException x) {
        trouble = true;
    }
    return this;
}

Formatter类 在Java中,所有新的格式化功能都由Formatter类处理,上述的printf与format也是。可以将Formatter看作是一个翻译器,它将你的格式化字符串与数据翻译成需要的结果。当你创建一个Formatter对象的时候 ,需要向其构造器传递一些信息,告诉它最终的结果将向哪里输出。

public static void main(String[] args) throws IOException {
        String name = "huhx";
        int age = 22;
        Formatter formatter = new Formatter(System.out);
        formatter.format("My name is %s, and my age is %d ", name, age);
        formatter.close();
    }

格式化说明符 在插入数据时,如果想要控制空格与对齐,就需要精细复杂的格式修饰符,以下是其抽象的语法:

image-20220221103015555.png

  • 最常见的应用是控制一个域的最小尺寸,这可以通过指定width来实现。Formatter对象通过在必要时添加空格,来确保一个域至少达到某个长度。在默认的情况下,数据是右对齐的,通过"-“标志可以改变对齐的方向
  • 与width相对的是precision(精确度),它用来指明最大尺寸。width可以应用各种类型的数据转换,并且其行为方式都一样。precision则不一样,不是所有类型的数据都能使用precision,而且,应用于不同的类型的数据转换时,precision的意义也不同。
  • precision应用于String时,它表示打印String时输出字符的最大数量 precision应用于浮点数时,它表示小数点要显示出来的位数。默认是6位小数,如果小数位数过多则舍入,过少则在尾部补零。 由于整数没有小数部分,所以precision不能应用于整数。如果你对整数应用precision,则会触发异常
import java.util.Formatter;

public class Demo {
    static Formatter formatter = new Formatter(System.out);

    public static void printTitle() {
        formatter.format("%-15s %-5s %-10s\n", "huhx", "linux", "liuli");
        formatter.format("%-15s %-5s %-10s\n", "zhangkun", "yanzi", "zhangcong");
        formatter.format("%-15s %-5s %-10s\n", "zhangkun", "yanzhou", "zhangcong");
    }

    public static void print() {
        formatter.format("%-15s %5d %10.2f\n", "My name is huhx", 5, 4.2);
        formatter.format("%-15.4s %5d %10.2f\n", "My name is huhx", 5, 4.1);
    }

    public static void main(String[] args) {
        printTitle();
        System.out.println("----------------------------");
        print();
        formatter.close();
    }
}

image-20220221103430378.png