繁体   English   中英

Java:结合使用BufferedReader和PrintWriter会导致问题

[英]Java: Using BufferedReader and PrintWriter in Conjunction Causes Issues

我正在尝试通过实验和《 Java2:完整参考(第5版)》一书来学习Java的io包。 下面,我尝试制作一个非常简单的程序,以使用BufferedReader实例进行一些输入,并使用PrintWriter实例提供一些简单的控制台输出。

package io;

import java.io.*;

public class UsingPrinterWriter {
    public static void main(String argv[]) {
        PrintWriter output = new PrintWriter(System.out, true);
        Profile hypro = Profile.promptedProfile();
        output.print(hypro);
        output.close();
        return;
    }
}

class Profile {
    private String first_name;
    private String last_name;
    private int age;

    Profile() {}

    Profile(String first_name, String last_name, int age) {
        this.first_name = first_name;
        this.last_name = last_name;
        this.age = age;
    }

    void setFirstName(String fn) {
        this.first_name = fn;
        return;
    }

    void setLastName(String ln) {
        this.last_name = ln;
        return;
    }

    void setAge(int a) {
        this.age = a;
        return;
    }

    static Profile promptedProfile() {
        Profile new_profile = new Profile();

        // create the writer and reader
        PrintWriter output = new PrintWriter(System.out, true);
        BufferedReader input = new BufferedReader(new InputStreamReader(System.in));

        try {
            // prompt for first name
            output.print("Enter your first name: ");
            new_profile.setFirstName(input.readLine());

            // prompt for last name
            output.print("Enter your last name: ");
            new_profile.setLastName(input.readLine());

            // prompt for age
            output.print("Enter your age: ");
            while(true) {
                try {
                    new_profile.setAge(Integer.parseInt(input.readLine()));
                    if(new_profile.age > 0 && new_profile.age < 110) {
                        break;
                    }
                    throw new NumberFormatException("Out of bounds.");
                } catch(NumberFormatException nfe) {
                    output.print("Invalid response, try again: ");
                }
            }
            input.close();          
        } catch (IOException ioe) {
            output.println(ioe);
        } finally {
            output.close();
        }

        return new_profile;
    }

    @Override
    public String toString() {
        return String.format("Profile:\n  Name: %s %s\n  Age: %d\n", this.first_name, this.last_name, this.age);
    }
}

问题1 :运行此命令(使用Eclipse IDE)时,得到的输出是空白终端,在其中输入一个字符串,另一个字符串和一个有效的整数,然后在换行符中一个接一个,然后我在其中执行output.print(...)的提示行。 这是一个例子来说明我的意思:

first
last
20
Enter your first name: Enter your last name: Enter your age:

问题2 :该行: output.print(hypro); 不会被打印。 Profile hypro = Profile.promptedProfile();Profile hypro = Profile.promptedProfile();

所以我想问:

  1. 这是怎么回事(我似乎缺少的关于这些io类的概念性知识)?
  2. 我该怎么解决这些问题?

预先谢谢你。

PS我已经知道java.util.Scanner类,但是我想解决这个问题而不使用它。 另外,我也愿意就应该在这里实现的任何更好的编程实践提出建议。

PrintWriter已缓冲,并且只有在以下两种情况下才会刷新自身:

  1. 您调用flush() ,或
  2. 您可以使用autoflush参数的true构造它, 通过调用println()或在传递给print()write()的数据中使用\\n\\r\\nprint()行终止符。

您没有做任何这些事情。 如果希望行终止的输出在print()之后立即出现,则需要刷新。

  1. 不要使用setter的return语句。
  2. 您只能打开一个PrintWriter并将其传递给您的authenticatedProfile()方法
  3. 使用PrintWriter的println(String str)方法打印到控制台
  4. 一切完成后,关闭PrintWriter。
  5. 使用正确的Java变量约定

尝试下面的代码并了解自己。

import java.io.*;

public class UsingPrinterWriter {
    public static void main(String argv[]) {
        PrintWriter output = new PrintWriter(System.out, true);
        Profile hypro = Profile.promptedProfile(output);
        output.print("\n");
        output.flush();
        output.println(hypro);
        output.close();
    }
}

class Profile {
private String firstName;
private String lastName;
private int age;

Profile() {
}

Profile(String firstName, String lastName, int age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
}

void setFirstName(String fn) {
    this.firstName = fn;

}

void setLastName(String ln) {
    this.firstName = ln;
}

void setAge(int a) {
    this.age = a;
}

static Profile promptedProfile(PrintWriter output) {
    Profile newProfile = new Profile();
    BufferedReader input = new BufferedReader(new InputStreamReader(System.in));

    try {
        // prompt for first name
        output.println("Enter your first name: ");
        output.flush();
        newProfile.setFirstName(input.readLine());

        // prompt for last name
        output.println("Enter your last name: ");
        output.flush();
        newProfile.setLastName(input.readLine());

        // prompt for age
        output.println("Enter your age: ");
        output.flush();
        while (true) {
            try {
                newProfile.setAge(Integer.parseInt(input.readLine()));
                if (newProfile.age > 0 && newProfile.age < 110) {
                    break;
                }
                throw new NumberFormatException("Out of bounds.");
            } catch (NumberFormatException nfe) {
                output.println("Invalid response, try again: ");
            }
        }
        input.close();
    } catch (IOException ioe) {
        output.println(ioe);
    }

    return newProfile;
}

@Override
public String toString() {
    return String.format("Profile:\n  Name: %s %s\n  Age: %d\n", this.firstName, this.lastName, this.age);
}
}

让我们从一些基础知识开始:

首先, 冲洗流意味着什么? ,好,这只是意味着当您刷新缓冲的流时,会清除其中的所有数据并将其发送到目标位置。 在您的代码中,刷新输出将确保将其中的所有数据发送到控制台(System.out)进行打印。

其次,流System.out是STATIC流,即您仅获得该流的一个副本,并且在关闭该流时,不能再次使用它来打印内容。

问题1 :现在,尽管您已启用自动刷新( PrintWriter output = new PrintWriter(System.out, true); // the second argument is true ),但仅在\\ r \\ n(回车换行符,CRLF)时才调用自动刷新或遇到\\ n,并且由于您的输出语句缺少这些字符,因此不会在正确的时间刷新流,因此不会显示任何提示。 当自动刷新第一次和最后一次运行时,数据一直附加到流中,直到程序结束,结果,当程序终止时,所有语句都打印在一行中。

解决方法 :如上一个答案所述,您可以使用println()而不是print() ,也可以将缺少的字符添加到print()调用中,例如:

output.print(new_profile.getName() + "\\r\\n")

或者,如果您想在同一行中获得输出,则可以在每个print()调用之后手动调用flush()(@EJP建议编辑)

问题2 :正如我刚才所说,System.out流是静态流,并且由于在调用hintdProfile promptedProfile()时关闭了该流,因此无法在UsePrinterWriter类的main方法中再次使用它。 您可以在函数调用之前尝试打印其他内容,如下所示:

output.println("foo bar"); //print something here Profile hypro = Profile.promptedProfile();

您会看到foo bar印在控制台上。

要解决的问题 :如要解决此问题,我想说的是,在使用System.out的writer对象上调用close()之前,在单个函数中打印所有内容并打印所有内容,或者可以简单地使用System.out.println(); 完全避免所有这些;)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM