web-dev-qa-db-ja.com

file.delete()、file.canRead()、file.canWrite()、file.canExecute()はすべてtrueを返しますが、file.delete()はfalseを返します

ファイルに何かを書き込んだ後、FileOutputStreamでファイルを削除しようとしています。これは私が書くために使用するコードです:

private void writeContent(File file, String fileContent) {
    FileOutputStream to;
    try {
        to = new FileOutputStream(file);
        to.write(fileContent.getBytes());
        to.flush();
        to.close();
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

ご覧のように、ストリームをフラッシュして閉じますが、削除しようとすると、file.delete()はfalseを返します。

削除する前に、ファイルが存在するかどうかを確認しました。file.exists()file.canRead()file.canWrite()file.canExecute()はすべてtrueを返します。これらのメソッドを呼び出した直後にfile.delete()を試し、falseを返します。

私が間違ったことをしたことはありますか?

86
Jenny Smith

うまくいったトリックはかなり奇妙でした。問題は、以前にファイルの内容を読んだとき、BufferedReaderを使用したことです。読んだ後、私はバッファを閉じました。

その間、切り替えて、FileInputStreamを使用してコンテンツを読んでいます。また、読み終わったら、ストリームを閉じます。そして今、それは機能しています。

問題は、これについての説明がないことです。

BufferedReaderFileOutputStreamに互換性がないことはわかりません。

46
Jenny Smith

Javaの別のバグ。私はそれらを見つけることはめったになく、私の10年のキャリアの中で2番目だけです。他の人が言ったように、これは私の解決策です。ネザーを使用していますSystem.gc()。しかし、ここで、私の場合、それは絶対に重要です。変?はい!

finally
{
    try
    {
        in.close();
        in = null;
        out.flush();
        out.close();
        out = null;
        System.gc();
    }
    catch (IOException e)
    {
        logger.error(e.getMessage());
        e.printStackTrace();
    }
}
95
Da Martin

私はこの簡単なことを試しましたが、うまくいっているようです。

file.setWritable(true);
file.delete();

わたしにはできる。

これが機能しない場合、Linuxの場合はJavaアプリケーションをSudoで実行し、Windowsの場合は管理者として実行してください。 Javaにファイルのプロパティを変更する権限があることを確認するだけです。

17
Kislay Sinha

ファイルを削除/名前を変更する前に、すべてのリーダーまたはライター(例:BufferedReader/InputStreamReader/BufferedWriter)が適切に閉じられていることを確認する必要があります。

ファイルからデータを読み書きしようとすると、ファイルはプロセスによって保持され、プログラムの実行が完了するまで解放されません。プログラムが終了する前に削除/名前変更操作を実行する場合は、Java.io.*クラスに付属のclose()メソッドを使用する必要があります。

5
Sai Manoj

Jon Skeetがコメントしたように、ファイルが常に閉じられるように、finally {...}ブロックでファイルを閉じる必要があります。そして、例外をe.printStackTraceで飲み込む代わりに、例外をキャッチしてメソッドシグネチャに追加しないでください。何らかの理由でできない場合は、少なくともこれを行います:

catch(IOException ex) {
    throw new RuntimeException("Error processing file XYZ", ex);
}

次に、質問番号#2:

これを行うとどうなりますか:

...
to.close();
System.out.println("Please delete the file and press <enter> afterwards!");
System.in.read();
...

ファイルを削除できますか?

また、ファイルは閉じられたときにフラッシュされます。 IOUtils.closeQuietly(...)を使用しているため、ファイルを閉じる前に、flushメソッドを使用してファイルの内容が存在することを確認します(IOUtils.closeQuietlyは例外をスローしません)。このようなもの:

...
try {
    ...
    to.flush();
} catch(IOException ex) {
    throw new CannotProcessFileException("whatever", ex);
} finally {
    IOUtils.closeQuietly(to);
}

だから私は、ファイルの内容がそこにあることを知っています。通常、ファイルの内容が書き込まれることは重要であり、ファイルを閉じることができるかどうかは関係ありませんが、ファイルが閉じられているかどうかは関係ありません。あなたの場合、重要なことですが、自分でファイルを閉じて例外を処理することをお勧めします。

3
Ravi Wallau

Eclipse IDEで作業している場合は、アプリケーションの前回の起動でファイルを閉じていないことを意味する可能性があります。ファイルを削除しようとしたときに同じエラーメッセージが表示されたとき、それが理由でした。 Eclipse IDEは、アプリケーションの終了後にすべてのファイルを閉じないようです。

2
Gangnus

このファイルを削除できない理由はありません。このファイルを保持しているユーザーを確認します。 UNIX/Linuxでは、lsofユーティリティを使用して、どのプロセスがファイルをロックしているかを確認できます。 Windowsでは、プロセスエクスプローラーを使用できます。

lsofの場合、次のように簡単です:

lsof /path/and/name/of/the/file

プロセスエクスプローラーでは、検索メニューを使用してファイル名を入力し、ファイルをロックしているプロセスを示すハンドルを表示できます。

ここにあなたがする必要があると思うことをするいくつかのコードがあります:

FileOutputStream to;

try {
    String file = "/tmp/will_delete.txt";
    to = new FileOutputStream(file );
    to.write(new String("blah blah").getBytes());
    to.flush();
    to.close();
    File f = new File(file);
    System.out.print(f.delete());
} catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

OS Xでは正常に動作します。Windowsではテストしていませんが、Windowsでも動作するはずです。また、Windows w.r.tで予期しない動作が発生することも認めます。ファイル処理。

2
neesh

答えは、ファイルをロードするときに、コードの任意の行で「close」メソッドを適用する必要があるということです。

1
user3200921

これが役立つことを願っています。 Javaコードが他のフォルダーにコンテンツのコピーを作成した後、ファイルを削除できないという同様の問題に遭遇しました。広範囲にわたるグーグル検索の後、すべてのファイル操作関連変数を明示的に宣言し、各ファイル操作オブジェクトのclose()メソッドを呼び出して、それらをNULLに設定しました。次に、System.gc()という関数があります。これは、ファイルのI/Oマッピングをクリアします(わかりません。Webサイトで提供されていることを伝えるだけです)。

コードの例を次に示します。

public void start() {
    File f = new File(this.archivePath + "\\" + this.currentFile.getName());
    this.Copy(this.currentFile, f);

    if(!this.currentFile.canWrite()){
        System.out.println("Write protected file " +
           this.currentFile.getAbsolutePath());

        return;
    }


    boolean ok = this.currentFile.delete();
    if(ok == false){
        System.out.println("Failed to remove " + this.currentFile.getAbsolutePath());
        return;
    }
}

private void Copy(File source, File dest) throws IOException {
    FileInputStream fin;
    FileOutputStream fout;
    FileChannel cin = null, cout = null;
    try {
        fin = new FileInputStream(source);
        cin = fin.getChannel();
        fout = new FileOutputStream(dest);
        cout = fout.getChannel();

        long size = cin.size();
        MappedByteBuffer buf = cin.map(FileChannel.MapMode.READ_ONLY, 0, size);

        cout.write(buf);
        buf.clear();
        buf = null;

        cin.close();
        cin = null;

        fin.close();
        fin = null;

        cout.close();
        cout = null;

        fout.close();
        fout = null;

        System.gc();

    } catch (Exception e){
        this.message = e.getMessage();
        e.printStackTrace();
    }
}
1
poh

file.delete()がfalseを送信している場合、ほとんどの場合、Bufferedreaderハンドルは閉じられません。すぐ近くにあり、正常に機能しているようです。

0
Piyush

FOR Eclipse/NetBeans

IDEを再起動してコードを再度実行してください。これは1時間の苦労の末、私にとってはちょっとしたトリックです。

ここに私のコードがあります:

File file = new File("file-path");
if(file.exists()){
  if(file.delete()){
     System.out.println("Delete");
  }
  else{

       System.out.println("not delete");
  }
}

出力:

削除する

0
Omore

すべてのストリームを閉じるか、try-with-resourceブロックを使用する必要があります

static public String head(File file) throws FileNotFoundException, UnsupportedEncodingException, IOException
{
    final String readLine;
    try (FileInputStream fis = new FileInputStream(file);
            InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
            LineNumberReader lnr = new LineNumberReader(isr))
    {
        readLine = lnr.readLine();
    }
    return readLine;
}
0
feech

Windowsでも同じ問題が発生しました。 scalaのファイルを1行ずつ読み取る

Source.fromFile(path).getLines()

今、私は全体としてそれを読みます

import org.Apache.commons.io.FileUtils._

// encoding is null for platform default
val content=readFileToString(new File(path),null.asInstanceOf[String])

これは読み取り後にファイルを適切に閉じます

new File(path).delete

動作します。

0
sbtpr

問題は、ファイルがまだプログラムによって開かれ、ロックされていると見なされることです。または、プログラムで開かれたコンポーネントである可能性があるため、dispose()メソッドを使用してその問題を解決する必要があります。すなわちJFrame frame; .... frame.dispose();

0
Winnifred

ここにリストされているソリューションはどれも私の状況では機能しませんでした。私の解決策は、whileループを使用して、ファイルを削除しようとすることで、安全のために5秒(構成可能)の制限がありました。

File f = new File("/path/to/file");

int limit = 20; //Only try for 5 seconds, for safety
while(!f.delete() && limit > 0){
    synchronized(this){
        try {
            this.wait(250); //Wait for 250 milliseconds
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    limit--;
}

上記のループを使用すると、手動でガベージコレクションを実行したり、ストリームをnullに設定したりする必要がなくなりました。

0
etech

かつてRubyに問題があり、Windowsのファイルは、書き込みと終了後にファイルを実際に向きを変えて再読み取りできるようにするために「fsync」を必要としていました。たぶん、これは同様の症状です(もしそうなら、Windowsのバグだと思います)。

0
rogerdpack

これが発生する可能性がある別のコーナーケース:URLを介してJARファイルを読み取り/書き込みし、後で同じJVMセッション内で同じファイルを削除しようとした場合。

File f = new File("/tmp/foo.jar");
URL j = f.toURI().toURL();

URL u = new URL("jar:" + j + "!/META-INF/MANIFEST.MF");
URLConnection c = u.openConnection();

// open a Jar entry in auto-closing manner
try (InputStream i = c.getInputStream()) {

    // just read some stuff; for demonstration purposes only
    byte[] first16 = new byte[16];
    i.read(first16);
    System.out.println(new String(first16));
}

// ...

// i is now closed, so we should be good to delete the jar; but...
System.out.println(f.delete());     // says false!

理由は、Javaの内部JARファイル処理ロジックがJarFileエントリをキャッシュする傾向があるためです。

// inner class of `JarURLConnection` that wraps the actual stream returned by `getInputStream()`

class JarURLInputStream extends FilterInputStream {
    JarURLInputStream(InputStream var2) {
        super(var2);
    }

    public void close() throws IOException {
        try {
            super.close();
        } finally {

            // if `getUseCaches()` is set, `jarFile` won't get closed!

            if (!JarURLConnection.this.getUseCaches()) {
                JarURLConnection.this.jarFile.close();
            }
        }
    }
}

そして、各JarFile(むしろ、基礎となるZipFile構造体)は、構築時からclose()が呼び出されるまで、ファイルへのハンドルを保持します。

public ZipFile(File file, int mode, Charset charset) throws IOException {
    // ...

    jzfile = open(name, mode, file.lastModified(), usemmap);

    // ...
}

// ...

private static native long open(String name, int mode, long lastModified,
                                boolean usemmap) throws IOException;

このNetBeansの問題 には良い説明があります。


どうやらこれを「修正」する2つの方法があります:

  • 現在のURLConnection、または現在のJVMセッションの将来のすべてのURLConnections(グローバル)に対して、JARファイルのキャッシュを無効にできます。

    URL u = new URL("jar:" + j + "!/META-INF/MANIFEST.MF");
    URLConnection c = u.openConnection();
    
    // for only c
    c.setUseCaches(false);
    
    // globally; for some reason this method is not static,
    // so we still need to access it through a URLConnection instance :(
    c.setDefaultUseCaches(false);
    
  • [HACK WARNING!]完了したら、JarFileをキャッシュから手動で削除できます。キャッシュマネージャーSun.net.www.protocol.jar.JarFileFactoryはパッケージプライベートですが、いくつかのリフレクションマジックがあなたのために仕事を終わらせることができます:

    class JarBridge {
    
        static void closeJar(URL url) throws Exception {
    
            // JarFileFactory jarFactory = JarFileFactory.getInstance();
            Class<?> jarFactoryClazz = Class.forName("Sun.net.www.protocol.jar.JarFileFactory");
            Method getInstance = jarFactoryClazz.getMethod("getInstance");
            getInstance.setAccessible(true);
            Object jarFactory = getInstance.invoke(jarFactoryClazz);
    
            // JarFile jarFile = jarFactory.get(url);
            Method get = jarFactoryClazz.getMethod("get", URL.class);
            get.setAccessible(true);
            Object jarFile = get.invoke(jarFactory, url);
    
            // jarFactory.close(jarFile);
            Method close = jarFactoryClazz.getMethod("close", JarFile.class);
            close.setAccessible(true);
            //noinspection JavaReflectionInvocation
            close.invoke(jarFactory, jarFile);
    
            // jarFile.close();
            ((JarFile) jarFile).close();
        }
    }
    
    // and in your code:
    
    // i is now closed, so we should be good to delete the jar
    JarBridge.closeJar(j);
    System.out.println(f.delete());     // says true, phew.
    

注意:これはすべてJava 8コードベース(1.8.0_144)に基づいています。他のバージョン以降では動作しない可能性があります。

0
Janaka Bandara