2010-12-08 3 views
5

클라이언트에 제공되는 데이터 파일 (예 : /srv/data)이 들어있는 디렉토리가 있습니다. 일련의 업데이트를 진행하면서 /srv/data_tmp을 작업 중이며 작업이 끝나면 data을 원자 적으로 data_tmp으로 대체하고 싶습니다. File.renameTo()은 대상이 기존 디렉토리 인 경우 항상 false를 반환합니다. 어떻게해야합니까?Java에서 디렉터리를 원자 적으로 다른 디렉터리로 대체하는 방법은 무엇입니까?

+0

기본 파일 시스템에 제약이 있습니까? 분명히 FAT라면 파일 시스템이 FAT를 지원하지 않기 때문에 아무런 방법이 없습니다. 두 디렉토리가 같은 물리적 볼륨에 있는지 여부를 알고 있습니까? 새로운 JDK7 java.nio.file API를 사용할 수 있습니까, 아니면 JDK <= 6에서 작동해야합니까? –

+1

두 개의 파일 이동 작업이 엄밀히 말하면 "원자 적"으로 수행 될 수 있다고 생각하지 않습니다. 일부 파일 시스템은 일부 [원자 적 조작]을 보장하지만 (http://www.softpanorama.org/Internals/Filesystems/ntfs.shtml) OS에 여러 FS 작업이 모두에게 원자 적으로 수행되도록 요청하는 방법을 알지 못합니다 프로세스; 확실히 자바가 아닙니다. – maerics

+0

@Mike : HFS +, ext3 또는 NTFS를 사용하고 FAT을 사용하지 않을 것입니다. JDK 6에서 작동합니다. –

답변

1

나는 두려워 할 수 없다. 최소한 SO 수준은 아닙니다. 그래서 당신이 자바 애플리케이션의 맥락에서 "원 자성"을 관리한다고 할지라도, 실제 파일 시스템 수준에서 간섭하는 다른 "불량"프로세스에 대해서는 아무런 보장이 없다.

내가 너라면 this article (상당히 오래된 것이지만 몇 가지 아이디어를 제공해야 함)을 읽고 나서 more modern version에 제안 된 방법을 이식 할 수 있는지 확인하십시오.

아, 잠깐, 누군가 this을 이미 완료했습니다. 이 목표를 달성

그리고 분명히 당신의 the first one to ask here 아닌, 하나

행운을 빕니다 ...

+0

Apache Commons Transactions로 허용됩니다 이 자바 애플 리케이션의 컨텍스트에서 아주 깔끔한 방법으로.이게 나를 위해 충분하다. 귀하의 링크 주셔서 감사합니다! –

1

/srv/data 디렉토리를 기호 링크 (또는 junction in Windows XP)로 바꿀 수 있으며 적절할 경우 링크 대상을 변경할 수 있습니다. 그래도 Java 6 API에서는이를 수행 할 수 없습니다. 라이브러리에 의존하거나 명령 행 명령을 직접 작성해야합니다.

NB : 그 조작의 원 자성에 대해서는 아무런 보장을하지 않습니다.

+0

심볼 링크 접근법은 흥미 롭습니다. 그러나 파일 이름을 이미 존재하는 파일 이름으로 바꿀 수 없다는 것은 잘못된 것입니다. '/ home/me'에 a와 b가 모두 존재하면, b는 (Mac OS X/HFS +에서)'new file ("/ home/me/a")로 b를 성공적으로 덮어 씁니다. renameTo (new File ("/home/me/b ")' –

+0

아, 맞다. 기대하지 않았어 –

1

리눅스 호출 rename 시스템 호출은 이것을 허용하지 않습니다 (rename 시스템 호출은 빈 디렉토리를 덮어 쓸 수 있습니다). 그래서 나는 리눅스에서 자바로 할 수 있다고 생각합니다.

+0

'이름 바꾸기'에 대한 호출이 원자 적입니까? 그렇다면 덮어 쓰는 경우에도 마찬가지입니까? –

+0

네,하지만 [맨 페이지 ] (http://linux.die.net/man/2/rename) "덮어 쓸 때 oldpath와 newpath가 이름이 바뀌는 파일을 참조하는 창이있을 것입니다." –

0

는 중간 TMP와 함께, "심볼릭 링크"와 "이름 바꾸기"의 조합을 사용하여 완전히 가능하다 예배 규칙서. 다음의 예는 쉘,하지만 당신은 쉽게 기본 통화를 사용하는 것이 여기에 기능을 변환 할 수 있습니다 : 여기에서 가져온

mkdir -p tmp/real_dir1 tmp/real_dir2 
touch tmp/real_dir1/a tmp/real_dir2/a 
# start with ./target_dir pointing to tmp/real_dir1 
ln -s tmp/real_dir1 target_dir 
# create a symlink named target_dir in tmp, pointing to real_dir2 
ln -sf tmp/real_dir2 tmp/target_dir 
# atomically mv it into ./ replacing ./target_dir 
mv tmp/target_dir ./ 

예 : http://axialcorps.wordpress.com/2013/07/03/atomically-replacing-files-and-directories/

이 (의사 코드)로 귀결를 :

mkdir('./tmp'); 
mkdir('./tmp/real_dir1'); 
mkdir('./tmp/real_dir2'); 
symlink('./tmp/real_dir1', './target_dir') 
symlink('./tmp/real_dir2', './tmp/target_dir') 
rename('./tmp/target_dir', './target_dir') 

여기에서 최종 이름 바꾸기는 기본적입니다. 따라서 작업은 디렉토리를 사용하는 모든 프로세스의 시점에서 성공하거나 완전히 실패합니다. 작업은 원 자성입니다.

관련 문제