file.delete ()는 file.exists (), file.canRead (), file.canWrite (), file.canExecute () 모두가 true를 반환하더라도 false를 반환합니다.


90

파일을 .NET으로 작성한 후 파일을 삭제하려고합니다 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()모든 반환 사실. 이 메서드를 호출 한 직후에 시도 file.delete()하고 false를 반환합니다.

내가 잘못한 것이 있습니까?


예외가 없다는 것을 언급하는 것을 잊었습니다.
Jenny Smith

다른 프로세스에서 파일을 사용하고 있지 않습니까? 잠그 셨나요? deleteOnExit + exiting과 함께 작동합니까?
instanceof me

어떤 OS에서 실행 중입니까? 파일을 수동으로 삭제할 수 있습니까? 파일에 대한 열린 핸들이있을 수 있습니다.
akarnokd

다른 프로세스에서 사용하고 있는지 어떻게 알 수 있습니까? 나는 그것을 잠그지 않았다. 파일을 삭제하고 그 후에도 적용을 계속해야하므로 deleteOnExit 메서드를 사용할 수 없습니다. 아이디어는 한 세션 동안 다른 폴더의 파일을 저장하는 데 사용되는 임시 폴더를 내보내려고한다는 것입니다. 응용 프로그램에서 열기 버튼을 누르면 다른 파일을위한 공간을 확보하기 위해 폴더를 비워야합니다. 그 파일에 쓸 때 그 부분을 건너 뛰어도 괜찮고 삭제할 수 있습니다.
Jenny Smith

1
당신의 플러시 & 클로즈를 finally 블록으로 감싸 주시겠습니까? 나는 당신이 이것을 한 것을 알고 있으며 작동하지 않지만 귀하의 질문에 명확성을 더할 것입니다.
bharal

답변:


100

자바의 또 다른 버그. 10 년 경력 중 두 번째에 불과했습니다. 이것은 다른 사람들이 언급했듯이 내 해결책입니다. 나는 네더를 사용했다 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();
    }
}

7
나는 어떤 종류의 스트림으로 열지 않았지만 (그냥 new File(path)) 동일한 문제가 발생하여 작동 System.gc()하기 전에 추가 delete()했습니다!
ixM 2013 년

1
다른 버그는 무엇입니까?
bogdan.mustiata

나를 위해 wotk하지 않습니다. 삭제할 수없는 파일은 DownloadsFromURL 파일의 ZIP 파일입니다. 좋은 점은 다운로드 한 파일이 삭제된다는 것입니다. 어떤 생각?
Andrea_86

나를 위해 일했습니다. 그리고 @andreadi 나는 내 코드에서 FileChannel.map을 사용하지 않았습니다. System.gc트릭이 매번 작동 하기 때문에이 버그는 해결할 수없는 것으로 종료 된 것 같습니다 .
Adam Burley

단일 GC는 () 도움이되지 않을 수도 있습니다System.gc(); result = file.delete(); if (!result){ Thread.sleep(100); System.gc(); result = file.delete(); }
노트 - JJ

48

효과가있는 속임수는 꽤 이상했습니다. 문제는 이전에 파일의 내용을 읽었을 때 BufferedReader. 읽은 후 버퍼를 닫았습니다.

그동안 나는 전환했고 지금은 FileInputStream. 또한 읽기를 마친 후 스트림을 닫습니다. 그리고 이제 작동합니다.

문제는 이것에 대한 설명이 없다는 것입니다.

나도 몰라 BufferedReaderFileOutputStream호환되지 않을 수 있습니다.


4
나는 그것이 버그라고 주장 할 것이다 : java.sun.com/javase/6/docs/api/java/io/… 그것은 거기에 메소드가 스트림과 그와 관련된 모든 자원을 닫아야한다고 말한다. 나는 일반적으로 IOUtils.closeQuietly를 사용하여 반전 된 시퀀스의 모든 스트림을 닫는 것을 좋아하지만 (마지막으로 열려있는 것이 닫히는 첫 번째 스트림입니다),하지만 과잉 인 경향이 있습니다.
Ravi Wallau

2
나는이 정확한 문제를 가지고 있었고 나는 내가 미쳐 가고 있다고 생각했습니다. 솔루션에 감사드립니다!
Electrons_Ahoy

14
JDK 7이 적용된 2011 년인데 여전히 문제가 해결되지 않았습니다. 나는 단순히 무엇이 잘못된 것인지 알아낼 수 ... - 나는이 스레드를 발견 기뻐요
데이비드

내가 읽고 닫은 다음 삭제하려고 한 파일에 매우 성가신 문제가있었습니다. 여기에 언급 된 어떤 것도 도움이되지 않았습니다. 그런 다음 한 시간 후 다른 사용자가 파일을 생성했기 때문에 파일 권한 만 있음을 발견했습니다.
-D

어둠 속에서 찔러서 ... finalize()청소를 위해 전화 해줄 수있어 ? 아니면 설정 to = null? 강제 종료 및 가비지 수집을 참조하십시오 .
jww

19

나는이 간단한 것을 시도했고 작동하는 것 같다.

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

그것은 나를 위해 작동합니다.

이것이 작동하지 않으면 Linux에서는 sudo로, Windows에서는 관리자로 Java 애플리케이션을 실행하십시오. Java에 파일 속성을 변경할 수있는 권한이 있는지 확인하기 위해서입니다.


1
이 문제에 대해; 일반적으로 사람들은 참조를 null로 설정하거나 system.gc (); 하지만 서버를 다시 시작한 후에도 파일이 삭제되지 않았습니다 !! 하지만 file.setWritable (true); 단지 일 ...
디팍 Singhal이에게

