如何扇区对齐缓冲区中的数据(win32file.FILE_FLAG_NO_BUFFERING)

时间:2016-10-25 21:13:11

标签: python window pywin32 writefile

考虑这个程序:

import win32file

src_file = win32file.CreateFile(
   r'C:\test.rar',
   win32file.GENERIC_READ,
   win32file.FILE_SHARE_READ,
   None,
   win32file.OPEN_EXISTING,
   win32file.FILE_FLAG_NO_BUFFERING,
   None
)

dst_file = win32file.CreateFile(
    r'D:\test.rar',
    win32file.GENERIC_WRITE,
    win32file.FILE_SHARE_WRITE,
    None,
    win32file.CREATE_ALWAYS,
    win32file.FILE_FLAG_NO_BUFFERING,
    None
)

while True:
    rc, data = win32file.ReadFile(src_file, 4096)
    if not data:
        break
    else:
        win32file.WriteFile(dst_file, data)

src_file.close()
dst_file.close()

写入最新数据文件失败时: pywintypes.error:(87,' WriteFile','参数不正确。')

这是FILE_FLAG_NO_BUFFERING标志所期望的行为,但我不知道如何在python中解决它。

1 个答案:

答案 0 :(得分:0)

您可以使用ctypes。请注意,FILE_FLAG_NO_BUFFERING需要以扇区大小的倍数进行写入,因此除非您希望目标文件大于源文件,否则您可能希望使用不同的设置进行写入。我使用了FILE_FLAG_WRITE_THROUGH:

import ctypes
import ctypes.wintypes

import sys
src_filename = sys.argv[0]
dst_filename = sys.argv[0] + ".test.backup"

CloseHandle = ctypes.windll.kernel32.CloseHandle
CreateFile = ctypes.windll.kernel32.CreateFileA
ReadFile = ctypes.windll.kernel32.ReadFile
WriteFile = ctypes.windll.kernel32.WriteFile
FILE_SHARE_READ = 1
FILE_SHARE_WRITE = 2
FILE_FLAG_NO_BUFFERING = 0x20000000
CREATE_ALWAYS = 2
OPEN_EXISTING = 3
OPEN_ALWAYS = 4
GENERIC_READ  = 0x80000000
GENERIC_WRITE = 0x40000000
INVALID_HANDLE_VALUE = ctypes.wintypes.HANDLE(-1).value
INVALID_FILE_ATTRIBUTES = 0xFFFFFFFF
FILE_FLAG_WRITE_THROUGH = 0x80000000

hSrc = CreateFile(
    src_filename,
    GENERIC_READ,
    FILE_SHARE_READ,
    None,
    OPEN_EXISTING,
    FILE_FLAG_NO_BUFFERING,
    None
)

hDest = CreateFile(
    dst_filename,
    GENERIC_WRITE,
    FILE_SHARE_WRITE,
    None,
    OPEN_ALWAYS,
    FILE_FLAG_WRITE_THROUGH,
    None
)

def ctypes_alloc_aligned(size, alignment):
    """
    http://stackoverflow.com/questions/8658813/control-memory-alignment-in-python-ctypes
    """
    bufSize = size+(alignment-1)
    raw_memory = bytearray(bufSize)

    ctypes_raw_type = (ctypes.c_char * bufSize)
    ctypes_raw_memory = ctypes_raw_type.from_buffer(raw_memory)

    raw_address = ctypes.addressof(ctypes_raw_memory)
    offset = raw_address % alignment
    offset_to_aligned = (alignment - offset) % alignment

    ctypes_aligned_type = (ctypes.c_char * (bufSize-offset_to_aligned))
    ctypes_aligned_memory = ctypes_aligned_type.from_buffer(raw_memory, offset_to_aligned)

    return ctypes_aligned_memory

sectorSize = 4096
bufSize = 256*sectorSize  # 1MB
lpBuffer = ctypes_alloc_aligned(bufSize, sectorSize)
numBytes = ctypes.wintypes.DWORD()

while True:
    bSuccess = ctypes.windll.kernel32.ReadFile( 
       hSrc, lpBuffer, bufSize, ctypes.byref(numBytes), None)

    if not bSuccess:
        print "ReadFile FAILED:", hSrc, numBytes
        raise ctypes.WinError()

    if numBytes.value == 0:
       break

    bSuccess = ctypes.windll.kernel32.WriteFile(
        hDest, lpBuffer, numBytes, ctypes.byref(numBytes), None)

    if not bSuccess:
        print "WriteFile FAILED:", hDest, numBytes
        raise ctypes.WinError()

CloseHandle(hSrc)
CloseHandle(hDest)