在.NET中计算目录大小的最佳方法是什么?


78

我编写了以下例程来手动遍历目录并在C#/。NET中计算其大小:


protected static float CalculateFolderSize(string folder)
{
    float folderSize = 0.0f;
    try
    {
        //Checks if the path is valid or not
        if (!Directory.Exists(folder))
            return folderSize;
        else
        {
            try
            {
                foreach (string file in Directory.GetFiles(folder))
                {
                    if (File.Exists(file))
                    {
                        FileInfo finfo = new FileInfo(file);
                        folderSize += finfo.Length;
                    }
                }

                foreach (string dir in Directory.GetDirectories(folder))
                    folderSize += CalculateFolderSize(dir);
            }
            catch (NotSupportedException e)
            {
                Console.WriteLine("Unable to calculate folder size: {0}", e.Message);
            }
        }
    }
    catch (UnauthorizedAccessException e)
    {
        Console.WriteLine("Unable to calculate folder size: {0}", e.Message);
    }
    return folderSize;
}

我有一个针对大量文件夹重复运行此例程的应用程序。我想知道是否有更有效的方法来使用.NET计算文件夹的大小?我没有看到框架中的任何特定内容。我应该使用P / Invoke和Win32 API吗?在.NET中计算文件夹大小的最有效方法是什么?

Answers:


25

我不相信有Win32 API可以计算目录消耗的空间,尽管我对此有待纠正。如果有的话,我会假设资源管理器会使用它。如果您在资源管理器中获得了一个大目录的属性,则为您提供文件夹大小所花费的时间与其所包含的文件/子目录的数量成正比。

您的例程看起来相当整洁和简单。请记住,您是在计算文件长度的总和,而不是磁盘上实际消耗的空间。群集末尾的浪费空间,文件流等消耗的空间将被忽略。


6
此方法还忽略联结,硬链接,压缩和脱机存储。
2009年

EnumerateFiles也可能更可取,因为其中可能包含100k +个文件的文件夹。如上所述的连接点可能会导致无限递归IIRC。
只是另一个元编程人员,2013年


@DanielFisherlennybacon你知道它是如何实现的吗?不fso.GetFolder().Size循环递归如DirSize()确实或可能是Windows跟踪文件夹的大小?它返回什么样的“大小”
jfs

为什么不使用此“ GetDiskFreeSpaceEx”功能?链接:msdn.microsoft.com/en-us/library/windows/desktop/...
大利Nachum

65

不,这看起来是推荐的计算目录大小的方法,下面是relevent方法:

public static long DirSize(DirectoryInfo d) 
{    
    long size = 0;    
    // Add file sizes.
    FileInfo[] fis = d.GetFiles();
    foreach (FileInfo fi in fis) 
    {      
        size += fi.Length;    
    }
    // Add subdirectory sizes.
    DirectoryInfo[] dis = d.GetDirectories();
    foreach (DirectoryInfo di in dis) 
    {
        size += DirSize(di);   
    }
    return size;  
}

您将以root身份调用:

Console.WriteLine("The size is {0} bytes.", DirSize(new DirectoryInfo(targetFolder));

...targetFolder要计算的文件夹大小在哪里。


搜索“以下代码示例演示如何计算目录的大小;” 和上面的例子一样
mbrownnyc 2011年


1
@ladenedge更新了链接?那将带您到v2.0。答案链接是正确的。
kzfabi

顺便说一句:推荐的方式链接不再包含该实例。似乎MSDN已更新,而其中一个迷路了。
kzfabi

4
使用EnumerateFiles和EnumerateDirectories
Mauro Sampietro 2016年

33
DirectoryInfo dirInfo = new DirectoryInfo(@strDirPath);
long dirSize = await Task.Run(() => dirInfo.EnumerateFiles( "*", SearchOption.AllDirectories).Sum(file => file.Length));

这将获得“ UnauthorizedAccess异常”检查此内容: stackoverflow.com/questions/8877516/...
艾哈迈德·萨布里

@AhmedSabry:您从此错误中了解到什么。
Trikaldarshiii

它需要这条道路的许可
Ahmed Sabry

正是@AhmedSabry,这就是为什么这种1线好。如果所有权限都很好,那就很好。如果不是这样,它将失败,并且您不需要特定的自定义try..catch,您将知道遇到什么问题。
Ofer Zelig

如果子目录的完整路径太长
则会

15
public static long DirSize(DirectoryInfo dir)
{
    return dir.GetFiles().Sum(fi => fi.Length) +
           dir.GetDirectories().Sum(di => DirSize(di));
}

1
这种解决方案有几个问题,其中之一就是缺少NTFS(又称“交汇点”)和Unix-SMB共享上递归符号链接目录的终止。
mbx

1
我同意。还有什么?
Grozz 2013年

2
PathTooLongException(请参阅此博客文章),然后UnauthorizedAccessException想到从某些子目录()中读取的缺少凭据。一个不太重要的问题应该是在运行时拔下可移动驱动器(USB记忆棒等)。必须进行异常处理-如果求和结果应为任何值,则仅在本地返回0并记录错误。顺便说一句:在远程共享上应用它可能看起来像是DOS攻击。我确定我至少错过了另一种情况:-)
mbx 2013年