6

파일을 삭제 / 이름 변경하기 전에 모든 판독기 또는 작성기 (예 : BufferedReader/ InputStreamReader/ BufferedWriter)가 제대로 닫혔 는지 확인해야합니다 .

파일에서 데이터를 읽고 쓰려고 할 때 파일은 프로세스에 의해 유지되고 프로그램 실행이 완료 될 때까지 해제되지 않습니다. 프로그램이 종료되기 전에 삭제 / 이름 변경 작업을 수행하려면 클래스 close()와 함께 제공 되는 메서드를 사용해야합니다 java.io.*.


1
이것은 Windows에서만 해당됩니다. 실제 O / S에서 열린 파일을 삭제하고 이름을 바꿀 수 있습니다.
Archie

3

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

그래서 나는 파일의 내용이 거기에 있다는 것을 알고 있습니다. 일반적으로 파일의 내용이 기록되고 파일을 닫을 수 있는지 여부가 아니라 파일이 닫혔는지 여부는 중요하지 않습니다. 귀하의 경우 중요하므로 파일을 직접 닫고 예외를 처리하는 것이 좋습니다.


나는 첫 번째 시도-finally 블록에서 출력 스트림을 닫습니다. 그리고 그것은 작동하지 않았습니다. 그 후에 읽으려고하면 스트림이 닫혔다는 메시지가 표시됩니다. FileInputReader로 파일을 전환하고 읽을 때 위에서 설명한 "나쁜"일이 발생하지 않았습니다.
Jenny Smith

2

이 파일을 삭제할 수없는 이유는 없습니다. 이 파일을 누가 보유하고 있는지 확인하겠습니다. 유닉스 / 리눅스에서는 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 wrt 파일 처리에서 예상치 못한 동작이 있음을 인정할 것입니다.


1
Windows의 경우 MS에서 무료 Process Explorer를 다운로드 할 수 있습니다. technet.microsoft.com/en-us/sysinternals/bb896653.aspx
akarnokd

2

Eclipse IDE에서 작업하는 경우 이전 애플리케이션 실행에서 파일을 닫지 않았 음을 의미 할 수 있습니다. 파일을 삭제하려고 할 때 동일한 오류 메시지가 표시되는 것이 그 이유였습니다. Eclipse IDE는 응용 프로그램 종료 후 모든 파일을 닫지 않는 것 같습니다.


1

이것이 도움이되기를 바랍니다. 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();
    }
}

1

대답은 파일을로드 할 때 코드 줄에 "close"메서드를 적용해야한다는 것입니다.


0

한때 루비에서는 윈도우의 파일이 파일을 쓰고 닫은 후 실제로 돌아 서서 다시 읽을 수있는 "fsync"가 필요한 문제가있었습니다. 아마도 이것은 비슷한 현상 일 것입니다 (그렇다면 윈도우 버그라고 생각합니다).


0

여기에 나열된 솔루션 중 어느 것도 내 상황에서 작동하지 않았습니다. 내 해결책은 안전을 위해 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--;
}

위의 루프를 사용하면 수동 가비지 수집을 수행하거나 스트림을 null로 설정하지 않고도 작동했습니다.


당신은 무엇을 사용합니까? STREAMS에 액세스 할 수있는 경우 닫으면 작동합니다. 그러나 파일이 "이미"잠겨 있으면 문제가있는 것입니다.
marcolopes 2013

1
-1 파일을 삭제하기 위해 코드를 반복하는 것은 좋은 생각이 아닙니다. 작동하는 gc () 옵션을 사용하지 않는 이유는 무엇입니까?
bharal

@bharal Notice 위에서 언급 한 것은 다른 솔루션 (gc () 포함)이 저의 특별한 경우에 효과가 없었습니다. while 루프를 사용하는 것이 이상적이지는 않지만 특정 상황에서는 적절한 솔루션이 될 수 있습니다. 위의 코드에 시간 초과 또는 최대 반복 변수와 같은 추가 검사를 추가하면 while 루프를 더 안전하게 만드는 좋은 방법이 될 것입니다.
etech 2013-07-25

파일이 존재하지 않았다면 @etech는 방금 무한 루프를 만든 것입니다.
bharal

0

문제는 파일이 여전히 프로그램에 의해 열리고 잠긴 것으로 보인다는 것입니다. 또는 프로그램에서 열었던 구성 요소 일 수 있으므로 dispose()해당 문제를 해결하는 방법을 사용해야합니다 . 즉JFrame frame; .... frame.dispose();


0

모든 스트림을 닫거나 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

file.delete ()가 false를 보내는 경우 대부분의 경우 Bufferedreader 핸들이 닫히지 않습니다. 닫으면 정상적으로 작동하는 것 같습니다.


0

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

공장.


0

Eclipse / NetBeans 용

IDE를 다시 시작하고 코드를 다시 실행하십시오. 이것은 한 시간의 긴 노력 끝에 저에게 유일한 트릭 작업입니다.

내 코드는 다음과 같습니다.

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

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

산출:

지우다


0

이것이 발생할 수있는 또 다른 코너 케이스 : a를 통해 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 문제 에 대한 좋은 설명 있습니다.


이 문제를 "수정"하는 방법에는 두 가지가 있습니다.

  • JAR 파일 캐싱을 비활성화 할 수 있습니다 . 현재 JVM 세션의 현재 URLConnection또는 모든 미래 URLConnection(전역)에 대해

    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); 다른 / 이후 버전에서는 작동하지 않을 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.