Meshbeyn / Projects

Пример использования функций для работы с разреженными потоками

static void ExampleSparse()
{
    //Create new file. Delete the file before restart example!
    FileStream FS = new FileStream(@"d:\file.fil", FileMode.CreateNew);
    for (int i = 0; i < 1000; i++)
        for (byte b = 0; b < 250; b++)
            FS.WriteByte(b);
    FS.Flush();

    //Size of not compressed file
    Console.WriteLine("File Size: {0}", FS.Length);
    Console.WriteLine("Occupied: {0}", FS.GetLengthCompressed());

    //Print first 16 bytes
    Console.WriteLine();
    PrintFirst16Bytes(FS);

    //Zero first 8 bytes in not sparse file
    FS.SetZeroData(new Range(0, 8));
    PrintFirst16Bytes(FS);

    //Make file sparse
    FS.SetSparseAtribute(true);

    //Zero first 0-64k and 128k-196k
    FS.SetZeroData(new Range(0, 64 * 1024));
    FS.SetZeroData(new Range(128 * 1024, 64 * 1024));
    Console.WriteLine();
    Console.WriteLine("Occupied after two 64k-blocks zeroed: {0}", FS.GetLengthCompressed());
    PrintOccupiedRegions(FS);

    //Write one byte in removed region
    FS.Position = 1000;
    FS.WriteByte(0);
    FS.Flush(); 
    Console.WriteLine();
    Console.WriteLine("Occupied after 1 byte written (may be wrong): {0}", FS.GetLengthCompressed());
    System.Threading.Thread.Sleep(1000);
    Console.WriteLine("After pause: {0}", FS.GetLengthCompressed());            
    PrintOccupiedRegions(FS);

    //Print occupied Regions
    Console.WriteLine();
    Console.WriteLine("Refill file");
    FS.RefillZeroRegions();
    PrintOccupiedRegions(FS);


    FS.SetSparseAtribute(false);
    FS.Close();
}

static void PrintFirst16Bytes(FileStream FS)
{
    StringBuilder SB = new StringBuilder();
    FS.Position = 0;
    for (int i = 0; i < 16; i++)
        SB.AppendFormat(" {0:x2}", FS.ReadByte());
    Console.WriteLine("First 16 bytes: {0}", SB.ToString());
}

static void PrintOccupiedRegions(FileStream FS)
{
    Console.WriteLine("Occupied regions:");
    foreach (var R in FS.GetAllocatedRanges())
        Console.WriteLine(" {0} , {1}", R.Start, R.Length);
}

Что происходит в данном примере:

  1. Сначала создается файл D:\file.fil размером в 250000 байт. Чтобы случайно не затереть нужный файл и не оставить атрибуты от старого файла, мы создаем принудительно новый файл. Перед каждым запуском примера Вы должны удалять созданный файл с диска.
  2. Затем выводится логическая длина потока и длина сжатого потока. Так как файл еще не сжат, вторая длина равна первой.
  3. Затем мы выводим первые 16 байт файла до и после обнуления первых восьми. Первые 8 байт стали равны 0, но размер файла не изменился.
  4. Затем у файла устанавливается атрибут разреженности и обнуляются два интервала по 64К: в самом начале файла и с позиции 128К. Физический размер файла при этом сократился.
  5. Затем мы записываем один байт в обнуленный интервал. Файловая система вынуждена опять выделить под него место и занимаемое место увеличивается на 64К. Если вызвать функцию GetLengthCompressed сразу после записи байта, она не всегда возвращает правильный размер. Это проблема WinAPI, а не данной библиотеки.
  6. И, наконец, мы заполняем пустые интервалы в файле и снимаем атрибут разреженности.
File Size: 250000
Occupied: 250000

First 16 bytes:  00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
First 16 bytes:  00 00 00 00 00 00 00 00 08 09 0a 0b 0c 0d 0e 0f

Occupied after two 64k-blocks zeroed: 131072
Occupied regions:
 65536 , 65536
 196608 , 53392

Occupied after 1 byte written (may be wrong): 131072
After pause: 196608
Occupied regions:
 0 , 131072
 196608 , 53392

Refill file
Occupied regions:
 0 , 250000
Распечатка вывода данного примера

Значения физического размера могут зависеть от версии ОС и настроек файловой системы. На моей машине (Windows 8 64bit, с размером кластера 4К) вырезаются блоки только по 64К. Разумеется, выровнены они тоже по этой границе. При другой конфигурации значения могут быть другими, но размер блока и выравнивание не могут быть меньше размера кластера. При запуске под Windows XP этот пример завершится с ошибкой, т.к. некоторые функции появились лишь в более поздних версиях.

Общее описание работы с разреженными потоками см. в разделе Сжатые и разреженные потоки.