2014-01-24 128 views
1

假設我有我的目錄結構如下所示:刪除文件,只有當所有的可刪除 - 饒無辜

mydirectory中
>文件1
>文件2
>文件3
> UndeletableFile
> FILE4

假設我已經實現了一個遞歸算法來刪除一個文件夾的內容,然後是文件夾本身和/或使用了一個極好的建議here

現在這裏是我無法找到一個解決方案後,在網絡上搜索一下和SO:
我想要刪除整個文件夾,但我想要做到這一點只有當它會成功爲每個文件和那裏的子文件夾。當前的實現(確切地說爲java.io.File.delete())將在被調用時立即刪除文件,然後轉到下一個文件。如果在刪除文件夾的過程中中途遇到問題,則會在系統上留下UndeletableFileFile5以及MyDirectory

這種情況下是否有一種方法或最佳實踐算法?
目標是讓讓可刪除文件生效如果操作中途失敗。畢竟他們不應該死,如果他們的家能夠存活下去,對吧?

我曾經想過到目前爲止:
也許這將是明智的只是重命名的所有文件,而不是先刪除它們,像這樣

mydirectory中
> File1temp
> File2temp
> ..

之後,如果進程失敗,我可以遍歷目錄再次重新命名所有文件恢復正常,如果成功,我可以刪除它們。

但是這對我來說效率非常低,是不是有更好的解決方案? 在我看來,這應該是一個共同的問題,請提供一個鏈接,如果我忽略了一些東西

+0

除您的應用程序之外,還有哪些人可以使用此文件?誰製造他們?其他過程?它由您或其第三方軟件管理? – Mikhail

+0

@Mikhail用戶可能會直接影響該文件夾。它們由另一個應用程序生成。當時沒有其他進程正在運行。由我管理。 **但是我想強調一下:**沒關係,如果它現在失敗了,我只想回到「不要刪除任何東西」,如果發生什麼事情 – avalancha

回答

2

沒有完全安全的方法來做到這一點。

最好的辦法是掃描所有文件,檢查是否允許刪除它們。只有掃描成功了,你才能進行實際的刪除操作。

問題在於,如果掃描後某些內容被鎖定,但在刪除之前刪除仍會在該文件上失敗。

唯一的選擇是保留所有文件的副本(即將它們移動到回收站,將它們存儲在一個zip文件中等),直到所有的刪除成功爲止,然後清空bin /刪除zip文件 - 如果不恢復。

但即使如此,還是有可能阻止恢復。

真的,你會在這裏遇到邊緣案例,你需要做的是確定它們是什麼,並決定在每種情況下期望的行爲。

+0

你能詳細說明如何最好地檢查我是否'm'被允許刪除「please? – avalancha

+0

這應該有所幫助:http://docs.oracle.com/javase/7/docs/api/java/io/File.html#canWrite%28%29 –

+0

我認爲複製它們/將它們移動到一個zip是均勻的更多的工作比重命名的想法,但除此之外,一個很好的答案,謝謝 – avalancha

0

您可以先使用一種非破壞性的方法來檢查是否有任何文件可以被刪除,例如,在UNIX上檢查文件本身及其包含的目錄是否可寫。然後遞歸地計算哪些目錄可以被刪除,然後在第二遍中刪除那些駐留在被計算爲可刪除的目錄內的文件和目錄。這種方法的問題是,在操作正在進行時,別人可能會修改目錄或文件內容或權限,因此您仍然可能得到錯誤的結果。

重命名不是一個傻瓜式的解決方案,要麼是因爲如果一個程序有文件或目錄的句柄,它可以在對象重命名時保留該句柄。因此,即使您重命名文件或將其移至「安全」位置,如果文件存在打開的句柄,其他人也可以更改其權限。

沒有一種適用於所有平臺的傻瓜式方法,因爲底層文件系統可以被其他進程同時操作。

對於單用戶場景,使用第一段概述的雙通道方法應該可行。

1

對於你的情況,當你必須獨佔使用多個文件時,通常的做法是在開始對文件進行任何操作之前,有一個單獨的信號量文件並將其鎖定。一個非常原始的例子看起來像:

private static RandomAccessFile raf; 

public static void main(String[] args) throws IOException { 
    lock(); 
    //do smth... 
    release(); 
} 

private static boolean lock() throws IOException { 
    File f = new File("Semaphore.lck"); 
    raf = new RandomAccessFile(f, "rw"); 
    FileLock fl = raf.getChannel().tryLock(); 
    return fl != null; 
} 

private static void release() throws IOException { 
    raf.close(); 
} 

了類似的方法採取Apache的駱駝集成框架,必須看看它的File組件。唯一的問題是第二個過程也應遵循相同的協議,否則它不會有任何影響。

+0

這是一個好主意!但是,我是否正確地理解,我仍然必須將這與蒂姆的答案結合起來?因爲這不會檢查文件當前是否可供我鎖定在第一位,對嗎? – avalancha

+0

如果用戶不手動訪問文件,並且所有操作都通過基於信號量的協議完成,則不必重命名文件。一旦獲得信號量,您可以安全地刪除文件。這很像Java中的同步塊。 – Mikhail

+1

是的,信號量文件運行良好 - 但只有在_everything_訪問這些文件時才使用信號量文件。即使一個進程/用戶忽略該文件也會破壞它。 –