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

StackOverflow https://stackoverflow.com/questions/991489

  •  13-09-2019
  •  | 
  •  

質問

ファイルに何かを書き込んだ後、ファイルを削除しようとしています。 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 を返します。

何か間違ったことはありますか?

役に立ちましたか?

解決 2

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

一方で、私は切り替えて、今私はFileInputStreamを使用してコンテンツを読んでいます。また、読み取りを終えた後、私は、ストリームを閉じます。そして今、それが働いています。

問題は、私はこれについての説明を持っていないです。

私は互換性がないことがBufferedReaderFileOutputStreamを知りません。

他のヒント

Javaで別のバグを修正しました。私はめったに、私の10年のキャリアの中で唯一の私の第二のそれらを見つけるん。他の人が言及したように、これは、私の解決策です。私は地獄はSystem.gc()を使用しています。しかし、ここで、私の場合には、それは絶対に不可欠です。奇妙な? YES!

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

私はこの単純なことを試してみましたが、それが動作しているようだ。

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

これは私のために動作します。

これはときに、Windows上であればLinux上で、管理者としてのsudoを使用してJavaアプリケーションを実行しようと動作しない場合。ただ、Javaは、ファイルのプロパティを変更する権限を持っていることを確認します。

適切に閉じられている:(BufferedReader / InputStreamReader / BufferedWriter EX用)

この任意のファイルの名前を変更/削除しようとする前に、あなたはすべての読者や作家のことを確認する必要があります。

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

ジョンスキートがコメントしたよう

、あなたはそれは常に閉じていていることを保証するために、最終的には{...}ブロックでファイルを閉じる必要があります。そして、代わりに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(...)を使用するので、私は、私は(IOUtils.closeQuietlyが例外をスローしません)、それを閉じる前に、ファイルの内容があることを確認するためにflushメソッドを使用します。このような何かます:

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

だから私は、ファイルの内容がそこにあることを知っています。それは通常、ファイルの内容が書かれていると、ファイルを閉じることができない場合やないように私には重要として、ファイルがクローズされたかどうか、それは本当に問題ではありません。それが重要としてあなたのケースでは、私が自分でファイルを閉じると応じた例外を処理することをお勧めします。

このファイルを削除できないようにする必要があり理由はありません。私は、このファイルのホールドを持っている誰が見てになります。 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();
}

これは私がWindows上でそれをテストしていないOS X上正常に動作しますが、私はそれがあまりにもWindows上で動作するはずと思います。私はまた、Windows w.r.t.上でいくつかの予期しない動作を見て認めますファイルの取り扱います。

あなたは、Eclipse IDEで作業している場合は、

、それはあなたがアプリケーションの前の立ち上げにファイルを閉じていないことを意味します。私は、ファイルを削除しようとしているのと同じエラーメッセージがあった場合は、それが理由でした。 Eclipse IDEは、アプリケーションの終了後にすべてのファイルを閉じない、そうです。

うまくいけば、これは役立ちます。私は私のJavaコードは、他のフォルダへのコンテンツのコピーを作った後、私は自分のファイルを削除することができませんでした同様の問題に出くわしました。豊富なグーグルの後、私は明示的にすべての単一のファイル操作関連の変数を宣言し、各ファイル操作オブジェクトのclose()メソッドを呼び出して、NULLに設定します。次に、ファイルをクリアしますにSystem.gc()という関数があり、I / Oマッピング(私はちょうどウェブサイト上で与えられているものを教えてくれ、わからない)。

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

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();
    }
}

答えは、あなたがファイルをロードするとき、あなたはコードの任意の行には、「クローズ」の方法を適用する必要がある。

私に動作します

「のfsync」必要なウィンドウ内のファイルが実際にそれを書いて、それを閉じた後、ファイルを振り向くと、再読み込みすることができるようにするために一度ルビーで問題が発生しました。多分これは同様の現れである(もしそうなら、私は本当に、Windowsのバグだと思います)。

ここに記載されている私の状況で働いていたソリューションのなし。私のソリューションは、安全のために5秒(設定可能)限度で、ファイルを削除しようと、whileループを使用することでした。

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--;
}

上記ループを使用するなど、任意の手動ガベージコレクションを実行すること、またはヌルにストリームを設定せずに働いています。

問題が開かれ、プログラムによってロックされたファイルがまだ見られていることが考えられます。または多分それはで開かれていたあなたのプログラムから構成要素であるので、あなたは、あなたがその問題を解決するためにdispose()メソッドを使用することを確認する必要があります。 即ちJFrame frame; .... frame.dispose();

あなたはすべてのストリームを閉じたり、使用する必要がしようと-リソースをブロック

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;
}

もしfile.delete()は、あなたのBufferedReaderのハンドルが閉じられませんほとんどの場合、その後偽送信しています。ただ、近くに正常に私のために働くようです。

私はWindows上で同じ問題を抱えていました。私は

とのラインでScalaのラインでファイルを読み込むために使用されます
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

作品ます。

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");
  }
}

出力:

消去

これが起こる可能性のある別の特殊なケース:経由で JAR ファイルの読み取り/書き込みを行う場合、 URL その後、同じ 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 つの方法があるようです。

  • JAR ファイルのキャッシュを無効にすることができます - 現在の URLConnection, 、またはすべての将来のために URLConnection現在の JVM セッション内で (グローバルに):

    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);
    
  • [ハッキング警告!] 手動でパージできます 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);他のバージョンまたはそれ以降のバージョンでは動作しない可能性があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top