Come posso ottenere una dimensione di file leggibile dall'uomo in abbreviazione di byte usando .NET?


Risposte:


353

Questo non è il modo più efficiente per farlo, ma è più facile da leggere se non si ha familiarità con i log log e dovrebbe essere abbastanza veloce per la maggior parte degli scenari.

string[] sizes = { "B", "KB", "MB", "GB", "TB" };
double len = new FileInfo(filename).Length;
int order = 0;
while (len >= 1024 && order < sizes.Length - 1) {
    order++;
    len = len/1024;
}

// Adjust the format string to your preferences. For example "{0:0.#}{1}" would
// show a single decimal place, and no space.
string result = String.Format("{0:0.##} {1}", len, sizes[order]);

12
Credo che potresti usare Math.Log per determinare l'ordine invece di usare un ciclo while.
Francois Botha,

12
Inoltre, KB è di 1000 byte. 1024 byte è KiB .
Constantin,

13
@Constantin bene che dipende dal sistema operativo? Windows conta ancora 1024 byte come 1 KB e 1 MB = 1024 KB, Personalmente voglio buttare il KiB fuori dalla finestra e contare tutto usando 1024? ...
Peter

4
@Petoj non dipende dal sistema operativo, la definizione è indipendente dal sistema operativo. Da Wikipedia:The unit was established by the International Electrotechnical Commission (IEC) in 1998 and has been accepted for use by all major standards organizations
ANeves

3
Preferisco questo codice poiché sembra funzionare più velocemente ma l'ho modificato leggermente per consentire numeri diversi di cifre decimali. I numeri più piccoli mostrano meglio 2 cifre decimali, ad esempio 1,38 MB, mentre i numeri più grandi richiedono meno decimali, ad esempio 246 k o 23,5 KB:
Myke Black

321

utilizzando Log per risolvere il problema ....

static String BytesToString(long byteCount)
{
    string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" }; //Longs run out around EB
    if (byteCount == 0)
        return "0" + suf[0];
    long bytes = Math.Abs(byteCount);
    int place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
    double num = Math.Round(bytes / Math.Pow(1024, place), 1);
    return (Math.Sign(byteCount) * num).ToString() + suf[place];
}

Anche in c #, ma dovrebbe essere un attimo da convertire. Inoltre ho arrotondato al primo decimale per leggibilità.

Fondamentalmente Determina il numero di posizioni decimali in Base 1024 e poi dividi per 1024 ^ decimali.

E alcuni esempi di utilizzo e output:

Console.WriteLine(BytesToString(9223372036854775807));  //Results in 8EB
Console.WriteLine(BytesToString(0));                    //Results in 0B
Console.WriteLine(BytesToString(1024));                 //Results in 1KB
Console.WriteLine(BytesToString(2000000));              //Results in 1.9MB
Console.WriteLine(BytesToString(-9023372036854775807)); //Results in -7.8EB

Modifica: è stato sottolineato che mi mancava un pavimento di matematica, quindi l'ho incorporato. (Convert.ToInt32 utilizza l'arrotondamento, non il troncamento, ecco perché è necessario il piano.) Grazie per la cattura.

Edit2: c'erano un paio di commenti su dimensioni negative e dimensioni di 0 byte, quindi ho aggiornato per gestire quei 2 casi.


7
Voglio avvertire che sebbene questa risposta sia davvero una breve parte di codice, non è la più ottimizzata. Mi piacerebbe dare un'occhiata al metodo pubblicato da @humbads. Ho eseguito il microtest inviando 10.000.000 di file generati casualmente attraverso entrambi i metodi e questo porta a numeri che il suo metodo è ~ 30% più veloce. Ho fatto comunque qualche ulteriore pulizia del suo metodo (incarichi non necessari e casting). Inoltre ho eseguito un test con dimensioni negative (quando si confrontano i file) mentre il metodo degli humbad elabora in modo impeccabile questo metodo Log genererà un'eccezione!
IvanL

1
Sì, dovresti aggiungere Math.Abs ​​per dimensioni negative. Inoltre, il codice non gestisce il caso se la dimensione è esattamente 0.
dasheddot

