你好!今天的讲座将分为两个部分。我们将重复一些之前已经讨论过的旧主题,并研究一些新功能:) 让我们从第一个开始。重复是学习之母:) 你已经使用过这样的类了
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);
}
}
}
如果我们运行这段代码并在控制台中输入字母“Y”,输出将如下所示:
Й
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);
}
}
}
如果我们在控制台中输入相同的字母“Y”,这次的结果将会不同:
Й
1049
10
InputStreamReader
将读取的两个字节(208、153)转换为单个数字 1049。这是按字符读取。1049对应的是字母“Y”,很容易验证:
public class Main {
public static void main(String[] args) throws IOException {
char x = 1049;
System.out.println(x);
}
}
控制台输出:
Й
好吧,对于BufferedReader
'a(以及一般情况下的 BufferedAnything),缓冲类用于优化性能。就性能而言,访问数据源(文件、控制台、Internet 上的资源)是一项相当昂贵的操作。因此,为了减少此类调用的次数,BufferedReader
它会读取数据并将其累积在一个特殊的缓冲区中,以便我们稍后可以从该缓冲区中接收数据。这样一来,对数据源的调用次数就减少了几倍甚至几十倍!BufferedReader
'a的另一个附加功能及其相对于常规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("Пользователь ввел следующий текст:");
System.out.println(s);
reader.close();
}
}
BufferedReader+InputStreamReader работает быстрее, чем просто InputStreamReader
Пользователь ввел следующий текст:
BufferedReader+InputStreamReader работает быстрее, чем просто InputStreamReader
当然,BufferedReader
这是一种非常灵活的机制,让您不仅可以使用键盘进行工作。例如,您可以直接从 Internet 读取数据,只需将所需的 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"));
/*Сохраним текущее meaning System.out в отдельную переменную, чтобы потом
можно было переключиться обратно на вывод в консоль*/
PrintStream console = System.out;
// Присваиваем System.out новое meaning
System.setOut(filePrintStream);
System.out.println("Эта строка будет записана в текстовый файл");
// Возвращаем System.out старое meaning
System.setOut(console);
System.out.println("А эта строка - в консоль!");
}
}
结果,第一行将被写入文本文件,第二行将输出到控制台:) 您可以将此代码复制到 IDE 并运行它。通过打开文本文件,您将看到所需的行已成功写入其中:) 讲座结束。今天,我们记住了如何使用流和阅读器,回顾了它们之间的差异,并了解了System.out
我们几乎每节课都使用的新功能:) 下一堂课见!
GO TO FULL VERSION