处理这些已知的异常时,StackOverflowException对于较大的驱动器,我仍然得到一个。
mbx 2013年

2
我认为在所有这些情况下都可以接受,因此默认行为很好。StackOverflowException是唯一应处理的问题,尽管我不认为没有递归符号链接也可以实现。
Grozz 2013年

14

真正的问题是 您打算将尺寸用于什么?

您的第一个问题是至少有四个“文件大小”定义:

  • “文件末尾”偏移量,即从文件开头到结尾必须跳过的字节数。
    换句话说,它是字节数文件中逻辑上(从使用角度来看)。

  • “有效数据长度”等于未实际存储的第一个字节的偏移量。
    它始终小于或等于“文件结尾”,并且是群集大小的倍数。
    例如,一个1 GB的文件可以具有1 MB的有效数据长度。如果您要求Windows读取前8 MB,它将读取前1 MB并假装其余数据在那里,将其返回为零。

  • 文件的“分配大小”。它始终大于或等于“文件末尾”。
    这是操作系统为文件分配的群集数乘以群集大小。
    与“文件结尾”大于“有效数据长度”的情况不同,多余的字节被视为文件数据的一部分,因此,如果您尝试读入,操作系统将不会用零填充缓冲区。文件末尾以外的分配区域。

  • 文件的“压缩大小”,仅对压缩(和稀疏?)文件有效。
    它等于集群的大小乘以卷上实际分配给该文件的集群的数量。
    对于非压缩和非稀疏文件,没有“压缩大小”的概念。您将改为使用“分配的大小”。

您的第二个问题是,类似的“文件”C:\Foo实际上可以具有多个数据流
此名称仅指默认流。文件可能具有备用流,例如C:\Foo:Bar,其大小甚至不会在资源管理器中显示!

您的第三个问题是“文件”可以有多个名称(“硬链接”)。
例如,C:\Windows\notepad.exe并且C:\Windows\System32\notepad.exe是两个名称相同文件。 可以使用任何名称打开文件的任何流。

您的第四个问题是“文件”(或目录)实际上甚至可能不是文件(或目录):
它可能是软链接到其他文件(“符号链接”或“重新解析点”)(或目录)。
该其他文件甚至可能不在同一驱动器上。它甚至可能指向网络上的某些内容,或者甚至可能是递归的!如果是递归的,尺寸应该是无穷大吗?

您的第五个问题是有一些使某些文件或目录看起来像实际文件或目录的“过滤器”驱动程序,即使它们并非如此。例如,可以使用称为ImageX的工具将Microsoft的WIM图像文件(已压缩)“挂载”在文件夹上,而不会像重分析点或链接。它们看起来就像目录-只是它们实际上不是目录,而且“大小”的概念对他们而言实际上没有任何意义。

您的第六个问题是每个文件都需要元数据。
例如,同一文件具有10个名称需要更多的元数据,这需要空间。如果文件名短,那么拥有10个名称可能和拥有1个名称一样便宜;如果文件名很长,那么拥有多个名称可能会占用更多的磁盘空间用于元数据。(具有多个流的同一个故事,等等。)
您也算这些吗?


2
我糊涂了。这不是一个答案,而是一个(相当长的)问题或多个问题。
Ofer Zelig

