ファイルに何かを書き込んだ後、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を返します。
私が間違ったことをしたことはありますか?
うまくいったトリックはかなり奇妙でした。問題は、以前にファイルの内容を読んだとき、BufferedReader
を使用したことです。読んだ後、私はバッファを閉じました。
その間、切り替えて、FileInputStream
を使用してコンテンツを読んでいます。また、読み終わったら、ストリームを閉じます。そして今、それは機能しています。
問題は、これについての説明がないことです。
BufferedReader
とFileOutputStream
に互換性がないことはわかりません。
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();
}
}
私はこの簡単なことを試しましたが、うまくいっているようです。
file.setWritable(true);
file.delete();
わたしにはできる。
これが機能しない場合、Linuxの場合はJavaアプリケーションをSudoで実行し、Windowsの場合は管理者として実行してください。 Javaにファイルのプロパティを変更する権限があることを確認するだけです。
ファイルを削除/名前を変更する前に、すべてのリーダーまたはライター(例:BufferedReader
/InputStreamReader
/BufferedWriter
)が適切に閉じられていることを確認する必要があります。
ファイルからデータを読み書きしようとすると、ファイルはプロセスによって保持され、プログラムの実行が完了するまで解放されません。プログラムが終了する前に削除/名前変更操作を実行する場合は、Java.io.*
クラスに付属のclose()
メソッドを使用する必要があります。
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);
}
だから私は、ファイルの内容がそこにあることを知っています。通常、ファイルの内容が書き込まれることは重要であり、ファイルを閉じることができるかどうかは関係ありませんが、ファイルが閉じられているかどうかは関係ありません。あなたの場合、重要なことですが、自分でファイルを閉じて例外を処理することをお勧めします。
Eclipse IDEで作業している場合は、アプリケーションの前回の起動でファイルを閉じていないことを意味する可能性があります。ファイルを削除しようとしたときに同じエラーメッセージが表示されたとき、それが理由でした。 Eclipse IDEは、アプリケーションの終了後にすべてのファイルを閉じないようです。
このファイルを削除できない理由はありません。このファイルを保持しているユーザーを確認します。 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で予期しない動作が発生することも認めます。ファイル処理。
答えは、ファイルをロードするときに、コードの任意の行で「close」メソッドを適用する必要があるということです。
これが役立つことを願っています。 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();
}
}
file.delete()がfalseを送信している場合、ほとんどの場合、Bufferedreaderハンドルは閉じられません。すぐ近くにあり、正常に機能しているようです。
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");
}
}
出力:
削除する
すべてのストリームを閉じるか、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;
}
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
動作します。
問題は、ファイルがまだプログラムによって開かれ、ロックされていると見なされることです。または、プログラムで開かれたコンポーネントである可能性があるため、dispose()
メソッドを使用してその問題を解決する必要があります。すなわちJFrame frame; .... frame.dispose();
ここにリストされているソリューションはどれも私の状況では機能しませんでした。私の解決策は、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に設定したりする必要がなくなりました。
かつてRubyに問題があり、Windowsのファイルは、書き込みと終了後にファイルを実際に向きを変えて再読み取りできるようにするために「fsync」を必要としていました。たぶん、これは同様の症状です(もしそうなら、Windowsのバグだと思います)。
これが発生する可能性がある別のコーナーケース: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セッションの将来のすべてのURLConnection
s(グローバル)に対して、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
)に基づいています。他のバージョン以降では動作しない可能性があります。