簡體   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