请帮我理解一些细节

时间:2015-02-28 18:14:00

标签: java

我刚看过文件I / O,现在,我想弄脏手。我想:

  1. 使用带有System.in对象的Scanner对象从控制台读取输入作为其参数。
  2. 我想使用PrintWriter对象将从控制台读取的输入写入文件。

  3. 现在,使用另一个以File对象作为参数的Scanner对象,我想从文件中读取并将其显示在控制台输出上。

  4. 我试图以这种方式实现它:

    import java.io.*;
    import java.util.Scanner;
    
    
    public class A {
        public static void main(String[] args) throws FileNotFoundException {
            PrintWriter pw = new PrintWriter("File.txt");
            File f = new File("File.txt");
            Scanner scan  = new Scanner(f);
            Scanner scan2 = new Scanner(System.in);
            String s;
            System.out.println("Please enter the input:\n");
            while (scan2.hasNext()) {
                s = scan2.nextLine();
                pw.println(s);
            }
            scan2.close();
            pw.close();
            System.out.println("****************************************");
            System.out.println("Displaying output:\n");
            while (scan.hasNext()) {
                System.out.println(scan.nextLine());
            }
            scan.close();
        }
    }
    

    为了停止从控制台输入,我点击ctrl + z这是最好的,也是标准的做法吗?

    另外,如果我需要在线之间输入空格,我该怎么做?它只是忽略了空白行。

3 个答案:

答案 0 :(得分:1)

终止

关于你的主要问题," [...]我点击ctrl+z这是最好的,也是标准的做法吗?"

我假设您使用的是Windows cmd.exe,因此ctrl+z实际上意味着终端会在EOF上生成模拟stdin。因此,是标准方式,但可能对所有用户都不方便。

在Windows cmd.exe上,ctrl+z在终端提供的EOF上生成stdin。它与POSIX系统上的ctrl+d相同。这是程序读取的标准方式 - 它们从流中读取,直到它们达到EOF

确实有成千上万的程序显示出这种行为。该行为是程序使用重定向< / >管道与{{1}成功交互文件和其他程序的前提条件}。最简单的程序显示了这种行为,例如|catheadtailsortgrep以及更复杂的程序sedavconv等程序。

等待mplayer的特定令牌坏主意。这将使您的程序行为非直观,甚至在用户使用重定向时崩溃,并且不知道该令牌。即使他们知道这个令牌,也会给他们带来额外的负担。

另外等待特定令牌EOF可能是一个好主意。例如,程序EOF二进制计算器可以使用bc终止,也可以通过向其发送包含文本EOF的行。如果您想添加用户友好性,可以这样做。

但这也取决于你输入的性质。如果您的程序要处理任意输入,最终从任意文件重定向,例如,计算行或单词或字符,等待特定标记将是一个非常糟糕的主意。

只要您支持使用quit但使用令牌终止程序,您需要考虑:如果该令牌也可以是有效输入怎么办?那么您需要开始考虑逃生机制。虽然这是标准解决方案的标准问题而不是过于复杂,但对于像这样的简单程序来说,额外的复杂性通常是不合理的。

关闭资源

您的程序关闭资源很好。 但是,资源不仅应该在好的情况下关闭,而且应该在坏的情况下关闭。如果发生异常,您的程序不会关闭资源。

只使用扫描仪从EOF读取的程序可以这样写:

stdin

这使用Java import java.io.InputStream; import java.util.Scanner; import static java.lang.System.in; import static java.lang.System.out; public class ScanCat { public static void main(final String... args) { scanCat(in); } public static void scanCat(final InputStream in) { try (final Scanner scanner = new Scanner(in)) { tryScanCat(scanner); } } public static void tryScanCat(final Scanner scanner) { while (scanner.hasNextLine()) out.println(scanner.nextLine()); } } - with-resources 语句。 try块上的右括号在try上执行隐式close(),无论Scanner scanner块是成功完成还是异常。

使用try

通过致电Scanner,您可以询问scan.hasNext()是否有下一个令牌。这与询问是否有下一行不同。简单来说,令牌是一系列非空白字符。 (这实际上已经过度简化,但对于这种情况已经足够了。)当您使用Scanner 读取行时,您实际上想要询问它是否有行,因此您想使用 Scanner 而不是scan.hasNextLine()。您的scan.hasNext()也是如此。

代码样式

您的方法scan2实际上很长。理想情况下,方法只做一件事。这保持了可维护性。当然,如果在特定情况下更简洁,只有一个方法可以内置一切,但有一个小方法(或函数/程序/操作/闭包)只做一件事可以让更多的重用,更容易测试和更好的源代码可读性(只要你给你的方法好名字。)

答案 1 :(得分:0)

  

为了停止从控制台输入,我点击了ctrl + z。这是最好的,也是标准的做法吗?

绝对不是。您应该让程序停止提示您的代码。

  

另外,如果我需要在线之间输入空格,我该怎么做?它只是忽略了空白行。

您只需执行以下操作即可决定拥有“break-command”: 这是一个开箱即用的解决方案,与hasNext()hasNextLine()的传统用法不同。

String breakCommand = "~end";  //Set a string combination which is unlikely to be used
Scanenr scan2 = new Scanner(System.in);
String input = "";

do{
    input = scan2 .nextLine();
}while(!input.equals(breakCommand));
//^Keeps prompting for input from console as long as input is not "~end".

在这种情况下,您可以输入所需的任何(breakCommand除外)(包括空格和新行)。

答案 2 :(得分:0)

我完全改写了你的程序并做了各种改变 我希望你从那段代码中学到一些东西。 :-)

public static void main(String[] args) {
    File f = new File("File.txt");
    // I am defining the Writer, the Scanner and the Reader inside a try with resources statement.
    // This assures that all streams are closed properly even if an exception occurs.
    // Also I am not giving the file directly to the PrintWriter directly but instead putting a BufferedWriter in between.
    // This makes it so that if content is printed, it is not immediately written to the File, but instead is being buffered.
    // In general this is more efficient because the file has to be only opened once.
    try (PrintWriter fileWriter = new PrintWriter(new BufferedWriter(new FileWriter(f)));
            Scanner inputScanner = new Scanner(System.in);
            // Instead of using a Scanner for reading the File I am using a BufferedReader.
            // This one also buffers the content so it only has to be opened once.
            BufferedReader fileReader = new BufferedReader(new FileReader(f))) {
        System.out.println("Please enter the input:\n");
        String line;
        // In addition to using Ctrl-Z you can terminate the input by writing the line "exit."
        while (inputScanner.hasNextLine() && !(line = inputScanner.nextLine()).equals("exit")) {
            fileWriter.println(line);
        }

        // This line makes sure that all content that is saved inside the BufferedWriter gets written to the file before we read it again.
        fileWriter.flush();

        System.out.println("****************************************");
        System.out.println("Displaying output:\n");

        // Here I am simply reading the file using the BufferedReader.
        // Also I am reusing the variable line because it is no longer needed to scan the input.
        while ((line = fileReader.readLine()) != null) {
            System.out.println(line);
        }
    }
    catch (IOException e) {
        e.printStackTrace();
    }
}

你的空白线似乎也适合我。也许这是你的IDE做奇怪的事情。 (我正在使用eclipse)