Java字節流read函數


問題引入

做Java作業從標准輸入流獲取用戶輸入,用到了System.in.read(),然后出現了bug。

//隨機生成一個小寫字母,用戶猜5次,讀取用戶輸入,並判斷是否猜對
import java.io.IOException;
public class LetterGuessing {
	public static void main(String[] args) throws IOException {
		char ch,answer;
		//隨機生成字母
		answer=(char)(Math.random()*26+'a');
		System.out.print("請輸入一個小寫字母:");
		for(int i=1;i<=5;i++) {
			//獲取用戶輸入,可能拋出異常
			ch=(char)System.in.read();
			//比較大小
			if(ch == answer){
				System.out.println("恭喜,正確!用了"+i+"次猜對");
				break;
			}
			else if(ch > answer)
				System.out.println("您猜大了,還有"+ (5-i) +"次機會");
			else
				System.out.println("您猜小了,還有"+ (5-i) +"次機會");
		}
	}
}

輸入字符'a',按下Enter,卻沒有等我下次輸入,循環就運行了三次。

問題來源

System.in.read()按字節讀,一次讀入一個字節。后邊有詳細講解。

經調試,可知三次循環中ch分別為a,\r,\n

為什么a+Enter,會變成a\r\n呢

Windows下存在兩種文件讀寫方式,一個是二進制方式,另一種是文本方式

文本方式中寫時“換行”會變成“回車-換行”,即\r\n;讀時“回車-換行”會變成“換行”。

二進制方式中讀寫是嚴格按照一個字節一個字節的方式進行的。

在這里雖然沒有用到文件,但道理應該是一樣的

read()函數是按照一個字節一個字節讀取的,即二進制方式。

可能可以推導出,我們向輸入流中輸入數據默認是按照文本方式。

解決方法

方法一

在代碼第10行后,加兩行System.in.read();

目的是讀取掉輸入流中的/r和/n。

這種方法的局限性就是輸入字母前后不能加空格,因為它不會使空格從輸入流中刪除。

方法二

不用read()讀取,用以下代碼代替

import java.util.Scanner;
Scanner input=new Scanner(System.in);
ch=input.next().charAt(0);

這種方法就比較好,讀取字符串(忽略空格和換行,空格和換行不會留在輸入流里),然后取字符串的第一個字符。

知識點

System.in

官方文檔:https://docs.oracle.com/javase/10/docs/api/java/lang/System.html#in

System是個類,in是System的一個成員,官方介紹如下:

public static final InputStream in

The “standard” input stream. This stream is already open and ready to supply input data. Typically this stream corresponds to keyboard input or another input source specified by the host environment or user.

in是一個InputStream類型的對象,所以只需要了解InputStream即可。

InputStream

官方文檔: https://docs.oracle.com/javase/10/docs/api/java/io/InputStream.html

public abstract class InputStream	//抽象類
extends Object			//繼承Object類
implements Closeable	//實現Closeable接口

官方介紹如下:

This abstract class is the superclass of all classes representing an input stream of bytes.

翻譯為:這個抽象類是所有字節流類的父類。

字節流的含義:讀取方式為一個字節一個字節地讀取,而字符流是二個字節二個字節的讀。

Applications that need to define a subclass of InputStream must always provide a method that returns the next byte of input.

翻譯為:需要定義一個InputStream子類的應用必須提供一個返回輸入下一字節的方法(函數)。

read()

官方文檔:https://docs.oracle.com/javase/10/docs/api/java/io/InputStream.html#read()

public abstract int read() 
				throws IOException

Reads the next byte of data from the input stream. The value byte is returned as an int in the range 0 to255.

這個是重點,它返回下一字節的ASCII碼

If no byte is available because the end of the stream has been reached, the value -1 is returned. This method blocks until input data is available, the end of the stream is detected, or an exception is thrown.

A subclass must provide an implementation of this method.

Returns:

the next byte of data, or -1 if the end of the stream is reached.

Throws:

IOException - if an I/O error occurs.

作者:@臭咸魚

本文為作者原創,轉載請注明出處:https://chouxianyu.github.io/2018/09/22/Java字節流read函數/#more

歡迎轉發和評論


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM