2010-01-24 3 views
13

제게 타사를 일으키는 제 3 자 JPEG/EXIF ​​조작 라이브러리 (Mediautil)로 작업하고 있습니다. 이미지의 EXIF ​​데이터를 변경하고 싶습니다. 이렇게하려면 업데이트 된 버전을 임시 파일에 쓰고 원본을 삭제 한 다음 임시 파일의 이름을 원래 이름으로 바꿔야합니다.false를 반환하는 File.delete() 진단 ​​방법/닫히지 않은 스트림 찾기?

내 문제는 File.delete() 호출이 실패하고 false을 반환한다는 것입니다. 라이브러리가 여전히 어떤 방식 으로든 열렸기 때문일 수 있습니다.하지만 API에서 모든 스트림을 닫을 수있는 모든 작업을 수행했습니다. 심지어 악화 : 문제는 타이밍에 따라 달라질 수 있으며 Unit 테스트는 때때로 실패하고 때로는 실패합니다. 코드는 이 아니며 다중 스레드입니다.

기괴하게도 문제를 제거하는 라이브러리 호출이 하나 있지만 실제로 원하지 않는 EXIF ​​축소판도 제거됩니다. 그리고 코드를 보면, 그렇지 않으면 열어 둘 수있는 스트림을 어디에 닫을 수 있는지 전혀 알 수 없습니다.

이 아이디어를 공격하는 방법은 무엇입니까?

편집 : 은 Windows XP, 자바 (6) 그리고 또 다른 한가지에 : 나는 File.delete()를 호출하기 전에 System.gc()를 호출하는 경우, 그것이 작동하는 것을 발견했다 - 그 어떤 종료자를 트리거 아마도 때문이다. 그래서 그것은 명확히 닫히지 않은 흐름 인 것처럼 보인다.

+2

당신은 안티 바이러스 시스템에서 실행이 있습니까? 때로 AV는 파일을 작성한 후 일시적으로 파일을 열 수 있으므로 삭제하려고하는 순간에 때때로 "불행한"경우가있는 산발적 인 행동을 유발할 수 있습니다. –

+0

어떤 플랫폼에 있습니까? –

+0

@ Neeil 좋은 생각이지만 AV를 끄지 않아도 효과가있었습니다. –

답변

5

여기 디버거에 대한 도움이 필요합니다. java.io 항목을 빠르게 살펴보면 finalize() 후보가 FileOutputStream에있는 것으로 나타납니다. 따라서 브레이크 포인트를 치고 프로그램을 실행 한 다음 System.gc()을 실행하여 FileOutputStream.finalize()을 시작하여 스트림을 해제하십시오. 그게 당신 문제인지 아닌지에 대한 답을 줄 것입니다.

일단 이것을 재현 할 수 있다면 FileOutputStream 인스턴스의 인스턴스를 해당 인스턴스와 일치시키기 시작해야합니다. 훌륭한 디버거는 각 객체에 대한 내부 JVM 객체 식별자를 제공 할 것이므로 OID가 생성 될 때이를 추적하고 마무리 될 때 OID를 추적 할 수 있다면 키 호출을 finalize에 연결할 수 있습니다. 새 전화 번호 new FileOutputStream.

응용 프로그램의 복잡성에 따라 길어질 수도 있습니다.

+0

지금 시도하십시오. 짜증나는 것은 범죄자가 FileInputStream이고, 클래스를로드하기 위해 JVM에서 사용하는 것이 확실하다는 것입니다. –

+0

이제이 메소드를 사용하여 라이브러리에서 누수를 발견했습니다. –

0

라이브러리를 열기 전에 파일의 이름을 변경하지 않는 이유는 무엇입니까? 그런 다음 Java의 File.deleteOnExit()을 사용하여 이름이 바뀐 파일을 삭제하십시오. 예를 들면 : 그것은 그렇지 않으면 영업을 수있는 스트림을 닫 곳

File jpeg = new File("image.jpg"); 
File temp = new File(jpeg + ".temp.jpg"); 
jpg.renameTo(temp); 
SomeObj result = exifLibrary(temp); // or exifLibrary(new FileInputStream(temp); 
OutputStream jpegStream = new FileOutputStream(jpeg); 
output.write(result.bytes(); 
output.close(); 
temp.deleteOnExit(); 
temp.delete(); 
+0

문제는 읽혀지는 모든 파일이 EXIF ​​데이터를 업데이트 할 필요가 없다는 것입니다. –

0

그리고 코드를보고, 나는 절대적으로 볼 수 없습니다.

나는 실제 문제를 확인했다고 생각합니다. 즉, 사용중인 API가 의도적으로 열린 파일 핸들을 누수한다는 것입니다.

오픈 소스 라이브러리이므로 사용하고있는 소스 코드에 액세스 할 수 있습니다. 따라서이를 확인하고 필요할 경우 직접 해결할 수 있어야합니다. 그리고 훌륭한 시민이 되려면 패치를 제출하여 수정 사항을 프로젝트에 다시 기부하십시오.

+0

이미 API가 아닌 라이브러리의 소스 코드를 살펴 보았습니다. 그리고 수수께끼 같은 것은 하나의 라이브러리 호출이 (부작용으로서) 문제를 해결하는 것처럼 보이지만 어떤 스트림을 닫고 있는지를 볼 수 없다는 것입니다. 그럼 다시, 그것은 단지 finalizer를 실행 GC를 trigering 수 있습니다 ... –

+0

"다시, 그것은 finalizers를 실행하는 GC를 촉발 수 있습니다 ..."- 그건 내 이론도했다. 그러나 그런 경우인지 알아 보려는 시도가 있습니다. 응용 프로그램을 거대한 힙으로 실행하여 GC가 힙 고갈에 의해 트리거되지 않도록하십시오. –

+0

누출을 발견했기 때문에 마지막 코멘트가 다소 불필요합니다. 하지만 누출을 발견하지 못했다면 도움이되었을 것 같아서 ... 후세를 위해 남겨 둘 것입니다. –

1

FileOutputStream을 사용하는 경우 명시 적으로 닫으면 파일을 삭제할 수 있습니다.

대신 :

File myFile = new File("test.txt"); 
myCustomStreamProcess(new FileOutputStream(myFile)); 
boolean test = myFile.delete(); //May return false 

당신은 수행해야합니다

File myFile = new File("test.txt"); 
FileOutputStream fos = new FileOutputStream(myFile); 
myCustomStreamProcess(fos); 
fos.close(); //Allow the document to be deleted afterwards 
boolean test = myFile.delete(); //Should always return true 
+1

스택 오버플로에 오신 것을 환영합니다. 답변을하기 전에 질문과 기존 답변을주의 깊게 읽고 이해해야합니다. 당신의 대답은 내가 FileOutputStream을 사용하는 코드를 작성한다고 가정하기 때문에 도움이되지 않습니다; 그 질문에 언급 된 바와 같이 그것이 사실이 아니었다. –

+0

의견을 보내 주셔서 감사합니다. 일부 질문은 일부 임시 테스트 파일이 삭제되지 않았지만 불행히도 아직 투표하지 못했습니다. 나는 다른 사람들이 이것에 부딪 치는 것이 유용 할 것이라는 희망으로 대답했다. 부적절한 경우 제거 할 수있다. – nkatsar

관련 문제