【问题标题】:How to create a sparse file on NTFS?如何在 NTFS 上创建稀疏文件?
【发布时间】:2011-04-30 00:24:59
【问题描述】:

我正在测试一个稀疏文件。 但是我的测试代码运行不好。

HANDLE h = CreateFileW(L"D:\\sparse.test",
        GENERIC_READ|GENERIC_WRITE,
        FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
        0,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_SPARSE_FILE,
        0);

DWORD d = GetFileAttributes(L"D:\\sparse.test");
// The function returns 32(FILE_ATTRIBUTE_ARCHIVE).
// Where is FILE_ATTRIBUTE_SPARSE_FILE flag?
// How do I make a sparse file.

DWORD written;
WriteFile(h, "aaa", 3, &written, 0);
SetFilePointer(h, 2*1024*1024*1023, 0, FILE_BEGIN);
SetEndOfFile(h);
WriteFile(h, "bbb", 3, &written, 0);

【问题讨论】:

    标签: windows winapi file-io ntfs sparse-file


    【解决方案1】:

    您必须创建一个普通文件,然后使用DeviceIoControlFSCTL_SET_SPARSE 使其成为稀疏文件。

    【讨论】:

    • @Benjamin:我不知道另一种方法可以完成这项工作。
    • 需要指出的是,所有写入文件的数据总是物理分配的,即使只是0-bytes。因此,根据用例,可能需要额外使用 FSCTL_SET_ZERO_DATA: When you perform a write operation (with a function or operation other than FSCTL_SET_ZERO_DATA) whose data consists of nothing but zeros, zeros will be written to the disk for the entire length of the write. To zero out a range of the file and maintain sparseness, use FSCTL_SET_ZERO_DATA. docs.microsoft.com/de-de/windows/desktop/FileIO/…
    • 微软自己的文档在其他地方另有说明:When a write operation is attempted where a large amount of the data in the buffer is zeros, the zeros are not written to the file.docs.microsoft.com/en-us/windows/desktop/fileio/sparse-files 也许不同之处在于措辞,所有0 与只有一些,两种情况下的行为不同?不过,对我来说没有多大意义。
    【解决方案2】:
    #include <windows.h>
    #include <string>
    #include <iostream>
    
    HANDLE CreateSparseFile(LPCTSTR lpSparseFileName)
    {
        // Use CreateFile as you would normally - Create file with whatever flags 
        //and File Share attributes that works for you
        DWORD dwTemp;
    
        HANDLE hSparseFile = CreateFile(lpSparseFileName,
            GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            NULL,
            CREATE_ALWAYS,
            FILE_ATTRIBUTE_NORMAL,
            NULL);
    
        if (hSparseFile == INVALID_HANDLE_VALUE)
            return hSparseFile;
    
        DeviceIoControl(hSparseFile,
            FSCTL_SET_SPARSE,
            NULL,
            0,
            NULL,
            0,
            &dwTemp,
            NULL);
        return hSparseFile;
    }
    
    DWORD SetSparseRange(HANDLE hSparseFile, LONGLONG start, LONGLONG size)
    {
        // Specify the starting and the ending address (not the size) of the 
        // sparse zero block
        FILE_ZERO_DATA_INFORMATION fzdi;
        fzdi.FileOffset.QuadPart = start;
        fzdi.BeyondFinalZero.QuadPart = start + size;
        // Mark the range as sparse zero block
        DWORD dwTemp;
        SetLastError(0);
        BOOL bStatus = DeviceIoControl(hSparseFile,
            FSCTL_SET_ZERO_DATA,
            &fzdi,
            sizeof(fzdi),
            NULL,
            0,
            &dwTemp,
            NULL);
        if (bStatus) return 0; //Sucess
        else {
            DWORD e = GetLastError();
            return(e); //return the error value
        }
    }
    int _tmain(int argc, _TCHAR* argv[])
    {
        if (argc < 3) {
            std::cerr << "USAGE: SparseFile filename size" << std::endl;
            return 1;
        }
    
        try {
            ULONGLONG size = std::stoull(argv[2]);
            HANDLE h = CreateSparseFile(argv[1]);
            if (h == INVALID_HANDLE_VALUE) {
                std::cerr << "Unable to create file" << std::endl;
                return 1;
            }
            if (SetSparseRange(h, 0, size) != 0) {
                std::cerr << "Unable to set sparse range" << std::endl;
                return 1;
            }
            LARGE_INTEGER seek;
            seek.QuadPart = size;
            if (!SetFilePointerEx(h, seek, 0, 0)) {
                std::cerr << "Unable to seek to desired offset" << std::endl;
                return 1;
            }
            SetEndOfFile(h);
            CloseHandle(h);
        } catch (const std::exception &ex) {
            std::cerr << ex.what() << std::endl;
        }
    
        return 0;
    }
    

    【讨论】:

    • 这是否为 2010 年的答案添加了任何新内容?
    • @ThomasWeller 这是一个使用相同想法的完整工作示例。
    • @ThomasWeller 它引起了FSCTL_SET_ZERO_DATA 的注意,因此我认为这是更好的答案。如果要写入更大的0-bytes 块,则需要这样做,否则将在物理上分配,因此应牢记。 docs.microsoft.com/de-de/windows/desktop/FileIO/…
    猜你喜欢
    • 2014-10-03
    • 1970-01-01
    • 2013-07-25
    • 2022-06-16
    • 2017-03-31
    • 1970-01-01
    • 2019-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多