9
var size = new DirectoryInfo("E:\\").GetDirectorySize();

这是此扩展方法背后的代码

public static long GetDirectorySize(this System.IO.DirectoryInfo directoryInfo, bool recursive = true)
{
    var startDirectorySize = default(long);
    if (directoryInfo == null || !directoryInfo.Exists)
        return startDirectorySize; //Return 0 while Directory does not exist.

    //Add size of files in the Current Directory to main size.
    foreach (var fileInfo in directoryInfo.GetFiles())
        System.Threading.Interlocked.Add(ref startDirectorySize, fileInfo.Length);

    if (recursive) //Loop on Sub Direcotries in the Current Directory and Calculate it's files size.
        System.Threading.Tasks.Parallel.ForEach(directoryInfo.GetDirectories(), (subDirectory) =>
    System.Threading.Interlocked.Add(ref startDirectorySize, GetDirectorySize(subDirectory, recursive)));

    return startDirectorySize;  //Return full Size of this Directory.
}

1
在我的案例中,这段代码的运行速度比任何利用EnumerateFiles()的答案都要快。
6

6

看来,以下方法比递归函数执行任务的速度更快:

long size = 0;
DirectoryInfo dir = new DirectoryInfo(folder);
foreach (FileInfo fi in dir.GetFiles("*.*", SearchOption.AllDirectories))
{
   size += fi.Length;
}

一个简单的控制台应用程序测试表明,此循环比递归函数对文件进行汇总的速度更快,并提供相同的结果。您可能想使用LINQ方法(如Sum())来缩短此代码。


在我的包含目录的源代码和许多隐藏文件的测试中(svn目录),结果与文件系统资源管理器报告的结果不同。
DavidDoumèche2015年

1
一如既往地使用"*"而不是"*.*"用于没有扩展的文件
Bernhard

5

更多更快!添加COM参考“ Windows脚本宿主对象...”

public double GetWSHFolderSize(string Fldr)
    {
        //Reference "Windows Script Host Object Model" on the COM tab.
        IWshRuntimeLibrary.FileSystemObject FSO = new     IWshRuntimeLibrary.FileSystemObject();
        double FldrSize = (double)FSO.GetFolder(Fldr).Size;
        Marshal.FinalReleaseComObject(FSO);
        return FldrSize;
    }
private void button1_Click(object sender, EventArgs e)
        {
            string folderPath = @"C:\Windows";
        Stopwatch sWatch = new Stopwatch();

        sWatch.Start();
        double sizeOfDir = GetWSHFolderSize(folderPath);
        sWatch.Stop();
        MessageBox.Show("Directory size in Bytes : " + sizeOfDir + ", Time: " + sWatch.ElapsedMilliseconds.ToString());
          }

好的 但似乎它给出的是文件大小,而不是磁盘上的实际大小(我有一个大小为18154字节,磁盘上的大小为163840字节的情况!)
NGI

5

该解决方案效果很好。它正在收集所有子文件夹:

Directory.GetFiles(@"MainFolderPath", "*", SearchOption.AllDirectories).Sum(t => (new FileInfo(t).Length));

4

直到最近我一直在摆弄VS2008和LINQ,这种紧凑而简短的方法对我来说非常有用(示例在VB.NET中;当然需要LINQ / .NET FW 3.5+):

Dim size As Int64 = (From strFile In My.Computer.FileSystem.GetFiles(strFolder, _
              FileIO.SearchOption.SearchAllSubDirectories) _
              Select New System.IO.FileInfo(strFile).Length).Sum()

它简短,它搜索子目录,如果您知道LINQ语法,则很容易理解。您甚至可以使用.GetFiles函数的第三个参数指定通配符来搜索特定文件。

我不是C#专家,但是您可以通过这种方式在C#上添加My名称空间。

我认为这种获取文件夹大小的方法不仅比Hao的链接中描述的方法更短,更现代,而且基本上使用了最后描述的相同的FileInfo循环。


C#:返回Directory.GetFiles(目录,“ *”,SearchOption.AllDirectories).Sum(x =>(double)(new FileInfo(x).Length));
托马斯nn

3
这是不理想的,因为如果任何目录被拒绝访问,它将失败,并且它不能忽略此异常。
2013年

4

