使用C#取消目录的只读属性

16
我成功地使用以下代码片段从文件中删除只读属性:
在main.cs中:
FileSystemInfo[] sqlParentFileSystemInfo = dirInfo.GetFileSystemInfos();

foreach (var childFolderOrFile in sqlParentFileSystemInfo)
{
    RemoveReadOnlyFlag(childFolderOrFile);
}

private static void RemoveReadOnlyFlag(FileSystemInfo fileSystemInfo)
{
    fileSystemInfo.Attributes = FileAttributes.Normal;
    var di = fileSystemInfo as DirectoryInfo;

    if (di != null)
    {
        foreach (var dirInfo in di.GetFileSystemInfos())
            RemoveReadOnlyFlag(dirInfo);
    }
}

很遗憾,这在文件夹上不起作用。 运行代码后,当我进入文件夹、右键点击并选择属性时,会看到以下内容:

alt text

只读标志仍然被选中,尽管已从其中的文件中删除。这会导致一个进程无法删除该文件夹。当我手动删除标志并重新运行进程(一个批处理文件)时,它能够删除该文件(所以我知道这不是批处理文件的问题)

如何在C#中移除此标志?


10个回答

10

您也可以使用以下方法递归清除指定父目录中所有目录和文件的只读属性(以及存档等):

private void ClearReadOnly(DirectoryInfo parentDirectory)
{
    if(parentDirectory != null)
    {
        parentDirectory.Attributes = FileAttributes.Normal;
        foreach (FileInfo fi in parentDirectory.GetFiles())
        {
            fi.Attributes = FileAttributes.Normal;
        }
        foreach (DirectoryInfo di in parentDirectory.GetDirectories())
        {
            ClearReadOnly(di);
        }
    }
}
你因此可以这样调用:
public void Main()
{
    DirectoryInfo parentDirectoryInfo = new DirectoryInfo(@"c:\test");
    ClearReadOnly(parentDirectoryInfo);
}

6
请尝试使用DirectoryInfo代替FileInfo。
DirectoryInfo di = new DirectoryInfo(@"c:\temp\content");
di.Attributes = FileAttributes.Normal;

清理文件属性 -

foreach (string fileName in System.IO.Directory.GetFiles(@"c:\temp\content"))
{
    System.IO.FileInfo fileInfo = new System.IO.FileInfo(fileName);
    fileInfo.Attributes = FileAttributes.Normal;
}

这似乎在目录上不起作用。我仍然看到设置为只读的属性。 - DotnetDude

3
在Windows中,文件夹上的只读标志实际上是一个误称。文件夹并不使用只读标志。问题在于自定义设置。该标志被Windows用于识别文件夹上是否有自定义设置。这篇文章虽然是一个老帖子,但问题正在逐渐消失。不过,人们可能仍会遇到此问题,因为它相当恼人。微软的解释

3
对话框的工作方式非常奇怪。无论ReadOnly属性的状态如何,它总是以屏幕截图中看到的方式显示。复选框处于“不定”状态。您必须单击它并清除或选中它才能执行其操作。尽管有提示文本(但复选框旁边的提示除外),它仅更改目录中文件的ReadOnly属性,而不更改目录本身。
使用attrib命令行命令查看实际发生了什么。很可能,您的代码失败是因为目录包含具有设置其ReadOnly属性的文件。您需要对它们进行迭代。

2

以防万一,如果有人后来看到这个...

在我之前发布的所有答案要么是错误的,要么使用了不必要的递归。

首先,在Windows的属性对话框中,“只读”复选框对于文件夹总是带有三态标记。这是因为文件夹本身并非只读,但其中的文件可以是只读的。

如果您想为所有文件设置/取消设置只读标志,则可以按照以下简单步骤操作:

void SetReadOnlyFlagForAllFiles(DirectoryInfo directory, bool isReadOnly)
{
    // Iterate over ALL files using "*" wildcard and choosing to search all directories.
    foreach(FileInfo File in directory.GetFiles("*", SearchOption.All.Directories))
    {
        // Set flag.
        File.IsReadOnly = isReadOnly;
    }
}

当目录是只读的时候,无法向目录中添加/删除文件,那么你该怎么办呢?这就是OP所问的问题。 - Dunk
@Dunk 不是要求的内容。而且您仍然有一种奇怪的想法,即“目录”具有只读属性……它没有。您尝试过任何代码吗?OP的代码实际上确实有效,但只是因为您可以将DirectoryInfo强制转换为FileInfo。它真正做的只是在所有文件上设置属性,请自行测试。目录无法设置为FileAttibutes.Normal或.ReadOnly,它始终为.Directory。就像我说的,资源管理器始终为目录显示中间状态。另外,BAT文件可以以任何方式删除“只读”目录,因此更有可能是其他地方锁定了他的PC。 - Dave Williams

2

使用IEnumerable / Lambda递归删除目录和文件的只读属性的解决方案:

new DirectoryInfo(@"some\test\path").GetDirectories("*", SearchOption.AllDirectories).ToList().ForEach(
    di => {
        di.Attributes &= ~FileAttributes.ReadOnly;
        di.GetFiles("*", SearchOption.TopDirectoryOnly).ToList().ForEach(fi => fi.IsReadOnly = false);
    }
);

1

在原始的dirInfo上设置Attributes属性:

dirInfo.Attributes = FileAttributes.Normal;

FileSystemInfo[] sqlParentFileSystemInfo = dirInfo.GetFileSystemInfos();

foreach (var childFolderOrFile in sqlParentFileSystemInfo)
{
    RemoveReadOnlyFlag(childFolderOrFile);
}

不起作用。仍然看到带有只读标志的属性处于“intdetermined”状态。 - DotnetDude

0
这可能与编程直接相关,但在您的情况下根本问题可能是由底层文件引起的。例如,我尝试删除一个目录时遇到了这个问题:
System.IO.Directory.Delete(someDirectory, true)

这会导致“拒绝访问路径'blah'”。为解决这个根本问题,我移除了子文件的只读属性,然后才能删除父目录。在我的情况下,我使用的是PowerShell,所以你可以使用.NET等效方法。
dir -r $PrePackageDirectory |% {if ($_.PSIsContainer -ne $true){$_.IsReadOnly = $false}}

0

我看到@DotnetDude在评论中说,那些人的解决方案不起作用。我认为这是因为他们没有提到需要使用File.SetAttributes方法来应用新属性。


-1
Shell("net share sharefolder=c:\sharefolder/GRANT:Everyone,FULL")


Shell("net share sharefolder= c:\sharefolder/G:Everyone:F /SPEC B")


Shell("Icacls C:\sharefolder/grant Everyone:F /inheritance:e /T")


Shell("attrib -r +s C:\\sharefolder\*.* /s /d", AppWinStyle.Hide)

这段代码对我有效.. 可以共享一个文件夹给每个人并赋予读写权限


@Kiquenet,“Shell”不是一个类,它是VB.NET函数。在C#中,您可以使用Process.Start()实现类似的行为(即启动另一个进程)。查阅“Process”和“ProcessStartInfo”类的文档以获取更多信息。但是,仅出于关闭只读属性的目的,正如最初的问题所述,我建议使用Mark Avenius的答案,而不是启动新进程。 - reirab

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接