核心技术6-输入输出"/>
JAVA核心技术6-输入输出
1. 输入与输出
为了增加程序的功能性,需要程序能够接受输入,并且适当的格式化输出。现在我们主要使用基本的控制台来实现输入输出。
1.1 读取输入
读取输入首先需要构建一个Scanner
类对象:
Scanner sc = new Scanner(System.in)
这里创建过程主要涉及了面向对象的知识,详情参看构造器和new关键字
接下来就可以用Scanner
类的各种方法来读取输入了:
nextLine
方法将读取一行的输入:public String nextLine()
System.out.println("输入你的名字:");String name = sc.nextLine();
next
方法可以读取一个单词,以空格作为分隔符:public String next()
System.out.println("输入你的名字:");String name = sc.nextLine(); //这种方法假如输入jackma rouseli,对name输出时只会输出jackma,因为这个方法以空格作为分割,碰到空格停止扫描
与上边类似的:
- 如果想读取一个整数,调用
nextInt
方法:public int nextInt()
- 如果想读取一个浮点数,调用
nextDouble
方法:public double nextDouble()
这种类似的方法还有很多,具体参看API文档,这里只是举例介绍怎么进行格式输入。
需要注意的是,Scanner类并不属于
java.lang
包中,而在java.util
包中在使用前需要先进行导包。在程序最前边加上以上代码:
import java.util.*;
因为输入是可见的,所以Scanner类不适用于从控制台读取密码,Java 6特别引入了Console类来实现这个目的。
如果想隐晦的输入密码,可以使用以下代码:
Console cons = System.console();
String username = cons.readLine("User name: ");
char[] passwd = cons.readPassword("PassWord: ");
System.out.println("User name: " + username);
System.out.println("PassWord: " + String.valueOf(passwd)); //valueOf方法将基本数据类型转换为字符串
这个方法不能在IDEA或者Eclipse等控制台使用,否则会出现Exception in thread "main" java.lang.NullPointerException
。只能在DOS命令行使用,输入密码时是不可见的,而不是传统的用*覆盖。
1.2 格式化输出
我们通常使用的输出语句为:System.out.println();
但是Java还有很多提供格式化输出转换符。
但是,与C语言相同的是,Java 5开始提供了printf
输出方法。
printf
方法输出格式:
%[标志][字符宽度][.精度]类型
double x = 1000.0/3.0;
System.out.printf("%8.2f",x); // 333.33
System.out.printf("%.2f",x); //333.33
说明:每一个以%字符开始的格式说明符都有相应的参数替换,%8.2f表示输出的字段宽度为8位(包括小数点),精度为小数点后2位,无法凑够位数的在最前边用空格代替,比如上边的打印输出语句1。
以下列举了常用于printf
的转换符。
转换符 | 类型 | 示例 |
---|---|---|
d | 十进制整数 | 125 |
x | 十六进制整数 | 6f |
o | 八进制整数 | 237 |
f | 定点浮点数 | 15.9 |
e | 指数浮点数 | 1.59e+01 |
g | 通用浮点数(e和f中较短的一个) | - |
a | 十六进制浮点数 | 0x1.f |
s | 字符串 | hello |
c | 字符 | A |
b | 布尔 | true |
h | 散列码 | 42628b2 |
% | 百分号 | % |
n | 换行 | - |
tx或者Tx | 日期时间 | 已经过时,x的替代详情见下日期和时间转换符 |
另外,还可以指定控制格式化输出的外观,下边列出一些可能常用的分组分隔符:
标志 | 目的 | 示例 |
---|---|---|
+ | 打印正数和负数的符号 | System.out.printf("%+8.2f",x); |
空格 | 在正数前边添加空格 | System.out.printf("% 8.2f",x); |
, | 添加分组分隔符 | System.out.printf("%,8.2f",x); |
- | 左对齐(默认是右对齐) | System.out.printf("%-8.2f",x); |
( | 将负数括在括号内 | System.out.printf("%(8.2f",x); |
0 | 数字前边补充0 | System.out.printf("%08.2f",x); |
#(对于f格式) | 包含小数点 | System.out.printf("%#8.2f",x); |
#(对于x或0格式) | 添加前缀0x或0 | - |
$ | 指定要格式化的参数索引 | 例如%1$d %1$x ,将分别以十进制和十六进制打印第一个参数 |
< | 格式化前边说明的数值 | 例如%d%<x ,将以十进制和16进制打印同一个值 |
可以使用静态的String.format
方法创建一个格式化的字符串来替代打印输出:
String message = String.format("Hello,%s","liming");
此外,需要注意的是$打印的是固定第一个参数,<格式化的是前一个对应的参数(参数索引从1开始,而非0),如:
System.out.printf("%1$d %1$d %1$d",1000,2000,3000); //打印的都是1000
System.out.printf("%1$d %d %d %<d",1000,2000,3000); //打印的是1000,1000,2000,2000
从上边也可以看出:"%1$d"会固定打印第一个数字,不占用下一个”%d“对应的字符。
这两个字符的作用主要是避免多次提供相同的内容来进行格式化,来减少代码冗余:
System.out.printf("%1$d %1$d %1$d",1000,1000,1000);
等效于System.out.printf("%1$d %1$d %1$d",1000);
下边列出一些具体的日期和时间转换符,这些转换大多数已经过时,新的代码应该使用java.time
包中的方法:
转换符 | 类型 | 示例 |
---|---|---|
c | 完整的时间和日期 | Mon Feb 09 18: 05 : 19 PST 2015 |
F | ISO 8601 日期 | 2015 - 02 - 09 |
D | 美国格式的日期(月/日/年) | 02/09/2015 |
T | 24小时时间 | 18 : 05 : 19 |
r | 12小时时间 | 06 : 05 : 19 pm |
R | 24小时时间,没有秒 | 18 : 05 |
Y | 4位数字的年,前边补充0 | 2015 |
y | 年的后两位数字(前边补充0) | 15 |
C | 年的前两位数字(前边补充0) | 20 |
B | 月的完整拼写 | February |
b或h | 月的缩写 | Feb |
m | 两位数的月(前边补充0) | 02 |
d | 两位数字的日(前边补充0) | 09 |
e | 两位数字的日(前边不补充0) | 9 |
A | 星期几的完整拼写 | Monday |
a | 星期几的缩写 | Mon |
j | 三位数的年的第几天(前边补充0,001~366之间) | 069 |
H | 两位数字的小时(前边补充0,00~23之间) | 18 |
k | 两位数字的小时(前边不补充0) | 18 |
I | 两位数字的小时(前边补充0,在01-12之间) | 06 |
l(小写L) | 两位数字的小时(前边不补充0) | 6 |
M | 两位数字的分钟(前边补充0) | 05 |
S | 两位数字的秒(前边补充0) | 19 |
L | 三位数字的毫秒(前边补充0) | 047 |
N | 九位数字的毫微秒(前边补充0) | 047 000 000 |
p | 上午或者下午的标志 | pm |
z | 从GMT起,RFC 822数字的位移 | -0800 |
Z | 时区 | PST |
s | 从格林尼治时间1970-01-01 00 : 00 : 00起的秒数 | 1078884319 |
Q | 从格林尼治时间1970-01-01 00 : 00 : 00起的毫秒数 | 1078884319047 |
1.3 文件读取与写入
在运行下列代码前,请先按照如下修改main方法:
public static void main(String[] args) throws IOException
1.3.1 读取文件
如果想读取文件,需要构造一个Scanner
类对象,如下所示:
Scanner in = new Scanner(Path.of("myfile.txt"), StandardCharsets.UTF_8);//这里myfile.txt需要替换为文件的绝对路径
如果文件名和路径包括\,就要在每一个\前加一个额外的反斜杠(在字符串章节讲过,\在字符串或者字符中表示转义):
//设文件地址为:C:\Users\Desktop\myfile.txt,那么构造的对象为
Scanner in = new Scanner(Path.of("C:\\Users\\29457\\Desktop\\myfile.txt"), StandardCharsets.UTF_8);
这里指定了编码方式为UTF-8字符编码,这是最常用的字符编码,但是并不是所有的文件都采用这种方式,在读取文件时,要指明他的字符编码,如果省略,则会使用运行这个Java及其默认的字符编码,会导致程序可移植性降低。
可以构造一个带有字符串参数的Scanner
,但这个Scanner
会把字符串解释为数据,而不是文件名。
Scanner in = new Scanner("myfile.txt");//这个代码不会报错,但是会将参数看作包含10个字符的数据。
1.3.2 写入文件
如果想写入文件需要构造一个PrintWriter
对象,在构造器中,需要提供文件名和字符编码:
PrintWriter out = new PrintWriter("myfile.txt",StandardCharsets.UTF_8);
如果文件不存在就创建该文件,文件位于创建的工程目录下。
可以用以下代码定位文件所在的目录:
String dir = System.getProperty("user.dir");
System.out.println(dir); //输出当前工程的路径/* public static String getProperty(String key)这个方法返回传入的键值的系统属性,如果没有返回为null。可以暂时理解为返回当前的工作目录。*/Scanner in = new Scanner(Path.of(dir+"\\myfile.txt")); //上述代码也是合法的读取,但是需要注意的是,这个时候要注意myfile.txt要在你的工作目录下,而不能在别的地方。
绝对路径:是从盘符开始的路径,形如C:\windows\system32\cmd.exe
相对路径:是从当前路径开始的路径,如当前路径为C:\windows,要描述上述路径,只需输入入system32 \cmd.exe 。
如果用一个不存在的文件构造一个Scanner
,或者用一个无法创建的文件名构造一个PrintWriter
,就会出现异常,具体处理方式可以参看异常这一章节,现在只需要告诉编译器,你知道有可能会出现这种异常。这需要在main方法中用throws
子句标记。
public static void main(String[] args) throws IOException
更多推荐
JAVA核心技术6-输入输出
发布评论