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

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

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

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

Q&A

解決済

3回答

1408閲覧

Javaの読み込みと書き込みのファイルを同じにしたい

soda99

総合スコア1

Java

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

1グッド

0クリップ

投稿2022/10/11 09:49

前提

ファイルを読み込んで、上書きして終了するプログラムを作成しています。

実現したいこと

読み込んだファイルを置換後、全てを上書きしたいのですが、読み込んだファイルと書き込むファイルを同じにすることができません。

java初心者のため、細かく解説していただけると有り難いです。
よろしくお願いします。

該当のソースコード

java

1import java.io.*; 2 3public class Test{ 4 5 public static void main(String[] args){ 6 try{ 7 BufferedReader file = new BufferedReader(new FileReader("c:\\output\\input.txt")); 8 FileWriter fileWriter = new FileWriter("c:\\output\\input.txt"); 9 BufferedWriter buffWriter = new BufferedWriter(fileWriter); 10 PrintWriter printWriter = new PrintWriter(buffWriter); 11 12 String line; 13 while((line = file.readLine()) != null){ 14 15 // 置換処理 16 if(line.contains("?")){ 17 line = line.replaceAll("?", " "); 18 19 // ファイルへ書き込み 20 printWriter.write(line); 21 printWriter.flush(); 22 printWriter.close(); 23 } 24 25 } catch(FileNotFoundException e) { 26 e.printStackTrace(); 27 }catch(IOException ie){ 28 e.printStackTrace(); 29 } 30 } 31}

試したこと

読み込みと書き込みファイルのパスを同じにすると、上書きされてテキストの内容が削除されてしまいます。
ソース自体は、動くため、修正方法がわかりません。

takezoux2👍を押しています

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

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

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

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

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

jimbe

2022/10/11 11:24 編集

ご提示のコードはコンパイルエラーになります。 ループしながら close してますし。 line.replaceAll("?", " ") は "?" が正規表現として問題有りでエラーになりました。
m.ts10806

2022/10/11 21:14 編集

そういえば if(line.contains("?")){ が閉じてないのでそもそも動きませんね。 スコープの見誤りで参照できない変数からprintStackTrace()呼び出しているし。
guest

回答3

0

元ファイルを保存を兼ねてテンポラリにコピーして、そのファイルを読みながら置換・元ファイルへ書き込みを行います。
置換・元ファイルへ書き込みで例外が発生したらテンポラリのファイルを戻すことで、なるべく保存しています。

java

1import java.io.*; 2import java.nio.file.*; 3 4public class Test { 5 public static void main(String[] args) throws IOException { 6 Path path = Path.of("zzz.txt"); //"c:\\output\\input.txt" 7 Path tmpPath = Files.createTempFile("tmp", ".txt"); 8 Files.copy(path, tmpPath, StandardCopyOption.REPLACE_EXISTING); 9 try(PrintWriter writer = new PrintWriter(path.toFile())) { 10 try(BufferedReader reader = Files.newBufferedReader(tmpPath)) { 11 // 置換処理 12 for(String line; (line = reader.readLine()) != null; ) { 13 writer.println(line.replaceAll("\\?", " ")); 14 } 15 } 16 try { Files.deleteIfExists(tmpPath); } catch(Exception ignore) {} 17 } catch(Exception e) { 18 try { 19 Files.copy(tmpPath, path, StandardCopyOption.REPLACE_EXISTING); //戻す 20 try { Files.deleteIfExists(tmpPath); } catch(Exception ignore) {} 21 } catch(Exception ee) { 22 System.out.println("rollback error. the original is in " + tmpPath); 23 } 24 throw e; 25 } 26 } 27}

投稿2022/10/11 11:53

編集2022/10/11 15:21
jimbe

総合スコア13320

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

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

soda99

2022/10/14 16:29

jimbe様 ご回答ありがとうございます。 コピーして元ファイルの保存は、考えていなかったので勉強になりました。 ソースについて解説もしていただき、大変参考になりました。 ありがとうございました。
guest

0

ベストアンサー

現状の実装だと開きつつ書き込むことは出来ないので、
安全にデータを保持するためにも、readして置換した結果を配列に保持しておき、
readをcloseした後にループして全てwriteしてはどうでしょう。

もしくは別名のファイルに書き込み
→元のファイル削除→別名ファイルをリネーム

投稿2022/10/11 09:55

編集2022/10/11 10:41
m.ts10806

総合スコア80888

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

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

Zuishin

2022/10/11 10:09

読み込みと書き込みを独立させるという回答に異論はない、むしろそうすべきだと思うので修正依頼ではありませんが、たとえば RandomAccessFile を使えば読み込みと書き込みの両方ができると思います。
m.ts10806

2022/10/11 10:36 編集

>たとえば RandomAccessFile を使えば読み込みと書き込みの両方ができると思います。 有用な情報ありがとうございます。 あまり同時にするという発想はなかったので(1行ずつ読み書きするとデータがおかしくなる可能性もあるし、 PHPでもfile_get_contents()使うと取得した時にはcloseされてるから) どこかしらで試してみたいですね。
jimbe

2022/10/11 10:59

半角 '?' (1バイト?)を全角スペース(2バイト?)に置き換えることは、読み書き同時では非常に危ないよう思います。
m.ts10806

2022/10/11 11:07

確かに。 おおもとの目的と要件次第ではまた別の提案もできるかもしれません。
dodox86

2022/10/11 11:10

バッファリングや書き込みのフラッシュのタイミングを意識しつつ、読み書き同時に、と言う処理は少ないながらもたまにありますね。
m.ts10806

2022/10/11 11:14

>バッファリングや書き込みのフラッシュのタイミングを意識しつつ なるほど。私自身その手の経験がなかっただけかもしれません。 今回そこまでの対応が必要かどうかは不明ですね。
soda99

2022/10/14 16:27

m.ts10806様 ご回答ありがとうございます。 まずは、配列に保持する方法で、考えてみます。 ありがとうございました。
guest

0

Fileクラスの renameToメソッドを使ってみました。

Java

1import java.io.*; 2 3class Test { 4 public static void main(String[] args) { 5 try { 6 File fin = new File("c:\\output\\input.txt"); 7 BufferedReader br = new BufferedReader(new FileReader(fin)); 8 File fout = new File("c:\\output\\input.txt_"); 9 PrintWriter pw = new PrintWriter( 10 new BufferedWriter(new FileWriter(fout))); 11 String line; 12 while ((line = br.readLine()) != null) 13 pw.println(line.replaceAll("\\?", " ")); 14 pw.close(); 15 fout.renameTo(fin); 16 } catch (FileNotFoundException e) { 17 e.printStackTrace(); 18 } catch (IOException e) { 19 e.printStackTrace(); 20 } 21 } 22}

投稿2022/10/11 16:10

kazuma-s

総合スコア8222

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

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

soda99

2022/10/14 16:27

kazuma-s様 ご回答ありがとうございます。 renameToメソッドは、知らなかったので大変勉強になりました。 参考にさせていただきます。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.31%

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

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

質問する

関連した質問