public void SparseFile() { byte[] randomData = new byte[35 * 4096]; _random.NextBytes(randomData); // Clear the 16 * 4096 -> 32 * 4096 range Array.Clear(randomData, 16 * 4096, 16 * 4096); using (TempFile tmpFile = new TempFile()) { // Create a file File.WriteAllBytes(tmpFile.File.FullName, randomData); using (FilesystemDeviceWrapper wrapper = Win32.GetFileWrapper(tmpFile.File.FullName)) { wrapper.FileSystemSetSparseFile(true); wrapper.FileSystemSetZeroData(16 * 4096, 16 * 4096); FILE_ALLOCATED_RANGE_BUFFER[] rangesData = wrapper.FileSystemQueryAllocatedRanges(0, randomData.Length); // We should have 2 ranges on non-zero data Assert.AreEqual(2, rangesData.Length); } // Discover it via the NTFS lib char driveLetter = tmpFile.File.FullName[0]; RawDisk disk = new RawDisk(driveLetter); NTFSDiskProvider provider = new NTFSDiskProvider(disk); NTFSWrapper ntfsWrapper = new NTFSWrapper(provider, 0); NtfsDirectory ntfsDir = NTFSHelpers.OpenDir(ntfsWrapper, tmpFile.File.DirectoryName); NtfsFile ntfsFile = NTFSHelpers.OpenFile(ntfsDir, tmpFile.File.Name); Assert.IsNotNull(ntfsFile); Assert.IsTrue(tmpFile.File.Attributes.HasFlag(FileAttributes.SparseFile)); AttributeData attributeData = ntfsFile.MFTRecord.Attributes.OfType <AttributeData>().Single(); Assert.IsTrue(attributeData.DataFragments.Length > 1); Assert.IsTrue(attributeData.DataFragments.Any(s => s.IsSparseFragment)); // Read it using (Stream actualStream = File.OpenRead(tmpFile.File.FullName)) using (Stream ntfsStream = ntfsFile.OpenRead()) { bool equal = StreamUtils.CompareStreams(actualStream, ntfsStream); Assert.IsTrue(equal); } } }
private static void ExampleSparseFile() { string file = Path.GetTempFileName(); try { // Write file data const int length = 1 * 1024 * 1024; // 1 MB const int sparseLength = 512 * 1024; // 0.5 MB using (FileStream fs = File.OpenWrite(file)) { byte[] data = new byte[length]; for (int i = 0; i < data.Length; i++) data[i] = 1; // Set the data to non-zero fs.Write(data, 0, data.Length); } Console.WriteLine(@"## Exmaple with {0} ##", file); SafeFileHandle fileHandle = CreateFile(file, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); if (fileHandle.IsInvalid) { int lastError = Marshal.GetLastWin32Error(); Console.WriteLine(@"!! Invalid {0}; Error ({1}): {2}", file, lastError, new Win32Exception(lastError).Message); Console.WriteLine(); return; } using (FilesystemDeviceWrapper fileIo = new FilesystemDeviceWrapper(fileHandle, true)) { FileInfo fileInfo = new FileInfo(file); Console.WriteLine("File size: " + fileInfo.Length); Console.WriteLine("Sparse: " + fileInfo.Attributes.HasFlag(FileAttributes.SparseFile)); // Enable sparse ranges Console.WriteLine("Enabling Sparse file"); fileIo.FileSystemSetSparseFile(true); fileInfo.Refresh(); Console.WriteLine("Sparse: " + fileInfo.Attributes.HasFlag(FileAttributes.SparseFile)); // Set sparse range Console.WriteLine(" Setting sparse range: " + sparseLength + " (length: " + ((fileInfo.Length - sparseLength) / 2) + ")"); fileIo.FileSystemSetZeroData(sparseLength, (fileInfo.Length - sparseLength) / 2); // Query sparse range fileInfo.Refresh(); FILE_ALLOCATED_RANGE_BUFFER[] ranges = fileIo.FileSystemQueryAllocatedRanges(0, length); Console.WriteLine("File size: " + fileInfo.Length); Console.WriteLine("Sparse ranges (" + ranges.Length + "):"); foreach (FILE_ALLOCATED_RANGE_BUFFER range in ranges) { Console.WriteLine(" Non-sparse range: " + range.FileOffset + " (length: " + range.Length + ")"); } } } finally { if (File.Exists(file)) File.Delete(file); } }
private static void ExampleSparseFile() { string file = Path.GetTempFileName(); try { // Write file data const int length = 1 * 1024 * 1024; // 1 MB const int sparseLength = 512 * 1024; // 0.5 MB using (FileStream fs = File.OpenWrite(file)) { byte[] data = new byte[length]; for (int i = 0; i < data.Length; i++) { data[i] = 1; // Set the data to non-zero } fs.Write(data, 0, data.Length); } Console.WriteLine(@"## Exmaple with {0} ##", file); SafeFileHandle fileHandle = CreateFile(file, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); if (fileHandle.IsInvalid) { int lastError = Marshal.GetLastWin32Error(); Console.WriteLine(@"!! Invalid {0}; Error ({1}): {2}", file, lastError, new Win32Exception(lastError).Message); Console.WriteLine(); return; } using (FilesystemDeviceWrapper fileIo = new FilesystemDeviceWrapper(fileHandle, true)) { FileInfo fileInfo = new FileInfo(file); Console.WriteLine("File size: " + fileInfo.Length); Console.WriteLine("Sparse: " + fileInfo.Attributes.HasFlag(FileAttributes.SparseFile)); // Enable sparse ranges Console.WriteLine("Enabling Sparse file"); fileIo.FileSystemSetSparseFile(true); fileInfo.Refresh(); Console.WriteLine("Sparse: " + fileInfo.Attributes.HasFlag(FileAttributes.SparseFile)); // Set sparse range Console.WriteLine(" Setting sparse range: " + sparseLength + " (length: " + ((fileInfo.Length - sparseLength) / 2) + ")"); fileIo.FileSystemSetZeroData(sparseLength, (fileInfo.Length - sparseLength) / 2); // Query sparse range fileInfo.Refresh(); FILE_ALLOCATED_RANGE_BUFFER[] ranges = fileIo.FileSystemQueryAllocatedRanges(0, length); Console.WriteLine("File size: " + fileInfo.Length); Console.WriteLine("Sparse ranges (" + ranges.Length + "):"); foreach (FILE_ALLOCATED_RANGE_BUFFER range in ranges) { Console.WriteLine(" Non-sparse range: " + range.FileOffset + " (length: " + range.Length + ")"); } } } finally { if (File.Exists(file)) { File.Delete(file); } } }