你好!为了方便起见,今天的课程将分为两部分。我们将重复我们之前触及的一些旧主题,并且我们将考虑一些新功能 :) 让我们从第一个开始。你已经上过很多次课了
当然
那么我们需要什么来实现这一点?首先,我们需要一个新
BufferedReader
。我希望你没有时间忘记这句话:
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
在进一步阅读之前,试着记住每个组件 — System.in
, InputStreamReader
, BufferedReader
— 负责什么以及为什么需要它。你是否记得?如果没有,不用担心。:) 如果您忘记了什么,请重新阅读本课程,该课程专供读者上课。我们将简要回顾一下他们每个人可以做什么。 System.in
— 这是一个从键盘接收数据的流。 原则上,它本身就足以实现阅读文本所需的逻辑。但是,您会记得,System.in
只能读取字节,不能读取字符:
public class Main {
public static void main(String[] args) throws IOException {
while (true) {
int x = System.in.read();
System.out.println(x);
}
}
}
如果我们执行这段代码并输入西里尔字母“Й”,输出将是:
Й
208
153
10
西里尔字符在内存中占2个字节,显示在屏幕上。数字 10 是换行符的十进制表示,即来自按 Enter 键。读字节是一种乐趣,所以使用起来System.in
不是很方便。为了正确阅读西里尔(和其他)字母,我们使用InputStreamReader
以下包装器:
public class Main {
public static void main(String[] args) throws IOException {
InputStreamReader reader = new InputStreamReader(System.in);
while (true) {
int x = reader.read();
System.out.println(x);
}
}
}
我们输入相同的字母“Й”,但这次结果不同:
Й
1049
10
InputStreamReader
将两个字节(208和153)转换为单个数字1049。这就是读取字符的意思。1049对应西里尔字母“Й”。我们可以很容易地说服自己这是真的:
public class Main {
public static void main(String[] args) throws IOException {
char x = 1049;
System.out.println(x);
}
}
控制台输出:
Й
作为forBufferedReader
(一般而言BufferedAnythingYouWant
),缓冲类用于优化性能。访问数据源(文件、控制台、Web 资源)在性能方面非常昂贵。因此,为了减少访问次数,BufferedReader
将数据读取并累积在一个专门的缓冲区中,我们从那里获取。结果,数据源被访问的次数大幅减少——可能减少了几个数量级!的另一个BufferedReader
特点及其优于普通的方法InputStreamReader
是非常有用的readLine()
方法,它读取整行数据,而不是单个数字。当然,这在处理大文本时非常方便。这是阅读线的样子:
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String s = reader.readLine();
System.out.println ("The user entered the following text:");
System.out.println(s);
reader.close();
}
}
BufferedReader+InputStreamReader is faster than InputStreamReader alone
The user entered the following text:
BufferedReader+InputStreamReader is faster than InputStreamReader alone

BufferedReader
是很灵活的。您不仅限于使用键盘。例如,您可以直接从 Web 读取数据,只需将所需的 URL 传递给读取器即可:
public class URLReader {
public static void main(String[] args) throws Exception {
URL oracle = new URL("https://www.oracle.com/index.html");
BufferedReader in = new BufferedReader(
new InputStreamReader(oracle.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
}
您可以通过传递文件路径从文件中读取数据:
public class Main {
public static void main(String[] args) throws Exception {
FileInputStream fileInputStream = new FileInputStream("testFile.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(fileInputStream));
String str;
while ((str = reader.readLine()) != null) {
System.out.println (str);
}
reader.close();
}
}
替换 System.out
现在让我们来看看我们以前没有接触过的一个有趣的功能。您一定记得,该类System
有两个静态字段 —System.in
和 System.out
. 这些孪生兄弟是流对象。 System.in
是一个InputStream
。并且System.out
是一个PrintStream
. 现在,我们将讨论 System.out
. 如果我们进入System
类的源代码,我们会看到:
public final class System {
……………...
public final static PrintStream out = null;
…………
}
因此, System.out
只是该类的一个普通静态变量System
。这没什么神奇的:)out
变量是一个PrintStream
引用。这里有一个有趣的问题:什么时候System.out.println()
执行,为什么输出到控制台而不是其他地方?这可以以某种方式改变吗?例如,假设我们要从控制台读取数据并将其写入文本文件。是否有可能以某种方式简单地使用 System.out
而不是额外的阅读器和编写器类来实现这一点?的确,它是 :) 即使System.out
变量标有修饰符,我们也可以做到final
! 
PrintStream
对象来替换当前对象。当前对象,设置在System
默认情况下,类不符合我们的目的:它指向控制台。您需要创建一个指向文本文件的新文件——我们数据的“目的地”。其次,我们需要了解如何为变量分配新值System.out
。您不能使用简单的赋值运算符,因为变量被标记为final
。 让我们从头开始倒推。碰巧的是,这个System
类有我们需要的方法:setOut()
。它获取一个PrintStream
对象并将其设置为输出目标。这正是我们所需要的!剩下的就是创建一个PrintStream
对象。这也很容易:
PrintStream filePrintStream = new PrintStream(new File("C:\\Users\\Username\\Desktop\\test.txt"));
完整代码如下所示:
public class SystemRedirectService {
public static void main(String arr[]) throws FileNotFoundException
{
PrintStream filePrintStream = new PrintStream(new File("C:\\Users\\Username\\Desktop\\test.txt"));
/* Save the current value of System.out in a separate variable so that later
we can switch back to console output */
PrintStream console = System.out;
// Assign a new value to System.out
System.setOut(filePrintStream);
System.out.println("This line will be written to the text file");
// Restore the old value of System.out
System.setOut(console);
System.out.println("But this line will be output to the console!");
}
}
结果,第一个字符串被写入文本文件,第二个字符串显示在控制台中 :) 您可以将这段代码复制到您的 IDE 中并运行它。打开文本文件,你会看到字符串已经成功写入:) 到此,我们的课程就结束了。今天我们回顾了如何使用流和阅读器。我们回顾了它们之间的不同之处,并了解了 的一些新功能System.out
,我们几乎在每一节课中都使用过这些功能 :) 直到下一节课!
GO TO FULL VERSION