Math.Abs, Math.Floor, Math.Log, Conversione in numero intero, Math.Round, Math.Pow, Math.Sign, Aggiunta, Moltiplicazione, Divisione? Queste tonnellate di matematica non sono state solo un enorme picco sul processore? Questo è probabilmente più lento del codice @humbads
Jayson Ragasa il

Non riesce double.MaxValue(posto = 102)
BrunoLM il

Funziona alla grande! Per imitare il modo in cui funziona Windows (almeno sul mio Windows 7 ultimate), sostituisci Math.Round con Math.Ceiling. Grazie ancora. Mi piace questa soluzione.
H_He

101

Una versione testata e notevolmente ottimizzata della funzione richiesta è pubblicata qui:

Dimensione file leggibile nell'uomo C # - Funzione ottimizzata

Codice sorgente:

// Returns the human-readable file size for an arbitrary, 64-bit file size 
// The default format is "0.### XB", e.g. "4.2 KB" or "1.434 GB"
public string GetBytesReadable(long i)
{
    // Get absolute value
    long absolute_i = (i < 0 ? -i : i);
    // Determine the suffix and readable value
    string suffix;
    double readable;
    if (absolute_i >= 0x1000000000000000) // Exabyte
    {
        suffix = "EB";
        readable = (i >> 50);
    }
    else if (absolute_i >= 0x4000000000000) // Petabyte
    {
        suffix = "PB";
        readable = (i >> 40);
    }
    else if (absolute_i >= 0x10000000000) // Terabyte
    {
        suffix = "TB";
        readable = (i >> 30);
    }
    else if (absolute_i >= 0x40000000) // Gigabyte
    {
        suffix = "GB";
        readable = (i >> 20);
    }
    else if (absolute_i >= 0x100000) // Megabyte
    {
        suffix = "MB";
        readable = (i >> 10);
    }
    else if (absolute_i >= 0x400) // Kilobyte
    {
        suffix = "KB";
        readable = i;
    }
    else
    {
        return i.ToString("0 B"); // Byte
    }
    // Divide by 1024 to get fractional value
    readable = (readable / 1024);
    // Return formatted number with suffix
    return readable.ToString("0.### ") + suffix;
}

1
+1! Più semplice e diretto! Rende il processore in grado di fare matematica facilmente e velocemente!
Jayson Ragasa,

Cordiali saluti, non si utilizza il valore in double readable = (i < 0 ? -i : i);nessun luogo quindi rimuoverlo. un'altra cosa, il cast è redaundat
Royi Namir il

Ho rimosso il cast, aggiunto commenti e risolto un problema con il segno negativo.
humbads

Bella risposta. Grazie, perché non usare solo Math.Abs?
kspearrin,

1
(i <0? -i: i) è circa il 15% più veloce di Math.Abs. Per un milione di chiamate, Math.Abs ​​è più lento di 0,5 millisecondi sulla mia macchina - 3,2 ms contro 3,7 ms.
humbads

72
[DllImport ( "Shlwapi.dll", CharSet = CharSet.Auto )]
public static extern long StrFormatByteSize ( 
        long fileSize
        , [MarshalAs ( UnmanagedType.LPTStr )] StringBuilder buffer
        , int bufferSize );


/// <summary>
/// Converts a numeric value into a string that represents the number expressed as a size value in bytes, kilobytes, megabytes, or gigabytes, depending on the size.
/// </summary>
/// <param name="filelength">The numeric value to be converted.</param>
/// <returns>the converted string</returns>
public static string StrFormatByteSize (long filesize) {
     StringBuilder sb = new StringBuilder( 11 );
     StrFormatByteSize( filesize, sb, sb.Capacity );
     return sb.ToString();
}

Da: http://www.pinvoke.net/default.aspx/shlwapi/StrFormatByteSize.html


36
Potrei essere un noob, ma usare un cannone gigantesco come il pinvoke per uccidere quell'anatra è un grosso abuso.
Bart,

27
È questo che utilizza Explorer? In tal caso, quindi magnificamente utile per consentire alle persone di abbinare le dimensioni del file che mostri loro con ciò che Explorer mostra.
Andrew Backer,

8
E uno che non reinventa la ruota
Matthew Lock,

11 caratteri non sono un limite costante e un po 'basso per quello? Voglio dire, altre lingue potrebbero usare più caratteri per l'acronimo di byte size o altri stili di formattazione.
Ray,

1
@Bart ci vuole un po 'perché noobs apprenda la saggezza in questo: "Dovremmo dimenticare piccole efficienze, diciamo circa il 97% delle volte: l'ottimizzazione prematura è la radice di tutti i mali" ubiquity.acm.org/article.cfm? id = 1513451
Matthew Lock,

22

Un altro modo per skin, senza alcun tipo di loop e con supporto di dimensioni negative (ha senso per cose come i delta di dimensioni del file):

public static class Format
{
    static string[] sizeSuffixes = {
        "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };

    public static string ByteSize(long size)
    {
        Debug.Assert(sizeSuffixes.Length > 0);

        const string formatTemplate = "{0}{1:0.#} {2}";

        if (size == 0)
        {
            return string.Format(formatTemplate, null, 0, sizeSuffixes[0]);
        }

        var absSize = Math.Abs((double)size);
        var fpPower = Math.Log(absSize, 1000);
        var intPower = (int)fpPower;
        var iUnit = intPower >= sizeSuffixes.Length
            ? sizeSuffixes.Length - 1
            : intPower;
        var normSize = absSize / Math.Pow(1000, iUnit);

        return string.Format(
            formatTemplate,
            size < 0 ? "-" : null, normSize, sizeSuffixes[iUnit]);
    }
}

Ed ecco la suite di test:

[TestFixture] public class ByteSize
{
    [TestCase(0, Result="0 B")]
    [TestCase(1, Result = "1 B")]
    [TestCase(1000, Result = "1 KB")]
    [TestCase(1500000, Result = "1.5 MB")]
    [TestCase(-1000, Result = "-1 KB")]
    [TestCase(int.MaxValue, Result = "2.1 GB")]
    [TestCase(int.MinValue, Result = "-2.1 GB")]
    [TestCase(long.MaxValue, Result = "9.2 EB")]
    [TestCase(long.MinValue, Result = "-9.2 EB")]
    public string Format_byte_size(long size)
    {
        return Format.ByteSize(size);
    }
}

19

Checkout la ByteSize biblioteca. È System.TimeSpanper i byte!

Gestisce la conversione e la formattazione per te.

var maxFileSize = ByteSize.FromKiloBytes(10);
maxFileSize.Bytes;
maxFileSize.MegaBytes;
maxFileSize.GigaBytes;

Fa anche la rappresentazione e l'analisi delle stringhe.

// ToString
ByteSize.FromKiloBytes(1024).ToString(); // 1 MB
ByteSize.FromGigabytes(.5).ToString();   // 512 MB
ByteSize.FromGigabytes(1024).ToString(); // 1 TB

// Parsing
ByteSize.Parse("5b");
ByteSize.Parse("1.55B");

5
È la tua biblioteca personale, no?
Larsenal,

10
Nessuna vergogna in una comoda libreria come questa. :-)
Larsenal

13

Mi piace usare il seguente metodo (supporta fino a terabyte, che è sufficiente per la maggior parte dei casi, ma può essere facilmente esteso):

private string GetSizeString(long length)
{
    long B = 0, KB = 1024, MB = KB * 1024, GB = MB * 1024, TB = GB * 1024;
    double size = length;
    string suffix = nameof(B);

    if (length >= TB) {
        size = Math.Round((double)length / TB, 2);
        suffix = nameof(TB);
    }
    else if (length >= GB) {
        size = Math.Round((double)length / GB, 2);
        suffix = nameof(GB);
    }
    else if (length >= MB) {
        size = Math.Round((double)length / MB, 2);
        suffix = nameof(MB);
    }
    else if (length >= KB) {
        size = Math.Round((double)length / KB, 2);
        suffix = nameof(KB);
    }

    return $"{size} {suffix}";
}

Tieni presente che questo è scritto per C # 6.0 (2015), quindi potrebbe essere necessario apportare alcune modifiche alle versioni precedenti.


11
int size = new FileInfo( filePath ).Length / 1024;
string humanKBSize = string.Format( "{0} KB", size );
string humanMBSize = string.Format( "{0} MB", size / 1024 );
string humanGBSize = string.Format( "{0} GB", size / 1024 / 1024 );

