一个朋友要的操作稀疏文件源代码
#define _WIN32_WINNT 0x0500 // Windows 2000 or later
#include <windows.h>
#include <stdio.h>
#define ALLOWED_ATTRIBUTES (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
void PrintError(DWORD dwErr) {
char szMsg[256];
DWORD dwFlags = FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK |
FORMAT_MESSAGE_FROM_SYSTEM;
if (!::FormatMessage(dwFlags, NULL, dwErr, 0, szMsg, sizeof(szMsg), NULL)) strcpy(szMsg, "Unknown error.");
printf(szMsg);
printf("\n");
}
void CopyRange(HANDLE hFrom, HANDLE hTo, LARGE_INTEGER iPos, LARGE_INTEGER iSize) {
BYTE buf[64*1024];
DWORD dwBytesRead, dwBytesWritten;
LONG iPosHigh = iPos.HighPart;
DWORD dr = ::SetFilePointer(hFrom, iPos.LowPart, &iPosHigh, FILE_BEGIN);
if (dr == INVALID_SET_FILE_POINTER) {
dr = ::GetLastError();
if (dr != NO_ERROR) throw dr;
}
iPosHigh = iPos.HighPart;
dr = ::SetFilePointer(hTo, iPos.LowPart, &iPosHigh, FILE_BEGIN);
if (dr == INVALID_SET_FILE_POINTER) {
dr = ::GetLastError();
if (dr != NO_ERROR) throw dr;
}
while (iSize.QuadPart > 0) {
if (!::ReadFile(hFrom, buf, (DWORD)min(sizeof(buf), iSize.QuadPart), &dwBytesRead, NULL)) throw ::GetLastError();
if (!::WriteFile(hTo, buf, dwBytesRead, &dwBytesWritten, NULL)) throw ::GetLastError();
if (dwBytesWritten < dwBytesRead) throw (DWORD)ERROR_HANDLE_DISK_FULL;
iSize.QuadPart -= dwBytesRead;
}
}
void main(int argc, char *argv[]) {
HANDLE hInFile, hOutFile;
int iRetCode = EXIT_SUCCESS;
if (argc != 3) {
printf("\nStream copy program:.\n\nUsage:\n CS fromstream tostream\n\nExample:\n CS c:\\some.txt d:\\file.dat:text\n\n");
exit(EXIT_SUCCESS);
}
try {
BY_HANDLE_FILE_INFORMATION bhfi;
char szPath[MAX_PATH], szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szFName[_MAX_FNAME], szExt[_MAX_EXT];
LPSTR pszName;
char szVolName[MAX_PATH], szFSName[MAX_PATH];
DWORD dwSN, dwMaxLen, dwVolFlags;
BOOL bSparseCopy = TRUE;
DWORD dr;
// Source drive supports sparse files?
if (!::GetFullPathName(argv[1], MAX_PATH, szPath, &pszName)) throw ::GetLastError();
_splitpath(szPath, szDrive, szDir, szFName, szExt);
if (strlen(szDrive)) {
strcat(szDrive, "\\");
if (!::GetVolumeInformation(szDrive, szVolName, MAX_PATH, &dwSN, &dwMaxLen, &dwVolFlags, szFSName, MAX_PATH)) throw ::GetLastError();
bSparseCopy = dwVolFlags & FILE_SUPPORTS_SPARSE_FILES;
}
// Target drive supports sparse files?
if (bSparseCopy) { // No need to check if source drive does not support
if (!::GetFullPathName(argv[2], MAX_PATH, szPath, &pszName)) throw ::GetLastError();
_splitpath(szPath, szDrive, szDir, szFName, szExt);
if (strlen(szDrive)) {
strcat(szDrive, "\\");
if (!::GetVolumeInformation(szDrive, szVolName, MAX_PATH, &dwSN, &dwMaxLen, &dwVolFlags, szFSName, MAX_PATH)) throw ::GetLastError();
bSparseCopy = dwVolFlags & FILE_SUPPORTS_SPARSE_FILES;
}
}
hInFile = ::CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hInFile == INVALID_HANDLE_VALUE) throw ::GetLastError();
if (!::GetFileInformationByHandle(hInFile, &bhfi)) throw ::GetLastError();
bSparseCopy = bSparseCopy && (bhfi.dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE); // Check if the source file is sparse
hOutFile = ::CreateFile(argv[2], GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hOutFile == INVALID_HANDLE_VALUE) throw ::GetLastError();
if (bSparseCopy) {
// Perform sparse-aware copy
// Get file size
LARGE_INTEGER iFileSize;
iFileSize.LowPart = ::GetFileSize(hInFile, (LPDWORD)&iFileSize.HighPart);
if (iFileSize.LowPart == (DWORD)-1) {
dr = ::GetLastError();
if (dr != NO_ERROR) throw dr;
}
DWORD dwTemp;
if (!::DeviceIoControl(hOutFile, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwTemp, NULL)) throw ::GetLastError();
// Main loop querying and copying allocated area ranges
FILE_ALLOCATED_RANGE_BUFFER queryrange;
FILE_ALLOCATED_RANGE_BUFFER ranges[1024];
DWORD nbytes, n, i;
BOOL br;
queryrange.FileOffset.QuadPart = 0;
queryrange.Length = iFileSize;
do { // This loop executes more than once only if the file has more than 1024 allocated areas
br = ::DeviceIoControl(hInFile, FSCTL_QUERY_ALLOCATED_RANGES, &queryrange, sizeof(queryrange), ranges, sizeof(ranges), &nbytes, NULL);
if (!br) {
dr = ::GetLastError();
if (dr != ERROR_MORE_DATA) throw dr;
}
n = nbytes / sizeof(FILE_ALLOCATED_RANGE_BUFFER); // Calculate the number of records returned
for (i=0; i<n; i++) // Main loop
CopyRange(hInFile, hOutFile, ranges[i].FileOffset, ranges[i].Length);
// Set starting address and size for the next query
if (!br && n > 0) {
queryrange.FileOffset.QuadPart = ranges[n-1].FileOffset.QuadPart + ranges[n-1].Length.QuadPart;
queryrange.Length.QuadPart = iFileSize.QuadPart - queryrange.FileOffset.QuadPart;
}
} while (!br); // Continue loop if ERROR_MORE_DATA
// Set end of file (required because there can be a sparse area in the end)
dr = ::SetFilePointer(hOutFile, iFileSize.LowPart, &iFileSize.HighPart, FILE_BEGIN);
if (dr == INVALID_SET_FILE_POINTER) {
dr = ::GetLastError();
if (dr != NO_ERROR) throw dr;
}
if (!::SetEndOfFile(hOutFile)) throw ::GetLastError();
}
else {
// Not a sparse file, or sparse copy is impossible
BYTE buf[64*1024];
DWORD dwBytesRead, dwBytesWritten;
do {
if (!::ReadFile(hInFile, buf, sizeof(buf), &dwBytesRead, NULL)) throw ::GetLastError();
if (dwBytesRead) {
if (!::WriteFile(hOutFile, buf, dwBytesRead, &dwBytesWritten, NULL)) throw ::GetLastError();
if (dwBytesWritten < dwBytesRead) throw (DWORD)ERROR_HANDLE_DISK_FULL;
}
} while (dwBytesRead == sizeof(buf));
}
::CloseHandle(hInFile);
// Set output file attributes
if (!::SetFileTime(hOutFile, &bhfi.ftCreationTime, &bhfi.ftLastAccessTime, &bhfi.ftLastWriteTime)) throw ::GetLastError();
::CloseHandle(hOutFile);
if (!::SetFileAttributes(argv[2], bhfi.dwFileAttributes & ALLOWED_ATTRIBUTES)) throw ::GetLastError();
}
catch (DWORD dwErrCode) {
PrintError(dwErrCode);
iRetCode = EXIT_FAILURE;
}
exit(iRetCode);
}
浙公网安备 33010602011771号