这是计算目录大小的最佳方法。仅有其他方法仍将使用递归,但使用起来会更容易并且不那么灵活。

float folderSize = 0.0f;
FileInfo[] files = Directory.GetFiles(folder, "*", SearchOption.AllDirectories);
foreach(FileInfo file in files) folderSize += file.Length;

4
正如乔还说过的那样,发布的代码不起作用。您必须使用DirectoryInfo而不是Directory来获取FileInfo数组。枚举SearchOption也不是SearchOptions
托尼

您可以使用Array.ConvertAll<string, FileInfo>(Directory.GetFiles(folder, "*", SearchOption.AllDirectories), x => new FileInfo(x));
PJRobot,

4

我使用相同的计数原理扩展了@Hao的答案,但支持更丰富的数据返回,因此您获得了N个级别的返回大小,递归大小,目录计数和递归目录计数。

public class DiskSizeUtil
{
    /// <summary>
    /// Calculate disk space usage under <paramref name="root"/>.  If <paramref name="levels"/> is provided, 
    /// then return subdirectory disk usages as well, up to <paramref name="levels"/> levels deep.
    /// If levels is not provided or is 0, return a list with a single element representing the
    /// directory specified by <paramref name="root"/>.
    /// </summary>
    /// <returns></returns>
    public static FolderSizeInfo GetDirectorySize(DirectoryInfo root, int levels = 0)
    {
        var currentDirectory = new FolderSizeInfo();

        // Add file sizes.
        FileInfo[] fis = root.GetFiles();
        currentDirectory.Size = 0;
        foreach (FileInfo fi in fis)
        {
            currentDirectory.Size += fi.Length;
        }

        // Add subdirectory sizes.
        DirectoryInfo[] dis = root.GetDirectories();

        currentDirectory.Path = root;
        currentDirectory.SizeWithChildren = currentDirectory.Size;
        currentDirectory.DirectoryCount = dis.Length;
        currentDirectory.DirectoryCountWithChildren = dis.Length;
        currentDirectory.FileCount = fis.Length;
        currentDirectory.FileCountWithChildren = fis.Length;

        if (levels >= 0)
            currentDirectory.Children = new List<FolderSizeInfo>();

        foreach (DirectoryInfo di in dis)
        {
            var dd = GetDirectorySize(di, levels - 1);
            if (levels >= 0)
                currentDirectory.Children.Add(dd);

            currentDirectory.SizeWithChildren += dd.SizeWithChildren;
            currentDirectory.DirectoryCountWithChildren += dd.DirectoryCountWithChildren;
            currentDirectory.FileCountWithChildren += dd.FileCountWithChildren;
        }

        return currentDirectory;
    }

    public class FolderSizeInfo
    {
        public DirectoryInfo Path { get; set; }
        public long SizeWithChildren { get; set; }
        public long Size { get; set; }
        public int DirectoryCount { get; set; }
        public int DirectoryCountWithChildren { get; set; }
        public int FileCount { get; set; }
        public int FileCountWithChildren { get; set; }
        public List<FolderSizeInfo> Children { get; set; }
    }
}

3
public static long GetDirSize(string path)
{
    try
    {
        return Directory.EnumerateFiles(path).Sum(x => new FileInfo(x).Length)  
            +
               Directory.EnumerateDirectories(path).Sum(x => GetDirSize(x));
    }
    catch
    {
        return 0L;
    }
}

2

就最好的算法而言,您可能是正确的。我建议您拆开递归函数并使用自己的堆栈(请记住,.Net 2.0+应用程序中的堆栈溢出是世界末日,无法捕获IIRC异常)。

最重要的是,如果您以任何形式的UI使用它,请将其放在工作线程上,该线程向UI线程发出更新信号。



2

Trikaldarshi单线解决方案的替代方案。(它避免构造FileInfo对象)

long sizeInBytes = Directory.EnumerateFiles("{path}","*", SearchOption.AllDirectories).Sum(fileInfo => new FileInfo(fileInfo).Length);

变量fileInfo的类型为字符串,而不是FileInfo。
user425678

2
Directory.GetFiles(@"C:\Users\AliBayat","*",SearchOption.AllDirectories)
.Select (d => new FileInfo(d))
.Select (d => new { Directory = d.DirectoryName,FileSize = d.Length} )
.ToLookup (d => d.Directory )
.Select (d => new { Directory = d.Key,TotalSizeInMB =Math.Round(d.Select (x =>x.FileSize)
.Sum () /Math.Pow(1024.0,2),2)})
.OrderByDescending (d => d.TotalSizeInMB).ToList();

调用GetFileswithSearchOption.AllDirectories返回subdirectories指定目录的所有目录中所有文件的全名。OS表示文件大小(以字节为单位)。您可以从文件的长度属性中检索文件的大小。用1024除以2的幂可以得到文件的大小(以兆字节为单位)。因为目录/文件夹可以包含许多文件,所以d.Select(x => x.FileSize)返回以兆字节为单位的文件大小的集合。最后致电Sum()查找指定目录中文件的总大小。

更新:filterMask =“ ”不适用于没有扩展名的文件


1

我想出的最快方法是将EnumerateFiles与SearchOption.AllDirectories一起使用。此方法还允许在浏览文件并计算大小时更新UI。长路径名不会引起任何问题,因为不会尝试为长路径名创建FileInfo或DirectoryInfo。在枚举文件时,即使文件名很长,只要起始目录名称不太长,EnumerateFiles返回的FileInfo都不会引起问题。UnauthorizedAccess仍然存在问题。

    private void DirectoryCountEnumTest(string sourceDirName)
    {
        // Get the subdirectories for the specified directory.
        long dataSize = 0;
        long fileCount = 0;
        string prevText = richTextBox1.Text;

        if (Directory.Exists(sourceDirName))
        {
            DirectoryInfo dir = new DirectoryInfo(sourceDirName);
            foreach (FileInfo file in dir.EnumerateFiles("*", SearchOption.AllDirectories))
            {
                fileCount++;
                try
                {
                    dataSize += file.Length;
                    richTextBox1.Text = prevText + ("\nCounting size: " + dataSize.ToString());
                }
                catch (Exception e)
                {
                    richTextBox1.AppendText("\n" + e.Message);
                }
            }
            richTextBox1.AppendText("\n files:" + fileCount.ToString());
        }
    }

1

此.NET Core命令行应用程序在这里计算给定路径的目录大小:

https://github.com/garethrbrown/folder-size

关键方法是这种递归检查子目录以得出总大小的方法。

private static long DirectorySize(SortDirection sortDirection, DirectoryInfo directoryInfo, DirectoryData directoryData)
{
        long directorySizeBytes = 0;

        // Add file sizes for current directory

        FileInfo[] fileInfos = directoryInfo.GetFiles();

        foreach (FileInfo fileInfo in fileInfos)
        {
            directorySizeBytes += fileInfo.Length;
        }

        directoryData.Name = directoryInfo.Name;

        directoryData.SizeBytes += directorySizeBytes;

        // Recursively add subdirectory sizes

        DirectoryInfo[] subDirectories = directoryInfo.GetDirectories();

        foreach (DirectoryInfo di in subDirectories)
        {
            var subDirectoryData = new DirectoryData(sortDirection);

            directoryData.DirectoryDatas.Add(subDirectoryData);

            directorySizeBytes += DirectorySize(sortDirection, di, subDirectoryData);
        }

        directoryData.SizeBytes = directorySizeBytes;

        return directorySizeBytes;
    }
}

1

Microsoft Docs计算目录大小的多线程示例,这样会更快

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      long totalSize = 0;

      String[] args = Environment.GetCommandLineArgs();
      if (args.Length == 1) {
         Console.WriteLine("There are no command line arguments.");
         return;
      }
      if (! Directory.Exists(args[1])) {
         Console.WriteLine("The directory does not exist.");
         return;
      }

      String[] files = Directory.GetFiles(args[1]);
      Parallel.For(0, files.Length,
                   index => { FileInfo fi = new FileInfo(files[index]);
                              long size = fi.Length;
                              Interlocked.Add(ref totalSize, size);
                   } );
      Console.WriteLine("Directory '{0}':", args[1]);
      Console.WriteLine("{0:N0} files, {1:N0} bytes", files.Length, totalSize);
   }
}
// The example displaysoutput like the following:
//       Directory 'c:\windows\':
//       32 files, 6,587,222 bytes

本示例仅计算当前文件夹中的文件,因此,如果要递归计算所有文件,则可以更改

