۳۰ شهریور ۱۴۰۳

Techboy

اخبار و اطلاعات روز تکنولوژی

چگونه رشته ها را در سی شارپ فشرده و از حالت فشرده خارج کنیم

از روش‌های فشرده‌سازی GZip و Brotli برای کاهش اندازه داده‌های رشته‌ای و بهبود عملکرد در برنامه‌های NET Core خود استفاده کنید.

از روش‌های فشرده‌سازی GZip و Brotli برای کاهش اندازه داده‌های رشته‌ای و بهبود عملکرد در برنامه‌های NET Core خود استفاده کنید.

هنگام توسعه برنامه‌ها، اغلب باید با رشته‌ها سروکار داشته باشید. و از آنجایی که اشیاء رشته از نظر کارایی پرهزینه هستند، اغلب می خواهید محتوای رشته خود را فشرده کنید، به عنوان مثال، داده های داخل اشیاء رشته خود را برای کاهش بار. چندین کتابخانه برای انجام این کار موجود است اما دو تکنیک محبوب GZip و Brotli هستند.

در این مقاله نحوه فشرده‌سازی و از حالت فشرده‌سازی رشته‌ها را با استفاده از الگوریتم‌های GZip و Brotli در سی شارپ مورد بحث قرار خواهیم داد. برای کار با نمونه کدهای ارائه شده در اینجا، باید Visual Studio 2022 را در سیستم خود نصب کنید. اگر قبلاً نسخه‌ای ندارید، می‌توانید Visual Studio 2022 را از اینجا بارگیری کنید.

یک پروژه برنامه کاربردی کنسول در Visual Studio 2022 ایجاد کنید

ابتدا، اجازه دهید یک پروژه برنامه کاربردی کنسول NET Core در ویژوال استودیو ایجاد کنیم. با فرض اینکه Visual Studio 2022 در سیستم شما نصب شده است، مراحل ذکر شده در زیر را برای ایجاد یک پروژه برنامه کاربردی کنسول NET Core جدید دنبال کنید.

  1. Visual Studio IDE را راه اندازی کنید.
  2. روی “ایجاد پروژه جدید” کلیک کنید.
  3. در پنجره “ایجاد یک پروژه جدید”، “Console App” را از لیست الگوهای نمایش داده شده انتخاب کنید.
  4. بعدی را کلیک کنید.
  5. در پنجره “پیکربندی پروژه جدید خود” که در ادامه نشان داده شده است، نام و مکان پروژه جدید را مشخص کنید.
  6. در پنجره “اطلاعات اضافی”، .NET 6.0 را به عنوان زمان اجرا انتخاب کنید و روی Next کلیک کنید.
  7. روی ایجاد کلیک کنید.

از این پروژه برای نشان دادن فشرده‌سازی و رفع فشرده‌سازی رشته در زیر استفاده می‌کنیم. اما ابتدا یک بسته محک به نام BenchmarkDotNet نصب می کنیم که به ما امکان می دهد مزایایی را که از فشرده سازی به دست می آوریم اندازه گیری کنیم.

بسته BenchmarkDotNet NuGet را نصب کنید

کد محک برای درک عملکرد برنامه شما ضروری است. در این مقاله از BenchmarkDotNet برای ردیابی عملکرد روش ها استفاده خواهیم کرد. اگر با BenchmarkDotNet آشنایی ندارید، پیشنهاد می کنم ابتدا این مقاله را بخوانید.

برای کار با BenchmarkDotNet باید بسته BenchmarkDotNet را نصب کنید. می توانید این کار را از طریق NuGet Package Manager در داخل Visual Studio 2022 یا با اجرای دستور زیر در کنسول NuGet Package Manager انجام دهید:

Install-Package BenchmarkDotNet

فضای نام System.IO.Compression در سی شارپ

فضای نام System.IO.Compression شامل روش هایی برای فشرده سازی فایل ها و رشته ها است. این شامل دو الگوریتم فشرده سازی است: GZip و Brotli. در این بخش که در ادامه خواهد آمد، بررسی خواهیم کرد که چگونه می‌توانیم داده‌های رشته را با استفاده از الگوریتم‌های فشرده‌سازی GZip و Brotli در سی شارپ فشرده و از حالت فشرده خارج کنیم.

Deno 1.33 پایگاه داده داخلی با ارزش کلیدی را معرفی می کند

ما از متن زیر در مثال‌های زیر استفاده خواهیم کرد:

string originalString = "To work with BenchmarkDotNet you must install the BenchmarkDotNet package. " +
"You can do this either via the NuGet Package Manager inside the Visual Studio 2019 IDE, " +
"or by executing the Install-Package BenchmarkDotNet command at the NuGet Package Manager Console";

داده ها را با استفاده از GZip در سی شارپ فشرده و از حالت فشرده خارج کنید

قطعه کد زیر نشان می دهد که چگونه می توانید داده ها را با استفاده از کلاس GZipStream در C# فشرده کنید. توجه داشته باشید که پارامتر متد Compress یک آرایه بایت است.

public static byte[] Compress(byte[] bytes)
        {
            using (var memoryStream = new MemoryStream())
            {
                using (var gzipStream = new GZipStream(memoryStream, CompressionLevel.Optimal))
                {
                    gzipStream.Write(bytes, 0, bytes.Length);
                }
                return memoryStream.ToArray();
            }
        }

برای فشرده سازی داده هایی که با استفاده از الگوریتم GZip فشرده شده اند، می توانیم از روش زیر استفاده کنیم.

public static byte[] Decompress(byte[] bytes)
        {
            using (var memoryStream = new MemoryStream(bytes))
            {
                using (var outputStream = new MemoryStream())
                {
                    using (var decompressStream = new GZipStream(memoryStream, CompressionMode.Decompress))
                    {
                        decompressStream.CopyTo(outputStream);
                    }
                    return outputStream.ToArray();
                }
            }
        }

اجرای الگوریتم فشرده سازی GZip

می‌توانید از قطعه کد زیر برای اجرای روش‌های فشرده‌سازی GZip که ایجاد کردیم استفاده کنید.

byte[] dataToCompress = Encoding.UTF8.GetBytes(originalString);
byte[] compressedData = GZipCompressor.Compress(dataToCompress);
string compressedString = Encoding.UTF8.GetString(compressedData);
Console.WriteLine("Length of compressed string: " + compressedString.Length);
byte[] decompressedData = GZipCompressor.Decompress(compressedData);
string deCompressedString = Encoding.UTF8.GetString(decompressedData);
Console.WriteLine("Length of decompressed string: " + deCompressedString.Length);

وقتی کد بالا را اجرا می کنید، خروجی زیر را در پنجره کنسول خواهید دید.

c compression gzip 01

شکل ۱. GZip رشته اصلی ۲۵۹ کاراکتری را به ۱۶۷ کاراکتر فشرده کرد.

توجه داشته باشید که GZip 92 کاراکتر از رشته اصلی ۲۵۹ کاراکتری را بریده است. از آنجایی که رشته اصلی و رشته از حالت فشرده خارج شده باید یکسان باشند، طول آنها نیز باید یکسان باشد.

هوش مصنوعی مولد و نسخه جدیدی از برنامه نویسی قدیمی

داده ها را با استفاده از Brotli در سی شارپ فشرده و از حالت فشرده خارج کنید

قطعه کد زیر نحوه فشرده سازی داده ها را با استفاده از کلاس BrotliStream در C# نشان می دهد. مانند مثال GZip بالا، توجه داشته باشید که پارامتر متد Compress یک آرایه بایت است.

public static byte[] Compress(byte[] bytes)
        {
            using (var memoryStream = new MemoryStream())
            {
                using (var brotliStream = new BrotliStream(memoryStream, CompressionLevel.Optimal))
                {
                    brotliStream.Write(bytes, 0, bytes.Length);
                }
                return memoryStream.ToArray();
            }
        }

و در اینجا نحوه استفاده از BrotliStream برای فشرده سازی داده ها آمده است:

public static byte[] Decompress(byte[] bytes)
        {
            using (var memoryStream = new MemoryStream(bytes))
            {
                using (var outputStream = new MemoryStream())
                {
                    using (var decompressStream = new BrotliStream(memoryStream, CompressionMode.Decompress))
                    {
                        decompressStream.CopyTo(outputStream);
                    }
                    return outputStream.ToArray();
                }
            }
        }

اجرای الگوریتم فشرده سازی Brotli

قطعه کد زیر نشان می دهد که چگونه می توانید یک رشته را با استفاده از روش فشرده سازی Brotli که در بالا ایجاد کردیم فشرده کنید.

Console.WriteLine("Length of original string: " + originalString.Length);
byte[] dataToCompress = Encoding.UTF8.GetBytes(originalString);
byte[] compressedData = BrotliCompressor.Compress(dataToCompress);
string compressedString = Convert.ToBase64String(compressedData);
Console.WriteLine("Length of compressed string: " + compressedString.Length);
byte[] decompressedData = BrotliCompressor.Decompress(compressedData);
string deCompressedString = Convert.ToBase64String(decompressedData);
Console.WriteLine("Length of decompressed string: " + deCompressedString.Length);

هنگامی که برنامه را اجرا می کنید، خروجی زیر را در پنجره کنسول خواهید دید.

c compression brotli 02

شکل ۲. Brotli رشته اصلی ۲۵۹ کاراکتری را به ۱۲۱ کاراکتر فشرده کرد.

همانطور که می بینید، Brotli کار فشرده سازی را بسیار بهتر از GZip انجام می دهد. با این حال، همانطور که در زیر خواهیم دید، نسبت فشرده سازی تمام داستان نیست.

فشرده سازی و رفع فشرده سازی ناهمزمان با GZip و Brotli

توجه داشته باشید که روش‌های فشرده‌سازی و رفع فشاری که قبلاً استفاده کردیم، مشابه‌های ناهمزمانی دارند. در اینجا نسخه‌های ناهمزمان روش‌های Compress و Decompress با استفاده از الگوریتم GZip آمده است:

public async static Task<byte[]> CompressAsync(byte[] bytes)
        {
            using (var memoryStream = new MemoryStream())
            {
                using (var gzipStream = new GZipStream(memoryStream, CompressionLevel.Optimal))
                {
                    await gzipStream.WriteAsync(bytes, 0, bytes.Length);
                }
                return memoryStream.ToArray();
            }
        }
public async static Task<byte[]> DecompressAsync(byte[] bytes)
        {
            using (var memoryStream = new MemoryStream(bytes))
            {
                using (var outputStream = new MemoryStream())
                {
                    using (var decompressStream = new GZipStream(memoryStream, CompressionMode.Decompress))
                    {
                        await decompressStream.CopyToAsync(outputStream);
                    }
                    return outputStream.ToArray();
                }
            }
        }

و در اینجا نسخه‌های ناهمزمان روش‌های Compress و Decompress با استفاده از Brotli آمده است:

public static async Task<byte[]> CompressAsync(byte[] bytes)
        {
            using (var memoryStream = new MemoryStream())
            {
                using (var brotliStream = new BrotliStream(memoryStream, CompressionLevel.Optimal))
                {
                    await brotliStream.WriteAsync(bytes, 0, bytes.Length);
                }
                return memoryStream.ToArray();
            }
        }
public static async Task<byte[]> DecompressAsync(byte[] bytes)
        {
            using (var memoryStream = new MemoryStream(bytes))
            {
                using (var outputStream = new MemoryStream())
                {
                    using (var brotliStream = new BrotliStream(memoryStream, CompressionMode.Decompress))
                    {
                        await brotliStream.CopyToAsync(outputStream);
                    }
                    return outputStream.ToArray();
                }
            }
        }

محک گذاری فشرده سازی و رفع فشار با GZip و Brotli در سی شارپ

در پروژه برنامه کاربردی کنسولی که قبلا ایجاد کردیم، یک فایل جدید به نام BenchmarkCompression.cs ایجاد کنید و کد زیر را وارد کنید.

[MemoryDiagnoser]
[Orderer(BenchmarkDotNet.Order.SummaryOrderPolicy.FastestToSlowest)]
[RankColumn]
public class BenchmarkCompression
    {
        string originalString = "To work with BenchmarkDotNet you must install the BenchmarkDotNet package. " +
            "You can do this either via the NuGet Package Manager inside the Visual Studio 2019 IDE, " +
            "or by executing the Install-Package BenchmarkDotNet command at the NuGet Package Manager Console";

        [Benchmark]
        public void GZipCompress()
        {
            byte[] dataToCompress = Encoding.UTF8.GetBytes(originalString);
            var compressedData = GZipCompressor.Compress(dataToCompress);
        }

        [Benchmark]
        public void BrotliCompress()
        {
            byte[] dataToCompress = Encoding.UTF8.GetBytes(originalString);
            var compressedData = BrotliCompressor.Compress(dataToCompress);
        }
    }

هنگامی که معیارها را اجرا می کنید، باید خروجی کنسول مشابه آنچه در شکل ۳ در زیر نشان داده شده است، مشاهده کنید.

Microsoft .NET 8 با پیش نمایش پشته بومی ابری وارد بازار شد

c compression gzip brotli 03

شکل ۳. نتایج BenchmarkDotNet… GZip برنده است!

واضح است که هنگام انتخاب یک الگوریتم فشرده‌سازی، نسبت فشرده‌سازی تنها مورد توجه قرار نمی‌گیرد. اگرچه در مقایسه با GZip، می‌توانید با استفاده از Brotli به فشرده‌سازی بسیار بهتری دست یابید، فشرده‌سازی اضافی به قیمت عملکرد تمام می‌شود. GZip در فشرده سازی و فشرده سازی داده ها به طور قابل توجهی سریعتر از Brotli است.

هنگامی که برنامه دات نت خود را محک می زنید، همیشه باید مطمئن شوید که پروژه خود را در حالت انتشار اجرا می کنید. دلیل آن این است که کامپایلر کد را برای حالت های اشکال زدایی و انتشار به طور متفاوتی بهینه می کند. در پست‌های آینده در اینجا، در مورد معیارسنجی و عملکرد برنامه‌ها چیزهای بیشتری برای گفتن خواهم داشت.