Windows'ta numaralı Java'yı doğru bir şekilde kullanarak "geçici dosya yaz ve yeniden adlandır" işlevini uygulamamaya çalışıyorum. Dosyaların yeniden adlandırılmasının "atomik işlem" olduğunu (aslında "atomik" ifadesiyle gerçekte olduğu anlamına gelir) önerir. https://stackoverflow.com/a/20570968/65458, tmp dosyasının yazılmasını ve yeniden adlandırmanın çapraz platform olduğunu ve son dosyanın bulunmadığını ya da diğer işlem tarafından işlenebilmesini sağlar. Bu yüzden aslında bu yaklaşımı uygulamaya çalıştım. Aşağıda benim girişimlerimin özeti. Asıl soru için - dibe atlayın.Windows'ta Java'da nasıl atomik olarak yeniden adlandırma dosyası oluşturulur?
java.nio.file.Files
Kullanılması:
yazma yöntemleri
Ben yazının çeşitli yollar ve yeniden adlandırma dosya (content
ve
charset
sırasıyla
String
ve
Charset
vardır) denedik
Files.copy(new ByteArrayInputStream(content.getBytes(charset)), tmpFile);
Files.move(tmpFile, finalFile, StandardCopyOption.ATOMIC_MOVE);
Guava (14) kullanma ve java.io.File
:
com.google.common.io.Files.write(content, tmpFile, charset);
tmpFile.renameTo(finalFile);
Hatta daha karanlık yaklaşımlar:
try (OutputStream os = new FileOutputStream(tmpFile);
Writer writer = new OutputStreamWriter(os, charset)) {
writer.write(content);
}
Runtime.getRuntime().exec(
new String[] { "cmd.exe", "/C", "move " + tmpFile + " " + finalFile }).waitFor();
okuma yöntemleri Şimdi
(bunun başka bir süreç olabilir gerçek hayatta, testlerde olduğum için iplik) Başka bir iş parçacığı varsayalım
birini yürütülürkenortak fonksiyonu ile:
void waitUntilExists() throws InterruptedException {
while (!java.nio.file.Files.exists(finalFile)) {
NANOSECONDS.sleep(1);
}
}
kullanma kod sürümleri aşağıdaki:
waitUntilExists();
return new String(Files.readAllBytes(finalFile), charset);
Guava (14) kullanarak:
waitUntilExists();
return new String(com.google.common.io.Files.toByteArray(finalFile.toFile()), charset);
Hatta daha karanlık yaklaşımlar:
waitUntilExists();
StringBuilder sb = new StringBuilder();
try (InputStream is = new FileInputStream(finalFile.toFile())) {
byte[] buf = new byte[8192];
int n;
while ((n = is.read(buf)) > 0) {
sb.append(new String(buf, 0, n, charset));
}
}
return sb.toString();
Sonuçlar
kullanıyorum kullanarak okumak "Eğer java.nio.file.Files
yaklaşım ", her şey iyi çalışıyor.
Bu kodu Linux'ta çalıştırırsam (bu sorunun kapsamı dışında), her şey yolunda gidiyor. ı uygulamak durumunda
Ancak % 0.5 üstünde bir olasılıkla (0.005) testi
java.io. başarısız sonra Guava veya
FileInputStream
ile okuFileNotFoundException: o başıma tercüme
(Message benim pencere neden başka bir işlem tarafından kullanıldığı için Süreç İngilizce değil, dosyaya erişemiyor; "başka bir işlem" değinen yanıltıcı olduğunu, bunun Windows için normaldir çünkü Bu, açık engelleme ile doğrulanmış bir ben aynı işlem olsa bile bu anlat.)
Soru
nasıl uygulanır oluşturmak-sonra-adlandırmak son dosya, atomik yani görünür ya değildir, böylece Windows üzerinde Java kullanarak var ya da okunabilir?
Dosyaları teslim almaktan ziyade süreçleri kontrol ettiğimden, kullanımda herhangi bir özel okuma yöntemini veya Java içinde olduklarını bile edemiyorum. Bu nedenle çözüm, yukarıda listelenen tüm okuma yöntemleri ile çalışmalıdır.
"Oku" (Guava ve FileInputStream) hangi yolla yazılır (NIO)? – SubOptimal
Guava veya 'FileInputStream' ile' read' uygulandığında, kullanılan 'write' yönteminden bağımsız olarak rasgele olarak başarısız olur. 'read' NIO ile uygulandığında, kullanılan' write' yöntemine bakılmaksızın her zaman başarılı olur. (Aslında sanırım farklı "yazma" yöntemleri kaputun altında gerçekten farklı olmayabilir, çünkü her şey dosya yeniden adlandırılırken ya da - Windows API'da farklı adlandırma yöntemleri olabilir mi?) –
Kullandığınız yeniden adlandırma, NIO okuma her zaman başarılı ve Guave/FileInputStream zaman zaman başarısız oluyor? – SubOptimal