Buona risposta. Dovrebbe esserci un problema quando la dimensione del file è troppo piccola, nel qual caso / 1024 restituisce 0. È possibile utilizzare un tipo frazionario e chiamare Math.Ceilingo qualcosa del genere.
nawfal,

10

Ecco una risposta concisa che determina automaticamente l'unità.

public static string ToBytesCount(this long bytes)
{
    int unit = 1024;
    string unitStr = "b";
    if (bytes < unit) return string.Format("{0} {1}", bytes, unitStr);
    else unitStr = unitStr.ToUpper();
    int exp = (int)(Math.Log(bytes) / Math.Log(unit));
    return string.Format("{0:##.##} {1}{2}", bytes / Math.Pow(unit, exp), "KMGTPEZY"[exp - 1], unitStr);
}

"b" sta per bit, "B" sta per Byte e "KMGTPEZY" sono rispettivamente per chilo, mega, giga, tera, peta, exa, zetta e yotta

È possibile espanderlo per tenere conto di ISO / IEC80000 :

public static string ToBytesCount(this long bytes, bool isISO = true)
{
    int unit = 1024;
    string unitStr = "b";
    if (!isISO) unit = 1000;
    if (bytes < unit) return string.Format("{0} {1}", bytes, unitStr);
    else unitStr = unitStr.ToUpper();
    if (isISO) unitStr = "i" + unitStr;
    int exp = (int)(Math.Log(bytes) / Math.Log(unit));
    return string.Format("{0:##.##} {1}{2}", bytes / Math.Pow(unit, exp), "KMGTPEZY"[exp - 1], unitStr);
}

1
per tutti chiedersi perché c'è un oKMGTPE dopo: il suo francese ( byteè octetin francese). Per qualsiasi altra lingua basta sostituire il ocon ilb
Max R.

7
string[] suffixes = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
int s = 0;
long size = fileInfo.Length;

while (size >= 1024)
{
    s++;
    size /= 1024;
}

string humanReadable = String.Format("{0} {1}", size, suffixes[s]);

Dovresti controllare: while (size> = 1024 && <suffixes.Length).
TcK,

no ... un numero intero con segno a 64 bit non può andare oltre lo ZB ... che rappresenta i numeri 2 ^ 70.
bobwienholt,

7
Quindi perché mettere in YB?
configuratore

Questa risposta mi piace da sola, ma tutti qui hanno soluzioni davvero inefficienti, dovresti usare lo spostamento "size = size >> 10" è molto più veloce della divisione ... e penso che sia bello avere il c'è un altro identificatore greco, perché nel prossimo futuro, una funzione DLR posabile non avrebbe bisogno della "dimensione lunga .." potresti essere su una CPU vettoriale a 128 bit o qualcosa che può contenere ZB e più grandi;)
RandomNickName42

4
Bitshifting era più efficiente della divisione ai tempi della codifica C sul metallo. Hai fatto un test perf in .NET per vedere se il bitshift è davvero più efficiente? Non molto tempo fa, ho esaminato lo stato di xor-swap e ho scoperto che in .NET era effettivamente più lento rispetto a una variabile temp.
Pete,

7

Se stai cercando di far corrispondere le dimensioni come mostrato nella vista dei dettagli di Windows Explorer, questo è il codice che desideri:

[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
private static extern long StrFormatKBSize(
    long qdw,
    [MarshalAs(UnmanagedType.LPTStr)] StringBuilder pszBuf,
    int cchBuf);

public static string BytesToString(long byteCount)
{
    var sb = new StringBuilder(32);
    StrFormatKBSize(byteCount, sb, sb.Capacity);
    return sb.ToString();
}

Questo non solo corrisponderà esattamente a Explorer, ma fornirà anche le stringhe tradotte per te e corrisponderà alle differenze nelle versioni di Windows (ad esempio in Win10, K = 1000 rispetto alle versioni precedenti K = 1024).


Questo codice non viene compilato, è necessario specificare la dll da cui proviene la funzione. Quindi il prototipo dell'intera funzione suona così: [DllImport ("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern long StrFormatKBSize (long qdw, [MarshalAs (UnmanagedType.LPTStr)] StringBuilder pszBuf, int cchBuf ); Vorrei essere il primo a favorire questa soluzione. Perché reinventare la ruota se la ruota era già stata inventata? Questo è l'approccio tipico di tutti i programmatori C #, ma sfortunatamente C # non raggiunge tutti gli obiettivi raggiunti da C ++.
TarmoPikaro

E un altro bugfix: Int64.MaxValue raggiunge 9.223.372.036.854.775.807, che richiede di allocare una dimensione del buffer di 25+ - l'ho arrotondato a 32 per ogni evenienza (non 11 come nel codice demo sopra).
TarmoPikaro

Grazie @TarmoPikaro. Quando ho copiato dal mio codice di lavoro, ho perso il DllImport. Aumentata anche la dimensione del buffer secondo la tua raccomandazione. Buona pesca!
Metalogic,

approccio impressionante
tbhaxor

Questo mostra solo unità KB. L'idea è di mostrare l'unità più grande in base al valore.
jstuardo,

5

Miscela di tutte le soluzioni :-)

    /// <summary>
    /// Converts a numeric value into a string that represents the number expressed as a size value in bytes,
    /// kilobytes, megabytes, or gigabytes, depending on the size.
    /// </summary>
    /// <param name="fileSize">The numeric value to be converted.</param>
    /// <returns>The converted string.</returns>
    public static string FormatByteSize(double fileSize)
    {
        FileSizeUnit unit = FileSizeUnit.B;
        while (fileSize >= 1024 && unit < FileSizeUnit.YB)
        {
            fileSize = fileSize / 1024;
            unit++;
        }
        return string.Format("{0:0.##} {1}", fileSize, unit);
    }

    /// <summary>
    /// Converts a numeric value into a string that represents the number expressed as a size value in bytes,
    /// kilobytes, megabytes, or gigabytes, depending on the size.
    /// </summary>
    /// <param name="fileInfo"></param>
    /// <returns>The converted string.</returns>
    public static string FormatByteSize(FileInfo fileInfo)
    {
        return FormatByteSize(fileInfo.Length);
    }
}

public enum FileSizeUnit : byte
{
    B,
    KB,
    MB,
    GB,
    TB,
    PB,
    EB,
    ZB,
    YB
}


3

Come la soluzione di @ NET3. Utilizzare MAIUSC anziché divisione per testare l'intervallo di bytes, poiché la divisione richiede più costi della CPU.

private static readonly string[] UNITS = new string[] { "B", "KB", "MB", "GB", "TB", "PB", "EB" };

public static string FormatSize(ulong bytes)
{
    int c = 0;
    for (c = 0; c < UNITS.Length; c++)
    {
        ulong m = (ulong)1 << ((c + 1) * 10);
        if (bytes < m)
            break;
    }

    double n = bytes / (double)((ulong)1 << (c * 10));
    return string.Format("{0:0.##} {1}", n, UNITS[c]);
}


2

Che ne dici di una ricorsione:

private static string ReturnSize(double size, string sizeLabel)
{
  if (size > 1024)
  {
    if (sizeLabel.Length == 0)
      return ReturnSize(size / 1024, "KB");
    else if (sizeLabel == "KB")
      return ReturnSize(size / 1024, "MB");
    else if (sizeLabel == "MB")
      return ReturnSize(size / 1024, "GB");
    else if (sizeLabel == "GB")
      return ReturnSize(size / 1024, "TB");
    else
      return ReturnSize(size / 1024, "PB");
  }
  else
  {
    if (sizeLabel.Length > 0)
      return string.Concat(size.ToString("0.00"), sizeLabel);
    else
      return string.Concat(size.ToString("0.00"), "Bytes");
  }
}

Quindi lo chiami:

return ReturnSize(size, string.Empty);

Buono ma mangia CPU
kamalpreet

1

I miei 2 centesimi:

  • Il prefisso per kilobyte è kB (K minuscola)
  • Poiché queste funzioni sono a scopo di presentazione, è necessario fornire una cultura, ad esempio: string.Format(CultureInfo.CurrentCulture, "{0:0.##} {1}", fileSize, unit);
  • A seconda del contesto, un kilobyte può essere di 1000 o 1024 byte . Lo stesso vale per MB, GB, ecc.