String[] files = Directory.GetFiles(args[1]);

String[] files = Directory.GetFiles(args[1], "*", SearchOption.AllDirectories);


0

我尝试更改示例(Alexandre Pepin和hao的答案)

照原样

    private long GetDirectorySize(string dirPath)
    {
        if (Directory.Exists(dirPath) == false)
        {
            return 0;
        }

        DirectoryInfo dirInfo = new DirectoryInfo(dirPath);

        long size = 0;

        // Add file sizes.
        FileInfo[] fis = dirInfo.GetFiles();
        foreach (FileInfo fi in fis)
        {
            size += fi.Length;
        }

        // Add subdirectory sizes.
        DirectoryInfo[] dis = dirInfo.GetDirectories();
        foreach (DirectoryInfo di in dis)
        {
            size += GetDirectorySize(di.FullName);
        }

        return size;
    }

成为

    private long GetDirectorySize2(string dirPath)
    {
        if (Directory.Exists(dirPath) == false)
        {
            return 0;
        }

        DirectoryInfo dirInfo = new DirectoryInfo(dirPath);

        long size = 0;

        // Add file sizes.
        IEnumerable<FileInfo> fis = dirInfo.EnumerateFiles("*.*", SearchOption.AllDirectories);
        foreach (FileInfo fi in fis)
        {
            size += fi.Length;
        }

        return size;
    }

最后你可以检查结果

        // ---------------------------------------------
        // size of directory
        using System.IO;

        string log1Path = @"D:\SampleDirPath1";
        string log2Path = @"D:\SampleDirPath2";
        string log1DirName = Path.GetDirectoryName(log1Path);
        string log2DirName = Path.GetDirectoryName(log2Path);
        long log1Size = GetDirectorySize(log1Path);
        long log2Size = GetDirectorySize(log2Path);
        long log1Size2 = GetDirectorySize2(log1Path);
        long log2Size2 = GetDirectorySize2(log2Path);

        Console.WriteLine($@"{log1DirName} Size: {SizeSuffix(log1Size)}, {SizeSuffix(log1Size2)}
        {log2DirName} Size: {SizeSuffix(log2Size)}, {SizeSuffix(log2Size2)}");

这是SizeSuffix函数

    private static readonly string[] SizeSuffixes =
               { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };

    /// <summary>
    /// Size Display
    /// </summary>
    /// <param name="value">bytes 數值</param>
    /// <param name="decimalPlaces">小數位數</param>
    /// <returns></returns>
    public static string SizeSuffix(Int64 value, int decimalPlaces = 2)
    {
        if (decimalPlaces < 0) { throw new ArgumentOutOfRangeException("decimalPlaces"); }
        if (value < 0) { return "-" + SizeSuffix(-value); }
        if (value == 0) { return string.Format("{0:n" + decimalPlaces + "} bytes", 0); }

        // mag is 0 for bytes, 1 for KB, 2, for MB, etc.
        int mag = (int)Math.Log(value, 1024);

        // 1L << (mag * 10) == 2 ^ (10 * mag) 
        // [i.e. the number of bytes in the unit corresponding to mag]
        decimal adjustedSize = (decimal)value / (1L << (mag * 10));

        // make adjustment when the value is large enough that
        // it would round up to 1000 or more
        if (Math.Round(adjustedSize, decimalPlaces) >= 1000)
        {
            mag += 1;
            adjustedSize /= 1024;
        }

        return string.Format("{0:n" + decimalPlaces + "} {1}",
            adjustedSize,
            SizeSuffixes[mag]);
    }

-3

我知道这不是一个.net解决方案,但是无论如何它都来了。也许对于拥有Windows 10并想要更快解决方案的人来说很方便。例如,如果您在命令提示符下运行此命令或按winKey + R

bash -c "du -sh /mnt/c/Users/; sleep 5"    

sleep 5是让你有时间看到的结果,窗户没有关闭

在我的电脑上显示:

在此处输入图片说明

最后请注意,它显示的是85G(85 GB)。与使用.Net相比,它超级快。如果要更准确地查看尺寸,请删除h代表人类可读的尺寸。

因此,只要执行类似这样的操作,Processes.Start("bash",... arguments)那不是确切的代码,但您会明白的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.