質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

3回答

1913閲覧

JavaでSystem.inを閉じると再び開くことができないのはなぜか。

xebme

総合スコア1081

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2019/04/17 10:30

編集2020/07/30 23:05

JavaでSystem.inを閉じると再び開くことができないのはなぜですか。
以前気になってたのですが、デコレータを書けば回避できるので忘れていました。

質問

1 System.in、System.out、System.errを閉じると、再び開くことができない理由は。

  • 再び開けないとは思えません。調べると C で File Descriptor を dup する方法がありました。
  • プラットフォームごとに動作が異るから、一律に開けなくしているのか。

2 閉じないための回避策はありますか。

  • InputStreamReaderのデコレータを用意して close() をオーバーライドする方法(コード参照)。
  • それ以外に回避策はあるか。System.setIn() はこの目的で本当に使えるのか。

いまさら感のある質問で申しわけありません。

try-with-resources を使用する System.in の閉じ

Java

1 public static void main(String[] args) { 2 for (int i=0; i<2; ++i) { 3 // 2度目にSystem.inを開くことができない。 4 try (BufferedReader br = new BufferedReader( 5 new InputStreamReader(System.in))) { 6 while(true) { 7 String str = br.readLine(); 8 if ("quit".equals(str)) { 9 break; 10 } 11 } 12 // System.inはtry-with-resourceブロックの最後に閉じられる。 13 } catch(IOException e) { 14 e.printStackTrace(); 15 } 16 } 17 }

Decoraterパーターンを適用する閉じ無効策

Java

1package autocloseable; 2 3import java.io.IOException; 4import java.io.InputStream; 5import java.io.InputStreamReader; 6import java.io.UnsupportedEncodingException; 7import java.nio.charset.Charset; 8import java.nio.charset.CharsetDecoder; 9 10/** 11 * InputStreamReaderをラップする。 12 * System.inなら閉じない。それ以外なら閉じる。 13 */ 14public class SmartInputStreamReader extends InputStreamReader { 15 16 private final boolean isSystemIn; 17 18 public SmartInputStreamReader(InputStream in) { 19 super(in); 20 this.isSystemIn = (System.in == in); 21 } 22 public SmartInputStreamReader(InputStream in, String charsetName) 23 throws UnsupportedEncodingException { 24 super(in, charsetName); 25 this.isSystemIn = (System.in == in); 26 } 27 public SmartInputStreamReader(InputStream in, Charset cs) { 28 super(in, cs); 29 this.isSystemIn = (System.in == in); 30 } 31 public SmartInputStreamReader(InputStream in, CharsetDecoder dec) { 32 super(in, dec); 33 this.isSystemIn = (System.in == in); 34 } 35 36 /** 37 * InputStreamReaderの閉じを判断する。 38 * System.inなら閉じない。それ以外なら閉じる。 39 */ 40 @Override 41 public void close() throws IOException { 42 if (isSystemIn) { 43 return; 44 } else { 45 super.close(); 46 } 47 } 48}

追記(2019-6-29)

いまさらですが、java.io.Console を使うと try-with-resources でストリームが閉じられないことがわかりました。ただし eclipse で実行すると Console は null になります。コマンドラインで実行してください。

Java

1import java.io.BufferedReader; 2import java.io.Console; 3import java.io.IOException; 4 5public class ConsoleIo { 6 public static void main(String[] args) { 7 Console consl = System.console(); 8 for (int i = 0; i < 2; ++i) { 9 try (BufferedReader rdr = new BufferedReader(consl.reader())) { 10 String line = rdr.readLine(); 11 System.out.println(line); 12 } catch (IOException e) { 13 e.printStackTrace(); 14 } 15 } 16 } 17}

追記(2020-7-31)

いまさらですが、無名クラスを使用するやり方を追記。

Java

1import java.util.*; 2import java.io.InputStreamReader; 3 4public class Main_ { 5 public static void main(String[] args) throws Exception { 6 try (Scanner sc = new Scanner( 7 new InputStreamReader(System.in) {@Override public void close() {}})){ 8 } 9 } 10}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

episteme

2019/04/17 10:34

なんで C-tag ついてんの?
xebme

2019/04/17 10:38

プラットフォームの違いがなにか関係していないかと思ったので、つけました。
jimbe

2019/04/17 13:14

java での標準入出力のことをご質問ですから, 必要無いと思います.
guest

回答3

0

大して確認はしてないけどラッピングするならこうだろうな。
まあ今回の場合は for 文の外で try-resource-catch を行って for の内側は
try-catch を利用するだろう別に二重にしてはいけませんという理由はないから

class InputStreamReaderWrapper extends InputStreamReader { public NonClosingInputStreamReader(InputStream in, Charset cs) { super(in, cs); } public NonClosingInputStreamReader(InputStream in, CharsetDecoder dec) { super(in, dec); } public NonClosingInputStreamReader(InputStream in, String charsetName) throws UnsupportedEncodingException { super(in, charsetName); } public NonClosingInputStreamReader(InputStream in) { super(in); } @Override public void close() throws IOException { if (System.in != lock) { super.close(); } } }

理由?

#InputStreamReader public InputStreamReader(InputStream in) { super(in); try { sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object } catch (UnsupportedEncodingException e) { // The default encoding should always be available throw new Error(e); } } # Reader protected Object lock; protected Reader(Object lock) { if (lock == null) { throw new NullPointerException(); } this.lock = lock; }

投稿2019/04/20 00:07

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

xebme

2019/04/20 10:11

System.in は Reader のインスタンス変数 lock に保持されるので、閉じるかの判断に使える。しかし実際のread()はsdに委譲、sdのスパークラスのReadに保持されるlockは、InputStreamReaderのインスタンス。これでよろしいでしょうか。
guest

0

ストリームを閉じるのを「ストリームを提供した側」で行うようにすれば, ストリームが標準入力かどうかを知らない箇所でクローズするべきかを判断する必要は無いと思います.

投稿2019/04/17 13:22

jimbe

総合スコア12612

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

xebme

2019/04/19 10:21

『Linuxプログラミングインタフェース』Michael Kerrisk オライリージャパン『4章 ファイルI/O 統一されたインタフェース』を調べてみました。 『 ... 3つの標準ファイルデスクリプタがすでに利用可能となっていることを想定しており、通常はプログラムの実行前にシェルによりオープンされます。』と書かれており「提供した側」はJavaプログラムではない。...X系のOSではシェル、Windowsもプログラムの外側でオープンする、ですね。質問1の結論はほぼ出ました。
xebme

2019/04/19 10:24

Javaの動作についてコメントがあればお聞かせください。
jimbe

2019/04/19 13:55 編集

"提供側" をシステムまで遡る必要はありません. 最初にご提示のコードでは, ```new InputStreamReader(System.in)``` と System.in を記述していますから, InputStreamReader に System.in を "提供" した main メソッドは, close が必要無いことを分かっていることになります. ですので, ```new InputStreamReader(new CloseDisableInputStream(System.in))``` のようにラッピングしておくことができます. SmartInputStreamReader は自ら System.in と比較して close を行っていますが, 元になるストリームを生成する際に, 先のように大元が標準入力と分かっている箇所で close を無処理としたストリームを入れていれば, 後から判断する必要は無くなります.
guest

0

ベストアンサー

C言語でも一度閉じたら開けないですよ。
dup は開いているのではなくて複製しているだけです。

Unix系なら procfs で tty を指定して開くこともできると思いますけど、
そもそも in/out/err がどこに繋がっているか、はそのプロセスがどうやって起動されたかに依存するので
再び開く、というのとは違いますしね。

投稿2019/04/17 11:54

wtokuno

総合スコア448

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

xebme

2019/04/17 12:10

> どこに繋がっているか、はそのプロセスがどうやって起動されたかに依存するので なるほど、そのとおりですね。では、プログラムで閉じなければならないとしたら、どんな状況が考えられますか。閉じる必要があるでしょうか。
wtokuno

2019/04/17 12:24

デーモン化やforkしてpipeするなど、システムプログラミングで必要となることはよくありますね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問