Ken*_*enD 45 windows-server-2008 filesystems
不知何故,我们的一个旧 Server 2008(不是 R2)机器开发了一个看似无限循环的文件夹。这对我们的备份造成了严重破坏,因为备份代理试图向下递归到文件夹中并且永不返回。
文件夹结构类似于:
C:\Storage\Folder1
C:\Storage\Folder1\Folder1
C:\Storage\Folder1\Folder1\Folder1
C:\Storage\Folder1\Folder1\Folder1\Folder1
Run Code Online (Sandbox Code Playgroud)
... 等等。这就像我们在 90 年代玩过的那些Mandelbrot 套装之一。
我试过了:
RMDIR C:\Storage\Folder1 /Q/S
- 这返回 The directory is not empty
ROBOCOPY C:\temp\EmptyDirectory C:\Storage\Folder1 /PURGE
- 在 robocopy.exe 崩溃之前,这会在文件夹中旋转几分钟。任何人都可以建议一种永久关闭此文件夹的方法吗?
Ken*_*enD 45
感谢大家的有用建议。
进入 StackOverflow 领域后,我通过敲出这段 C# 代码解决了这个问题。它使用Delimon.Win32.IO库,专门解决访问长文件路径的问题。
以防万一这可以帮助其他人,这是代码 - 它通过了大约 1600 级递归,我不知何故被卡住了,花了大约 20 分钟将它们全部删除。
using System;
using Delimon.Win32.IO;
namespace ConsoleApplication1
{
class Program
{
private static int level;
static void Main(string[] args)
{
// Call the method to delete the directory structure
RecursiveDelete(new DirectoryInfo(@"\\server\\c$\\storage\\folder1"));
}
// This deletes a particular folder, and recurses back to itself if it finds any subfolders
public static void RecursiveDelete(DirectoryInfo Dir)
{
level++;
Console.WriteLine("Now at level " +level);
if (!Dir.Exists)
return;
// In any subdirectory ...
foreach (var dir in Dir.GetDirectories())
{
// Call this method again, starting at the subdirectory
RecursiveDelete(dir);
}
// Finally, delete the directory, and any files below it
Dir.Delete(true);
Console.WriteLine("Deleting directory at level " + level);
level--;
}
}
}
Run Code Online (Sandbox Code Playgroud)
Bri*_*ian 25
可能是递归连接点。可以使用Sysinternalsjunction
的文件和磁盘实用程序创建这样的东西。
mkdir c:\Hello
junction c:\Hello\Hello c:\Hello
Run Code Online (Sandbox Code Playgroud)
您现在可以无休止地向下运行 c:\Hello\Hello\Hello....(在达到 MAX_PATH 之前,大多数命令为 260 个字符,但某些 Windows API 函数为 32,767 个字符)。
目录列表显示它是一个结点:
C:\>dir c:\hello
Volume in drive C is DR1
Volume Serial Number is 993E-B99C
Directory of c:\hello
12/02/2015 08:18 AM <DIR> .
12/02/2015 08:18 AM <DIR> ..
12/02/2015 08:18 AM <JUNCTION> hello [\??\c:\hello]
0 File(s) 0 bytes
3 Dir(s) 461,591,506,944 bytes free
C:\>
Run Code Online (Sandbox Code Playgroud)
要删除使用连接实用程序:
junction -d c:\Hello\Hello
Run Code Online (Sandbox Code Playgroud)
小智 17
不是答案,但我没有足够的代表发表评论。
我曾经在 MS-DOS 系统上的当时巨大的 500MB FAT16 光盘上解决了这个问题。我使用DOS调试手动转储和解析目录表。然后我翻转了一点以将递归目录标记为已删除。我的 Dettman 和 Wyatt 'DOS Programmers' Reference' 给我指明了方向。
我仍然为此感到无比自豪。如果有任何通用工具对 FAT32 或 NTFS 卷具有如此强大的能力,我会感到惊讶和害怕。那个时候的生活比较简单。
Java 还可以处理长文件路径。它也可以做得更快。这段代码(我从 Java API 文档中复制的)将在大约 1 秒内删除一个 1600 级深度的目录结构(在 Windows 7、Java 8.0 下)并且没有堆栈溢出的风险,因为它实际上不使用递归。
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.io.*;
public class DeleteDir {
static void deleteDirRecur(Path dir) throws IOException {
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException
{
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException e)
throws IOException
{
if (e == null) {
Files.delete(dir);
return FileVisitResult.CONTINUE;
} else {
throw e;
}
}
});
}
public static void main(String[] args) throws IOException {
deleteDirRecur(Paths.get("C:/Storage/Folder1"));
}
}
Run Code Online (Sandbox Code Playgroud)
如果您chdir
进入目录并且只使用到rmdir
.
或者,如果您安装了 POSIX shell,或将其移植到 DOS 等效程序:
# untested code, didn't bother actually testing since the OP already solved the problem.
while [ -d Folder1 ]; do
mv Folder1/Folder1/Folder1/Folder1 tmp # repeat more times to work in larger batches
rm -r Folder1 # remove the first several levels remaining after moving the main tree out
# then repeat to end up with the remaining big tree under the original name
mv tmp/Folder1/Folder1/.../Folder1 Folder1
rm -r tmp
done
Run Code Online (Sandbox Code Playgroud)
(使用 shell 变量来跟踪您为循环条件重命名它的位置是像我在那里那样展开循环的另一种选择。)
这避免了 KenD 解决方案的 CPU 开销,这会迫使操作系统在n
每次添加新级别时从顶层遍历树,检查权限等。因此它具有sum(1, n) = n * (n-1) / 2 = O(n^2)
时间复杂度。从链的开头削减一个块的解决方案应该是O(n)
,除非 Windows 在重命名其父目录时需要遍历树。(的Linux / Unix没有。)解决方案,chdir
一路下跌到树的底部,并使用从那里相对路径,删除目录,因为它们chdir
备份,也应该是O(n)
,假设OS并不需要检查所有父目录每个系统调用,当你在某个地方 CD 做事情时。
find Folder1 -depth -execdir rmdir {} +
将在 CD 到最深目录时运行 rmdir。或者实际上,find 的-delete
选项适用于目录,并暗示-depth
. 所以find Folder1 -delete
应该做完全相同的事情,但速度更快。是的,Linux 上的 GNU find 是通过扫描目录、CDing 到具有相对路径的子目录,然后rmdir
是相对路径,然后是chdir("..")
. 它在上升时不会重新扫描目录,因此会消耗O(n)
RAM。
这确实是一个近似值:strace
显示它实际上使用unlinkat(AT_FDCWD, "tmp", AT_REMOVEDIR)
,open("..", O_DIRECTORY|...)
和fchdir(the fd from opening the directory)
,带着一帮fstat
中的混合呼叫了。但是如果在 find 运行时目录树没有被修改,效果是一样的。
编辑:只是为了好玩,我在 GNU/Linux(Ubuntu 14.10,在 2.4GHz 第一代 Core2Duo CPU 上,在 WD 2.5TB Green Power 驱动器(WD25EZRS)上的 XFS 文件系统上)尝试了这个。
time mkdir -p $(perl -e 'print "annoyingfoldername/" x 2000, "\n"')
real 0m1.141s
user 0m0.005s
sys 0m0.052s
find annoyingfoldername/ | wc
2000 2000 38019001 # 2k lines / 2k words / 38M characters of text
ll -R annoyingfoldername
... eventually
ls: cannot access ./annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername/annoyingfoldername: File name too long
total 0
?????????? ? ? ? ? ? annoyingfoldername
time find annoyingfoldername -delete
real 0m0.054s
user 0m0.004s
sys 0m0.049s
# about the same for normal rm -r,
# which also didn't fail due to long path names
Run Code Online (Sandbox Code Playgroud)
(mkdir -p 创建一个目录和任何缺少的路径组件)。
是的,2k rmdir ops 真的是 0.05 秒。xfs 非常擅长在日志中批量处理元数据操作,因为它们修复了元数据操作像 10 年前一样缓慢的问题。
在 ext4 上,create 花费了 0m0.279s,使用 find 删除仍然花费了 0m0.074s。
归档时间: |
|
查看次数: |
8064 次 |
最近记录: |