3
Un kilobyte significa 1000 byte ( wolframalpha.com/input/?i=kilobyte ), non dipende dal contesto. E ' storicamente dipendeva contesto, come wikipedia dice, ed è stato de jure cambiato nel 1998 e, di fatto, il cambiamento è iniziato intorno al 2005 quando terabyte hard disk portato all'attenzione del pubblico. Il termine per 1024 byte è kibibyte. Il codice che li cambia in base alla cultura sta producendo informazioni errate.
Superbo

1

Un altro approccio, per quello che vale. Mi è piaciuta la soluzione ottimizzata di @humbads di cui sopra, quindi ho copiato il principio, ma l'ho implementato in modo leggermente diverso.

Suppongo che sia discutibile se debba essere un metodo di estensione (dal momento che non tutti i long sono necessariamente dimensioni di byte), ma mi piacciono, ed è da qualche parte che posso trovare il metodo quando ne avrò bisogno in seguito!

Per quanto riguarda le unità, non credo di aver mai detto "Kibibyte" o "Mebibyte" nella mia vita, e mentre sono scettico su tali standard forzati piuttosto che evoluti, suppongo che eviterà confusione a lungo termine .

public static class LongExtensions
{
    private static readonly long[] numberOfBytesInUnit;
    private static readonly Func<long, string>[] bytesToUnitConverters;

    static LongExtensions()
    {
        numberOfBytesInUnit = new long[6]    
        {
            1L << 10,    // Bytes in a Kibibyte
            1L << 20,    // Bytes in a Mebibyte
            1L << 30,    // Bytes in a Gibibyte
            1L << 40,    // Bytes in a Tebibyte
            1L << 50,    // Bytes in a Pebibyte
            1L << 60     // Bytes in a Exbibyte
        };

        // Shift the long (integer) down to 1024 times its number of units, convert to a double (real number), 
        // then divide to get the final number of units (units will be in the range 1 to 1023.999)
        Func<long, int, string> FormatAsProportionOfUnit = (bytes, shift) => (((double)(bytes >> shift)) / 1024).ToString("0.###");

        bytesToUnitConverters = new Func<long,string>[7]
        {
            bytes => bytes.ToString() + " B",
            bytes => FormatAsProportionOfUnit(bytes, 0) + " KiB",
            bytes => FormatAsProportionOfUnit(bytes, 10) + " MiB",
            bytes => FormatAsProportionOfUnit(bytes, 20) + " GiB",
            bytes => FormatAsProportionOfUnit(bytes, 30) + " TiB",
            bytes => FormatAsProportionOfUnit(bytes, 40) + " PiB",
            bytes => FormatAsProportionOfUnit(bytes, 50) + " EiB",
        };
    }

    public static string ToReadableByteSizeString(this long bytes)
    {
        if (bytes < 0)
            return "-" + Math.Abs(bytes).ToReadableByteSizeString();

        int counter = 0;
        while (counter < numberOfBytesInUnit.Length)
        {
            if (bytes < numberOfBytesInUnit[counter])
                return bytesToUnitConverters[counter](bytes);
            counter++;
        }
        return bytesToUnitConverters[counter](bytes);
    }
}

0

Uso il seguente metodo di estensione Long per convertire una stringa di dimensioni leggibili dall'uomo. Questo metodo è l'implementazione C # della soluzione Java di questa stessa domanda pubblicata su StackTranslate.it, qui .

/// <summary>
/// Convert a byte count into a human readable size string.
/// </summary>
/// <param name="bytes">The byte count.</param>
/// <param name="si">Whether or not to use SI units.</param>
/// <returns>A human readable size string.</returns>
public static string ToHumanReadableByteCount(
    this long bytes
    , bool si
)
{
    var unit = si
        ? 1000
        : 1024;

    if (bytes < unit)
    {
        return $"{bytes} B";
    }

    var exp = (int) (Math.Log(bytes) / Math.Log(unit));

    return $"{bytes / Math.Pow(unit, exp):F2} " +
           $"{(si ? "kMGTPE" : "KMGTPE")[exp - 1] + (si ? string.Empty : "i")}B";
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.