8

一時ファイルにコピーせずに、テキスト ファイルからテキスト行を削除しようとしています。Printwriter と Scanner を使用し、同時にファイルをトラバースさせ、ライターが Scanner が読み取ったものを書き込み、各行を同じもので上書きして、目的の行に到達するまでこれを実行しようとしています。消去。次に、ライターではなくスキャナーを進め、以前と同じように続行します。コードは次のとおりです。

しかし、最初に、パラメーター: 私のファイル名は数字なので、これは 1.txt または 2.txt などと読み、f はファイル名を指定します。ファイルのコンストラクターで文字列に変換します。Int n は、削除したい行のインデックスです。

public void deleteLine(int f, int n){
 try{
 Scanner reader = new Scanner(new File(f+".txt")); 
 PrintWriter writer = new PrintWriter(new FileWriter(new File(f+".txt")),false); 
 for(int w=0; w<n; w++)
   writer.write(reader.nextLine()); 
 reader.nextLine(); 
 while(reader.hasNextLine())
   writer.write(reader.nextLine());
 } catch(Exception e){
   System.err.println("Enjoy the stack trace!");
   e.printStackTrace();
 }
}

奇妙なエラーが発生します。スタックトレースに「NoSuchElementException」と「行が見つかりません」と表示されます。異なる行を指しています。nextLine() 呼び出しのいずれかでこれを実行できるようです。この方法で行を削除することは可能ですか? もしそうなら、私は何を間違っていますか?そうでない場合、なぜですか?(ところで、これが必要な場合に備えて、テキスト ファイルは約 500 行です。ただし、それが大きいと見なされるのか、それとも問題になるのかはわかりません。)

4

3 に答える 3

24

他の人が指摘しているように、プログラムが途中でクラッシュするリスクがわずかでもある場合は、一時ファイルを使用する方がよいかもしれません。

public static void removeNthLine(String f, int toRemove) throws IOException {

    File tmp = File.createTempFile("tmp", "");

    BufferedReader br = new BufferedReader(new FileReader(f));
    BufferedWriter bw = new BufferedWriter(new FileWriter(tmp));

    for (int i = 0; i < toRemove; i++)
        bw.write(String.format("%s%n", br.readLine()));

    br.readLine();

    String l;
    while (null != (l = br.readLine()))
        bw.write(String.format("%s%n", l));

    br.close();
    bw.close();

    File oldFile = new File(f);
    if (oldFile.delete())
        tmp.renameTo(oldFile);

}

(エンコーディング、改行文字、および例外処理のずさんな扱いに注意してください。)


しかし、「どうせやってはいけないので、方法は教えません」と質問に答えるのは好きではありません。(たとえば、他の状況では、ハード ドライブの半分よりも大きなファイルを操作している可能性があります!)

代わりにa を使用する必要がありますRandomAccessFile。このクラスを使用すると、同じオブジェクトを使用してファイルの読み取りと書き込みの両方を行うことができます。

public static void removeNthLine(String f, int toRemove) throws IOException {
    RandomAccessFile raf = new RandomAccessFile(f, "rw");

    // Leave the n first lines unchanged.
    for (int i = 0; i < toRemove; i++)
        raf.readLine();

    // Shift remaining lines upwards.
    long writePos = raf.getFilePointer();
    raf.readLine();
    long readPos = raf.getFilePointer();

    byte[] buf = new byte[1024];
    int n;
    while (-1 != (n = raf.read(buf))) {
        raf.seek(writePos);
        raf.write(buf, 0, n);
        readPos += n;
        writePos += n;
        raf.seek(readPos);
    }

    raf.setLength(writePos);
    raf.close();
}
于 2011-06-25T13:05:38.557 に答える
2

このようにすることはできません。FileWriter は、ファイルの途中で書き込むのではなく、ファイルに追加することしかできません。途中で書き込みたい場合は、RandomAccessFile が必要です。あなたが今やっていること - あなたが最初にファイルに書き込むときにファイルをオーバーライドします(そして空になります - それが例外を受け取る理由です)。追加フラグを true に設定して FileWriter を作成できますが、この方法では、ファイルの途中に書き込むのではなく、ファイルに追加します。

新しいファイルに書き込み、最後に名前を変更することをお勧めします。

于 2011-06-25T13:02:16.163 に答える
1

@shelley: やろうとしていることはできません。さらに、すべきではありません。いくつかの理由で、ファイルを読み取って一時ファイルに書き込む必要があります。1 つは、(実行しようとしているのとは対照的に) この方法で実行することが可能であり、もう 1 つは、プロセスが破損した場合にベールすることができます。元のファイルを失うことなく出力します。RandomAccessFile を使用してファイルの特定の場所を更新できるようになりましたが、これは通常 (私の経験では) 通常のテキスト ファイルではなく固定サイズのレコードを扱う場合に行われます。

于 2011-06-25T12:54:24.283 に答える