Diamond
29-08-2009, 09:00
Скрипт позволяет разбивать файл на части, которые в последствии можно объеденить с помощью пакетного
файла без нарушения внутреннего форматирования (см. команда Copy /?).
После разбиения, скрипт создаёт пакетный файл "Combine all parts.bat" в том же директории куда копируются части.
P.S. Надеюсь это кому нибудь пригодится. :)
#include <WinAPI.au3>
#include <GuiConstants.au3>
#include <WindowsConstants.au3>
#include <GuiStatusBar.au3>
Global $Title = "SplitFile", $Msg, $ret, $fSplitRunning
Global $Gui = GUICreate($Title, 500, 240)
GUICtrlCreateLabel("Путь к файлу:", 5, 10, 104, 22)
GUICtrlCreateLabel("Сохранить в:", 5, 50, 104, 22)
GUICtrlCreateLabel("Размер части:", 5, 90, 104, 22)
Global $Input1 = GUICtrlCreateInput("",110, 10, 300, 22, 0x0080)
GUICtrlSetTip(-1, "Путь к файлу-источнику.")
Global $Input2 = GUICtrlCreateInput("C:\Split",110, 50, 300, 22, 0x0080)
GUICtrlSetTip(-1, "Директорий для сохранения частей.")
Global $Input3 = GUICtrlCreateInput("", 110, 90, 300, 22, 0x2000+0x0080)
GUICtrlSetTip($Input3, "Размер каждой части в Мегабайтах.")
Global $Button1 = GUICtrlCreateButton("Обзор", 420, 10, 70, 22)
Global $Button2 = GUICtrlCreateButton("Обзор", 420, 50, 70, 22)
Global $Button3 = GUICtrlCreateButton("Разделить", 420, 140, 70, 40)
For $i = $Input1 To $Input3
GUICtrlSetFont($i-3, 11.5, 800, 0, "Times New Roman")
GUICtrlSetFont($i, 11.5, 500, 0, "Arial")
Next
Global $radio1 = GUICtrlCreateRadio("Bytes", 10, 140, 50, 20)
Global $radio2 = GUICtrlCreateRadio("KBytes", 10, 160, 60, 20)
Global $radio3 = GUICtrlCreateRadio("MBytes", 10, 180, 60, 20)
GUICtrlSetState($radio3, $GUI_CHECKED)
Global $Progress = GUICtrlCreateProgress(0, 0, -1, -1, 0x01)
Global $hProgress = GUICtrlGetHandle($Progress)
Global $aParts[4] = [1, 222, 270, -1]
Global $hStatusBar = _GUICtrlStatusBar_Create($Gui, $aParts), $fStatusBarSpoiled = False
_GUICtrlStatusBar_EmbedControl($hStatusBar, 1, $hProgress, 4)
_GUICtrlStatusBar_SetText($hStatusBar, "0%", 2)
GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")
GUIRegisterMsg($WM_SYSCOMMAND, "WM_SYSCOMMAND")
GUIRegisterMsg($WM_PAINT, "WM_PAINT")
GUISetState()
While 1
$msg = GUIGetMsg()
Switch $msg
Case $GUI_EVENT_CLOSE
Exit
Case $Button1
GUISetState(@SW_DISABLE, $Gui)
$ret = FileOpenDialog($Title, "", 'Все файлы (*.*)', 1, "", $Gui)
If Not @error Then GUICtrlSetData($Input1, $ret)
GUISetState(@SW_ENABLE, $Gui)
Case $Button2
GUISetState(@SW_DISABLE, $Gui)
$ret = FileSelectFolder("Выберите пустой директорий для сохранения частей.", "", 1, "", $Gui)
If Not @error And FileExists($ret) Then GUICtrlSetData($Input2, $ret)
GUISetState(@SW_ENABLE, $Gui)
Case $Button3
If Split() = -1 Then $fSplitRunning = False
Case $radio1
GUICtrlSetTip($Input3, "Размер каждой части в Байтах.")
Case $radio2
GUICtrlSetTip($Input3, "Размер каждой части в Килобайтах.")
Case $radio3
GUICtrlSetTip($Input3, "Размер каждой части в Мегабайтах.")
EndSwitch
WEnd
Func Split()
$fSplitRunning = True ; Флаг $fSplitRunning сообщает о том что функция Split была запущена или завершена
Local $ret, $sFile, $sDir, $iSplitSize, $aDirInfo, $iSize, $i, $PartCount, $Current, $newState, $oldState
Local $iBytes, $tBuffer, $hFileOpen, $hFileWrite, $sExt, $sFileName, $sBat
If @ScriptDir <> @WorkingDir Then FileChangeDir(@ScriptDir)
$sFile = GUICtrlRead($Input1)
$sDir = GUICtrlRead($Input2)
For $i = $radio1 To $radio3
If GUICtrlRead($i) = $GUI_CHECKED Then ExitLoop
Next
$iSplitSize = GUICtrlRead($Input3)*1024^($i-$radio1)
If Not FileExists($sFile) Then
_MsgBox(16, $Title, "Файл не существует.", $Gui)
Return -1
EndIf
If Not FileExists($sDir) Then
If Not DirCreate($sDir) Then
_MsgBox(16, $Title, "Укажите путь к папке.", $Gui)
Return -1
EndIf
Else
$aDirInfo = DirGetSize($sDir, 1)
If $aDirInfo[1]+$aDirInfo[2] > 0 Then
$ret = _MsgBox(16, $Title, "Указанная папка не пуста.", $Gui)
Return -1
EndIf
EndIf
If DriveGetType($sDir) <> "Fixed" Then
_MsgBox(16, $Title, "Указанный тип носителя не поддерживается.", $Gui)
Return -1
EndIf
If Not $iSplitSize Then
_MsgBox(16, $Title, "Установлено недопустимое значение размера для части.", $Gui)
Return -1
EndIf
$iSize = FileGetSize($sFile)
If $iSplitSize >= $iSize Then
_MsgBox(16, $Title, "Указанный размер, превышает или равен размеру файла.", $Gui)
Return - 1
EndIf
;===============================================
$PartCount = Ceiling($iSize/$iSplitSize)
$sDir = StringRegExpReplace($sDir,"\\$","") & "\"
$sFileName = StringRegExpReplace($sFile,"^.*\\","")
$sExt = "." & StringRegExpReplace($sFileName, "^.*\.|^.*","")
_GUICtrlStatusBar_SetText($hStatusBar, "Открытие файла...", 3)
$hFileOpen = _WinAPI_CreateFile($sFile, 2, 2)
$Current = $iSplitSize
_GUICtrlStatusBar_SetText($hStatusBar, "Разделение...", 3)
For $i = 1 To $PartCount
If $i = $PartCount Then $Current = $iSize-$iSplitSize*($i-1)
$tBuffer = DllStructCreate("byte[" & $Current & "]")
_WinAPI_ReadFile($hFileOpen, DllStructGetPtr($tBuffer), $Current, $iBytes)
$hFileWrite = _WinAPI_CreateFile($sDir & "part" & $i & $sExt, 1, 4)
_WinAPI_WriteFile($hFileWrite, DllStructGetPtr($tBuffer), $Current, $iBytes)
_WinAPI_CloseHandle($hFileWrite)
_WinAPI_SetFilePointer($hFileOpen, 0, 1) ; смещение от текущей позиции на указанный размер($Current)
$newState = Round(100*$i/$PartCount)
If $newState <> $oldState Then
GUICtrlSetData($Progress, $newState)
_GUICtrlStatusBar_SetText($hStatusBar, $newState & "%", 2)
$oldState = $newState
EndIf
Next
_WinAPI_CloseHandle($hFileOpen)
$sBat = StrBatCreate($sExt, $sFileName, $PartCount)
FileWrite($sDir & "Combine all parts.bat", $sBat)
GUICtrlSetData($Progress, $newState)
_GUICtrlStatusBar_SetText($hStatusBar, "100%", 2)
Sleep(400)
GUICtrlSetData($Progress, 0)
_GUICtrlStatusBar_SetText($hStatusBar, "0%", 2)
_GUICtrlStatusBar_SetText($hStatusBar, "Готово", 3)
Return -1
EndFunc
Func StrBatCreate($sExt, $sDestFile, $iCount)
Local $sBat
$sBat = '@echo off' & @LF & _
'title Подготовка...' & @LF & _
'setlocal enableextensions enabledelayedexpansion' & @LF & _
'set strTempFolder=$temp%random%' & @LF & _
'md ".\%strTempFolder%"' & @LF & _
'for /l %%i in (1,1,' & $iCount & ') do (set strPartFile=Part%%i'& $sExt & @LF & _
'if exist "!strPartFile!" (move "!strPartFile!" ".\%strTempFolder%\!strPartFile!">nul))' & @LF & _
'title Слияние...' & @LF & _
'copy /b ".\%strTempFolder%\Part*'& $sExt & '" "' & $sDestFile & '"' & @LF & _
'title Пожалуйста, дождитесь завершения...' & @LF & _
'move ".\%strTempFolder%\Part*'& $sExt & '" ".">nul' & @LF & _
'rd /s /q ".\%strTempFolder%"'
Return CharToOem($sBat)
EndFunc
Func WM_COMMAND($HWnd, $MsgID, $wParam, $lParam)
Local $iFile, $CtrlID, $iSplitSize, $i, $iPartCount, $iFileSize
$CtrlID = BitAND($wParam, 0xFFFF)
Switch $CtrlID
Case $Button1 To $Button3
If $fSplitRunning Then
DllCall("User32.dll", "int", "MessageBeep", "uint", 16)
Return 1
EndIf
Case $Input1, $Input3, $radio1 To $radio3
$iFile = GUICtrlRead($Input1)
If FileExists($iFile) And Not $fSplitRunning Then
For $i = $radio1 To $radio3
If GUICtrlRead($i) = $GUI_CHECKED Then ExitLoop
Next
$iSplitSize = Number(GUICtrlRead($Input3)*1024^($i-$radio1))
$iFileSize = FileGetSize($iFile)
$iPartCount = Ceiling($iFileSize/$iSplitSize)
If $iPartCount < 0 Or $iFileSize <= $iSplitSize Then $iPartCount = 0
_GUICtrlStatusBar_SetText($hStatusBar, "Кол-во частей: " & $iPartCount, 3)
EndIf
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc
Func WM_PAINT($HWnd, $MsgID)
If $fStatusBarSpoiled Then ; "перерисовка" StatusBar
_GUICtrlStatusBar_EmbedControl($hStatusBar, 1, $hProgress, 4)
$fStatusBarSpoiled = False
EndIf
Return $GUI_RUNDEFMSG
EndFunc
Func WM_SYSCOMMAND($HWnd, $MsgID, $wParam, $lParam)
Local Const $SC_RESTORE = 0xF120
;Устанавливаю флаг $fStatusBarSpoiled в True (для WM_PAINT это обозначит что StatusBar был неверно отрисован при разворачивании окна.)
If $wParam = $SC_RESTORE Then $fStatusBarSpoiled = True
Return $GUI_RUNDEFMSG
EndFunc
Func _MsgBox($MsgBoxType, $MsgBoxTitle, $MsgBoxText, $Main_GUI)
Local $ret, $err
GUISetState(@SW_DISABLE, $Main_GUI)
$ret = DllCall("user32.dll", "int", "MessageBox", _
"hwnd", $Main_GUI, _
"str", $MsgBoxText, _
"str", $MsgBoxTitle, _
"int", $MsgBoxType)
$err = @error
GUISetState(@SW_ENABLE, $Main_GUI)
If Not $err Then Return $ret[0]
EndFunc ;==>_MsgBox
Func CharToOem($String)
Local $tBuffer = DllStructCreate('char[' & StringLen($String)+1 & ']')
DllCall('user32.dll','none','CharToOem','str',$String,'ptr',DllStructGetPtr($tBuffer))
If @error Then Return SetError(@error, 0, 0)
Return SetError(0, 0, DllStructGetData($tBuffer, 1))
EndFunc
файла без нарушения внутреннего форматирования (см. команда Copy /?).
После разбиения, скрипт создаёт пакетный файл "Combine all parts.bat" в том же директории куда копируются части.
P.S. Надеюсь это кому нибудь пригодится. :)
#include <WinAPI.au3>
#include <GuiConstants.au3>
#include <WindowsConstants.au3>
#include <GuiStatusBar.au3>
Global $Title = "SplitFile", $Msg, $ret, $fSplitRunning
Global $Gui = GUICreate($Title, 500, 240)
GUICtrlCreateLabel("Путь к файлу:", 5, 10, 104, 22)
GUICtrlCreateLabel("Сохранить в:", 5, 50, 104, 22)
GUICtrlCreateLabel("Размер части:", 5, 90, 104, 22)
Global $Input1 = GUICtrlCreateInput("",110, 10, 300, 22, 0x0080)
GUICtrlSetTip(-1, "Путь к файлу-источнику.")
Global $Input2 = GUICtrlCreateInput("C:\Split",110, 50, 300, 22, 0x0080)
GUICtrlSetTip(-1, "Директорий для сохранения частей.")
Global $Input3 = GUICtrlCreateInput("", 110, 90, 300, 22, 0x2000+0x0080)
GUICtrlSetTip($Input3, "Размер каждой части в Мегабайтах.")
Global $Button1 = GUICtrlCreateButton("Обзор", 420, 10, 70, 22)
Global $Button2 = GUICtrlCreateButton("Обзор", 420, 50, 70, 22)
Global $Button3 = GUICtrlCreateButton("Разделить", 420, 140, 70, 40)
For $i = $Input1 To $Input3
GUICtrlSetFont($i-3, 11.5, 800, 0, "Times New Roman")
GUICtrlSetFont($i, 11.5, 500, 0, "Arial")
Next
Global $radio1 = GUICtrlCreateRadio("Bytes", 10, 140, 50, 20)
Global $radio2 = GUICtrlCreateRadio("KBytes", 10, 160, 60, 20)
Global $radio3 = GUICtrlCreateRadio("MBytes", 10, 180, 60, 20)
GUICtrlSetState($radio3, $GUI_CHECKED)
Global $Progress = GUICtrlCreateProgress(0, 0, -1, -1, 0x01)
Global $hProgress = GUICtrlGetHandle($Progress)
Global $aParts[4] = [1, 222, 270, -1]
Global $hStatusBar = _GUICtrlStatusBar_Create($Gui, $aParts), $fStatusBarSpoiled = False
_GUICtrlStatusBar_EmbedControl($hStatusBar, 1, $hProgress, 4)
_GUICtrlStatusBar_SetText($hStatusBar, "0%", 2)
GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")
GUIRegisterMsg($WM_SYSCOMMAND, "WM_SYSCOMMAND")
GUIRegisterMsg($WM_PAINT, "WM_PAINT")
GUISetState()
While 1
$msg = GUIGetMsg()
Switch $msg
Case $GUI_EVENT_CLOSE
Exit
Case $Button1
GUISetState(@SW_DISABLE, $Gui)
$ret = FileOpenDialog($Title, "", 'Все файлы (*.*)', 1, "", $Gui)
If Not @error Then GUICtrlSetData($Input1, $ret)
GUISetState(@SW_ENABLE, $Gui)
Case $Button2
GUISetState(@SW_DISABLE, $Gui)
$ret = FileSelectFolder("Выберите пустой директорий для сохранения частей.", "", 1, "", $Gui)
If Not @error And FileExists($ret) Then GUICtrlSetData($Input2, $ret)
GUISetState(@SW_ENABLE, $Gui)
Case $Button3
If Split() = -1 Then $fSplitRunning = False
Case $radio1
GUICtrlSetTip($Input3, "Размер каждой части в Байтах.")
Case $radio2
GUICtrlSetTip($Input3, "Размер каждой части в Килобайтах.")
Case $radio3
GUICtrlSetTip($Input3, "Размер каждой части в Мегабайтах.")
EndSwitch
WEnd
Func Split()
$fSplitRunning = True ; Флаг $fSplitRunning сообщает о том что функция Split была запущена или завершена
Local $ret, $sFile, $sDir, $iSplitSize, $aDirInfo, $iSize, $i, $PartCount, $Current, $newState, $oldState
Local $iBytes, $tBuffer, $hFileOpen, $hFileWrite, $sExt, $sFileName, $sBat
If @ScriptDir <> @WorkingDir Then FileChangeDir(@ScriptDir)
$sFile = GUICtrlRead($Input1)
$sDir = GUICtrlRead($Input2)
For $i = $radio1 To $radio3
If GUICtrlRead($i) = $GUI_CHECKED Then ExitLoop
Next
$iSplitSize = GUICtrlRead($Input3)*1024^($i-$radio1)
If Not FileExists($sFile) Then
_MsgBox(16, $Title, "Файл не существует.", $Gui)
Return -1
EndIf
If Not FileExists($sDir) Then
If Not DirCreate($sDir) Then
_MsgBox(16, $Title, "Укажите путь к папке.", $Gui)
Return -1
EndIf
Else
$aDirInfo = DirGetSize($sDir, 1)
If $aDirInfo[1]+$aDirInfo[2] > 0 Then
$ret = _MsgBox(16, $Title, "Указанная папка не пуста.", $Gui)
Return -1
EndIf
EndIf
If DriveGetType($sDir) <> "Fixed" Then
_MsgBox(16, $Title, "Указанный тип носителя не поддерживается.", $Gui)
Return -1
EndIf
If Not $iSplitSize Then
_MsgBox(16, $Title, "Установлено недопустимое значение размера для части.", $Gui)
Return -1
EndIf
$iSize = FileGetSize($sFile)
If $iSplitSize >= $iSize Then
_MsgBox(16, $Title, "Указанный размер, превышает или равен размеру файла.", $Gui)
Return - 1
EndIf
;===============================================
$PartCount = Ceiling($iSize/$iSplitSize)
$sDir = StringRegExpReplace($sDir,"\\$","") & "\"
$sFileName = StringRegExpReplace($sFile,"^.*\\","")
$sExt = "." & StringRegExpReplace($sFileName, "^.*\.|^.*","")
_GUICtrlStatusBar_SetText($hStatusBar, "Открытие файла...", 3)
$hFileOpen = _WinAPI_CreateFile($sFile, 2, 2)
$Current = $iSplitSize
_GUICtrlStatusBar_SetText($hStatusBar, "Разделение...", 3)
For $i = 1 To $PartCount
If $i = $PartCount Then $Current = $iSize-$iSplitSize*($i-1)
$tBuffer = DllStructCreate("byte[" & $Current & "]")
_WinAPI_ReadFile($hFileOpen, DllStructGetPtr($tBuffer), $Current, $iBytes)
$hFileWrite = _WinAPI_CreateFile($sDir & "part" & $i & $sExt, 1, 4)
_WinAPI_WriteFile($hFileWrite, DllStructGetPtr($tBuffer), $Current, $iBytes)
_WinAPI_CloseHandle($hFileWrite)
_WinAPI_SetFilePointer($hFileOpen, 0, 1) ; смещение от текущей позиции на указанный размер($Current)
$newState = Round(100*$i/$PartCount)
If $newState <> $oldState Then
GUICtrlSetData($Progress, $newState)
_GUICtrlStatusBar_SetText($hStatusBar, $newState & "%", 2)
$oldState = $newState
EndIf
Next
_WinAPI_CloseHandle($hFileOpen)
$sBat = StrBatCreate($sExt, $sFileName, $PartCount)
FileWrite($sDir & "Combine all parts.bat", $sBat)
GUICtrlSetData($Progress, $newState)
_GUICtrlStatusBar_SetText($hStatusBar, "100%", 2)
Sleep(400)
GUICtrlSetData($Progress, 0)
_GUICtrlStatusBar_SetText($hStatusBar, "0%", 2)
_GUICtrlStatusBar_SetText($hStatusBar, "Готово", 3)
Return -1
EndFunc
Func StrBatCreate($sExt, $sDestFile, $iCount)
Local $sBat
$sBat = '@echo off' & @LF & _
'title Подготовка...' & @LF & _
'setlocal enableextensions enabledelayedexpansion' & @LF & _
'set strTempFolder=$temp%random%' & @LF & _
'md ".\%strTempFolder%"' & @LF & _
'for /l %%i in (1,1,' & $iCount & ') do (set strPartFile=Part%%i'& $sExt & @LF & _
'if exist "!strPartFile!" (move "!strPartFile!" ".\%strTempFolder%\!strPartFile!">nul))' & @LF & _
'title Слияние...' & @LF & _
'copy /b ".\%strTempFolder%\Part*'& $sExt & '" "' & $sDestFile & '"' & @LF & _
'title Пожалуйста, дождитесь завершения...' & @LF & _
'move ".\%strTempFolder%\Part*'& $sExt & '" ".">nul' & @LF & _
'rd /s /q ".\%strTempFolder%"'
Return CharToOem($sBat)
EndFunc
Func WM_COMMAND($HWnd, $MsgID, $wParam, $lParam)
Local $iFile, $CtrlID, $iSplitSize, $i, $iPartCount, $iFileSize
$CtrlID = BitAND($wParam, 0xFFFF)
Switch $CtrlID
Case $Button1 To $Button3
If $fSplitRunning Then
DllCall("User32.dll", "int", "MessageBeep", "uint", 16)
Return 1
EndIf
Case $Input1, $Input3, $radio1 To $radio3
$iFile = GUICtrlRead($Input1)
If FileExists($iFile) And Not $fSplitRunning Then
For $i = $radio1 To $radio3
If GUICtrlRead($i) = $GUI_CHECKED Then ExitLoop
Next
$iSplitSize = Number(GUICtrlRead($Input3)*1024^($i-$radio1))
$iFileSize = FileGetSize($iFile)
$iPartCount = Ceiling($iFileSize/$iSplitSize)
If $iPartCount < 0 Or $iFileSize <= $iSplitSize Then $iPartCount = 0
_GUICtrlStatusBar_SetText($hStatusBar, "Кол-во частей: " & $iPartCount, 3)
EndIf
EndSwitch
Return $GUI_RUNDEFMSG
EndFunc
Func WM_PAINT($HWnd, $MsgID)
If $fStatusBarSpoiled Then ; "перерисовка" StatusBar
_GUICtrlStatusBar_EmbedControl($hStatusBar, 1, $hProgress, 4)
$fStatusBarSpoiled = False
EndIf
Return $GUI_RUNDEFMSG
EndFunc
Func WM_SYSCOMMAND($HWnd, $MsgID, $wParam, $lParam)
Local Const $SC_RESTORE = 0xF120
;Устанавливаю флаг $fStatusBarSpoiled в True (для WM_PAINT это обозначит что StatusBar был неверно отрисован при разворачивании окна.)
If $wParam = $SC_RESTORE Then $fStatusBarSpoiled = True
Return $GUI_RUNDEFMSG
EndFunc
Func _MsgBox($MsgBoxType, $MsgBoxTitle, $MsgBoxText, $Main_GUI)
Local $ret, $err
GUISetState(@SW_DISABLE, $Main_GUI)
$ret = DllCall("user32.dll", "int", "MessageBox", _
"hwnd", $Main_GUI, _
"str", $MsgBoxText, _
"str", $MsgBoxTitle, _
"int", $MsgBoxType)
$err = @error
GUISetState(@SW_ENABLE, $Main_GUI)
If Not $err Then Return $ret[0]
EndFunc ;==>_MsgBox
Func CharToOem($String)
Local $tBuffer = DllStructCreate('char[' & StringLen($String)+1 & ']')
DllCall('user32.dll','none','CharToOem','str',$String,'ptr',DllStructGetPtr($tBuffer))
If @error Then Return SetError(@error, 0, 0)
Return SetError(0, 0, DllStructGetData($tBuffer, 1))
EndFunc