How can I split a binary file into chunks with certain size with batch script without external software?

前端 未结 3 612
情歌与酒
情歌与酒 2021-01-14 23:01

There are many reasons to want to split file into chunks - mainly for network transfer (e.g. e-mail attachments) but I\'m sure there are scenarios that could require such t

相关标签:
3条回答
  • 2021-01-14 23:22

    With all scripts syntax is the same - the file to split and the size in bytes.

    1) MAKECAB - the main limitation is the usage on Unix/Mac machines.For unix eventually cabextract or 7zip could be used , but I'm not sure if it can handle split CAB file .Even on windows the EXPAND command cant do it and EXTRAC32 (command is given in the help message) should be used (or Shell.Application )

    ;@echo off
    
    ;;;;; rem start of the batch part  ;;;;;
    ;; 
    ;; 
    ;; rem the first parameter is the file you want to split  the second is the size in bytes.
    ;; rem size is not guaranteed but will be not overflown 
    ;; 
    ; if "%~2" equ "" (
    ; call :helpmessage
    ; exit /b 1 
    ;)
    ;if not exist "%~dpnx1" (
    ; call :helpmessage
    ; exit /b 2
    ;)
    ;if exist  "%~dpnx1\" (
    ; call :helpmessage
    ; exit /b 3
    ;)
    ; rem remove leading zeroes
    ; cmd /c exit /b %~2
    ; set /a size=%errorlevel%
    ; if %size% equ 0 (
    ; echo size must be greater than 0
    ; exit /b 4
    ;)
    ; rem MaxDiskSize must be multiple of 512 and closest possible to desired size.
    ;if %~2 LSS 512 set diskSize=512 else (
    ; set /a part=%~2%%512
    ; set /a diskSize=%~2-part
    ;)
    ;makecab /d the_file="%~1" /d diskSize=%diskSize% /d the_size="%~2" /F "%~dpfnxs0"
    ;exit /b %errorlevel%
    ;:helpmessage
    ; echo no existing file has been passed
    ; echo usage [split a file to cab parts with given size]:
    ; echo %~nx0 file size
    ; echo(
    ; echo size must be greater than 0
    ; echo (
    ; echo for extraction use :
    ; echo extrac32 /a /e file.ext_part1.cab /l .
    ; exit /b 0
    
    ;;
    ;;;; rem end of the batch part ;;;;;
    
    ;;;; directives part ;;;;;
    ;;
    .New Cabinet
    .set GenerateInf=OFF
    .Set Cabinet=on
    .Set Compress=on
    .Set MaxDiskSize=%diskSize%;
    .Set MaxCabinetSize=%the_size%
    .set CabinetFileCountThreshold=1
    .set CompressedFileExtensionChar=_
    .Set CabinetNameTemplate=%the_file%_part*.cab
    .set DestinationDir=.
    .Set DiskDirectoryTemplate=; 
    
    .set RptFileName=nul
    .set UniqueFiles=ON
    ;.set DoNotCopyFiles=ON
    ;.set MaxDiskFileCount=1
    .set MaxErrors=1
    .set GenerateInf=OFF
    %the_file% /inf=no
    ;;
    ;;;; end of directives part ;;;;;
    

    --All other methods are direct splitting and files can be assembled with appending them to each other in correct order --

    2) JScript - a hybrid file that must be saved with .bat extension

         @if (@x)==(@y) @end /***** jscript comment ******
             @echo off
             cscript //E:JScript //nologo "%~f0" "%~nx0" %* 
             exit /b %errorlevel%
    
         @if (@x)==(@y) @end ******  end comment *********/
    
         //https://github.com/npocmaka/batch.scripts/blob/master/hybrids/jscript/zipjs.bat
    
        var FileSystemObj = new ActiveXObject("Scripting.FileSystemObject");
        var AdoDBObj = new ActiveXObject("ADODB.Stream");
    
        var ARGS = WScript.Arguments;
        var scriptName=ARGS.Item(0);
    
        if (ARGS.length <3) {
            WScript.Echo("Wrong arguments");
            WScript.Echo("usage:");
            WScript.Echo(scriptName +"file_to_split size_in_bytes");
            WScript.Quit(1);
        }
        var file=ARGS.Item(1);
        var max_size=parseInt(ARGS.Item(2));
    
        function getSize(file){
            return FileSystemObj.getFile(file).size;
        }
    
        function isExist(file){
            return FileSystemObj.FileExists(file);
        }
    
        function writeFile(fileName,data ){
            AdoDBObj.Type = 1;       
            AdoDBObj.Open();
            AdoDBObj.Position=0;
            AdoDBObj.Write(data);
            AdoDBObj.SaveToFile(fileName,2);
            AdoDBObj.Close();   
        }
    
        function readFile(fileName,size,position){
            AdoDBObj.Type = 1; 
            AdoDBObj.Open();
            AdoDBObj.LoadFromFile(fileName);
            AdoDBObj.Position=position;
            fileBytes=AdoDBObj.Read(size);
            AdoDBObj.Close();
            return fileBytes;
    
    
        }
    
        function chunker(file,size){
            var part=0;
            var position=0;
            var buffer=readFile(file,size,0);
            file_size=getSize(file);
            while (buffer !== null ) {
                part++;
                WScript.Echo("Creating: "+file+".part."+part);
                writeFile(file+".part."+part,buffer);
                if (size*part <= file_size) {
                    position=size*part;
                } else {
                    position=file_size;
                }
                buffer=readFile(file,size,position);
            }
        }
    
        if (!isExist(file)){
            WScript.Echo(file+" does not exist");
            WScript.Quit(2);
        }
    
        if(max_size<=0){
            WScript.Echo("Size must be bigger than 0.")
            WScript.Quit(3);
        }
    
        chunker(file,max_size);
    

    3) JScript.net - self compiled hybrid that must be saved with .bat extension.

    @if (@X)==(@Y) @end /* JScript comment
    @echo off
    setlocal
    
    for /f "tokens=* delims=" %%v in ('dir /b /s /a:-d  /o:-n "%SystemRoot%\Microsoft.NET\Framework\*jsc.exe"') do (
       set "jsc=%%v"
    )
    
    ::if not exist "%~n0.exe" (
        "%jsc%" /nologo /out:"%~n0.exe" "%~dpsfnx0"
    ::)
    
     %~n0.exe  %*
    
    endlocal & exit /b %errorlevel%
    
    */
    
    import System;
    import System.IO;
    
    var arguments:String[] = Environment.GetCommandLineArgs();
    
    if (arguments.length<3){
        Console.WriteLine("Wrong arguments");
        Console.WriteLine("usage:");
        Console.WriteLine(arguments[0]+"file_to_split size_in_bytes");
        Environment.Exit(1);
    }
    
    var file=arguments[1];
    var max_size=parseInt(arguments[2]);
    
    if (max_size<=0){
        Console.WriteLine("size must be bigger than zero");
        Environment.Exit(2);
    }
    
    if (!File.Exists(file)){
        Console.WriteLine("file"+file+" does not exist");
        Environment.Exit(3);
    }
    
    function writeData(file,data:byte[]){
        Console.WriteLine(data.Length);
        var writer = new BinaryWriter(File.Open(file, FileMode.Create));
        writer.Write(data);
        writer.Close();
    }
    
    function  chunker(inputFile, chunkSize){
    
        var part=0;
        var reader= new BinaryReader(File.Open(inputFile, FileMode.Open));
        var data:byte[]=reader.ReadBytes(chunkSize);
    
        while(reader.BaseStream.Position !== reader.BaseStream.Length) {
            part++;
            Console.WriteLine("Processing part " + part);
            writeData(inputFile+".part."+part,data);
            data=reader.ReadBytes(chunkSize);
    
        }
        if (data.Length !== 0) {
            part++;
            Console.WriteLine("Processing part " + part)
            writeData(inputFile+".part."+part,data);    
        }
        reader.Close();
    }
    
    chunker(file,max_size);
    

    4) CERTUTIL - rather an experimental stuff - it's slower as the buffers are limited to the max length that can string have 8,1** characters and is rather text processing:

    @echo off
    
    setlocal enableExtensions
    rem :-----------------------------------------
    rem : check if should prompt the help message
    rem :-----------------------------------------
    if "%~2" equ "" goto :help
    for %%H in (/h -h /help -help) do (
        if /I "%~1" equ "%%H" goto :help
    )
    if not exist "%~1" echo file does not exist & exit /b 1
    
    
    rem :-----------------------------------------
    rem : validate input
    rem :-----------------------------------------
    set /a size=%~2
    if not defined size echo something wrong with size parameter & exit /b 2
    if %size%0 LSS 00 echo not a valid number passed as a parameter & exit /b 3
    
    rem : -- two hex symbols and an empty space are 1 byte
    rem : -- so the sum of all hex symbols
    rem : -- per part should be doubled
    set /a len=%size%*2
    set "file=%~dfn1"
    
    for %%F in ("%file%") do set fn=%%~nxF
    
    rem : -- clear temp data
    del /F /Q "%temp%\file" >nul 2>&1
    del /F /Q  "%temp%\fn.p.*" >nul 2>&1
    certutil -encodehex -f "%file%" "%temp%\file" >nul
    set "part=1"
    
    setlocal enableDelayedExpansion
            set "hex_str="
            set hex_len=0
            break>%temp%\fn.p.!part!
    
    rem : -- reads the hex encoded file
    rem : -- and make it on a parts that will
    rem : -- decoded with certutil
    
    rem :-- the delimitier is <tab> wich separates
    rem :-- line number from the rest of the information
    rem :-- in the hex file
    rem :---------------------------- v <tab>
    for /f "usebackq tokens=2 delims=   " %%A in ("%temp%\file") do (
            set "line=%%A"
            rem : -- there's a double space in the middle of the line
            rem :-- so here the line is get
            set hex_str=!hex_str!!line:~0,48!
            rem echo hex_str !hex_str!
            rem :-- empty spaces are cleared
            set hex_str=!hex_str: =!
            rem echo hex_str !hex_str! 
            rem :-- the length of the hex line 32
            set /a hex_len=hex_len+32
    
            rem : -- len/size is reached
            rem : -- and the content is printed to a hex file
            if !hex_len! GEQ !len! (
                echo  !hex_len! GEQ !len!
                    set /a rest=hex_len-len
                    for %%A in (!rest!) do (
                            (echo(!hex_str:~0,-%%A!)>>%temp%\fn.p.!part!
                            rem : -- the rest of the content of the line is saved
                            set hex_str=!hex_str:~-%%A!
                            set /a hex_len=rest
                            echo !hex_len!
                    )
                    certutil -decodehex -f %temp%\fn.p.!part! %fn%.part.!part! >nul
                    echo -- !part!th part created --
                    rem :-- preprarin next hex file
                    set /a part=part+1
                    break>%temp%\fn.p.!part!
                    rem :-- reinitilization of the len/size of the file part
                    set /a len=%size%*2
            )
            rem : -- a buffer that not allows to
            rem : -- to enter too long commmands
            rem : -- used to reduce disk operations
            if !hex_len! GEQ 7800 (
                    (echo(!hex_str!)>>%temp%\fn.p.!part!
                    set "hex_str="
                    set hex_len=0
                    rem :-- the size that need to be reached is reduces
                    rem :-- as there's alredy part of the part of the file
                    rem :-- added to the hex file
            set /a len=!len!-7800
                    if !len! LSS 0 set len=0
    
            )
    
    )
    rem : -- adding the rest of the file
    echo !hex_str!>>%temp%\fn.p.!part!
    certutil -decodehex -f %temp%\fn.p.!part! %fn%.part.!part! >nul
    echo -- !part!th part created --
    
    rem : -- clear created temp data
    rem del /F /Q  %temp%\fn.p.* >nul 2>&1
    rem del /F /Q  %temp%\file >nul 2>&1
    endlocal
    endlocal
    
    goto :eof
    rem :-----------------------------------------
    rem : help message
    rem :-----------------------------------------
    
    :help
    echo\
    echo Splits a file on parts by given size in bytes in 'pure' batch.
    echo\
    echo\
    echo    %0 file size
    echo\
    echo\
    

    here's a script that can assemble files split with the last three methods:

    @echo off
    if "%~1" EQU "" echo parameter not entered & exit /b 1
    set "parts=%~1.part"
    
    setlocal enableDelayedExpansion
    set numb=0
    for /f "delims=." %%P in ('dir /b %parts%*') do (
        set /a numb=numb+1
    )
    rem echo !numb!
    
    
    setlocal enableDelayedExpansion
    set "string=%~1.part.1"
    for /l %%n in (2;1;!numb!) do (
        set "string=!string!+!parts!.%%n"
    )
    rem echo !string!
    copy /y /b !string! %~1%~x1
    endlocal
    
    0 讨论(0)
  • 2021-01-14 23:26

    The example below will split a file, producing multiple output files all smaller than the maxChunkSize supplied. To reassemble, you can use copy /b.

    SplitFile.cs
    (compile with c:\Windows\Microsoft.NET\Framework\v2.0.50727\csc /out:splitFile.exe SplitFile.cs)

    using System;
    using System.IO;
    
    namespace SplitFile
    {
        class Program
        {
            static void Main(string[] args)
            {
                long maxChunkSize;
                if (args.Length != 3 || !long.TryParse(args[2], out maxChunkSize) || maxChunkSize <= 81920)
                {
                    Console.WriteLine("Usage: splitfile.exe inputFile outputprefix maxchunksize");
                    Console.WriteLine(" inputfile:     File to split");
                    Console.WriteLine(" outputprefix:  Prefix to use for the output name");
                    Console.WriteLine("                Ex: out -> { out0001.bin, out0002.bin }");
                    Console.WriteLine(" maxchunksize:  Maximum number of bytes in each file");
                    Console.WriteLine("                Note: this is the maximum size, not an exact size");
                    Console.WriteLine("                Note: chunk size cannot be smaller than 81920 bytes");
                    return;
                }
    
                string inputFilePath = args[0];
                string outputFilePathFormat = string.Format("{0}{{0:0000}}.bin", args[1]);
    
                using (Stream fsInput = File.Open(inputFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    byte[] buffer = new byte[81920 /* default from System.Stream */];
                    int cOutFileNo = 0;
                    Stream destination = getOutputFile(ref cOutFileNo, outputFilePathFormat);
                    try
                    {
                        int read;
                        while ((read = fsInput.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            if (destination.Length + read > maxChunkSize)
                            {
                                destination.Dispose();
                                destination = getOutputFile(ref cOutFileNo, outputFilePathFormat);
                            }
    
                            destination.Write(buffer, 0, read);
                        }
                    }
                    finally
                    {
                        destination.Dispose();
                    }
                }
            }
    
            private static Stream getOutputFile(ref int cOutFileNo, string outFileFormat)
            {
                string filename = string.Format(outFileFormat, cOutFileNo);
                cOutFileNo++;
    
                return File.Open(filename, FileMode.CreateNew, FileAccess.Write, FileShare.None);
            }
        }
    }
    

    Example Use:

    C:\drop>splitFile.exe ubuntu-rescue-remix-12-04.iso Ubuntu_Split_ 10485760
    C:\drop>dir
    01/29/2015  17:21       244,570,112 ubuntu-rescue-remix-12-04.iso
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0000.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0001.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0002.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0003.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0004.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0005.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0006.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0007.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0008.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0009.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0010.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0011.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0012.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0013.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0014.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0015.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0016.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0017.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0018.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0019.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0020.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0021.bin
    01/30/2015  15:27        10,485,760 Ubuntu_Split_0022.bin
    01/30/2015  15:27         3,397,632 Ubuntu_Split_0023.bin
    
    C:\drop>copy /b Ubuntu_Split_* Ubuntu_recombined.iso
    Ubuntu_Split_0000.bin
    Ubuntu_Split_0001.bin
    Ubuntu_Split_0002.bin
    Ubuntu_Split_0003.bin
    Ubuntu_Split_0004.bin
    Ubuntu_Split_0005.bin
    Ubuntu_Split_0006.bin
    Ubuntu_Split_0007.bin
    Ubuntu_Split_0008.bin
    Ubuntu_Split_0009.bin
    Ubuntu_Split_0010.bin
    Ubuntu_Split_0011.bin
    Ubuntu_Split_0012.bin
    Ubuntu_Split_0013.bin
    Ubuntu_Split_0014.bin
    Ubuntu_Split_0015.bin
    Ubuntu_Split_0016.bin
    Ubuntu_Split_0017.bin
    Ubuntu_Split_0018.bin
    Ubuntu_Split_0019.bin
    Ubuntu_Split_0020.bin
    Ubuntu_Split_0021.bin
    Ubuntu_Split_0022.bin
    Ubuntu_Split_0023.bin
               1 file(s) copied.
    
    C:\drop>dir Ubuntu*.iso
    01/29/2015  17:21       244,570,112 ubuntu-rescue-remix-12-04.iso
    01/30/2015  15:27       244,570,112 Ubuntu_recombined.iso
    
    C:\drop>fciv -sha1 ubuntu-rescue-remix-12-04.iso
    //
    // File Checksum Integrity Verifier version 2.05.
    //
    02403c37cbdb3e03e00f5176807a793ef63d877c ubuntu-rescue-remix-12-04.iso
    
    C:\drop>fciv -sha1 Ubuntu_recombined.iso
    //
    // File Checksum Integrity Verifier version 2.05.
    //
    02403c37cbdb3e03e00f5176807a793ef63d877c ubuntu-rescue-remix-12-04.iso
    
    C:\drop>
    
    0 讨论(0)
  • 2021-01-14 23:43

    Some time ago I wrote a Batch-JScript hybrid script called BinToBat.bat with this purpose. This is its help screen:

    Create an installer Batch program for data files of any type
    
    BINTOBAT [/T:.ext1.ext2...] [/L:lineSize] [/F[:fileSize]] filename ...
    
      /T:.ext1.ext2    Specify the extensions of text type files that will not be
                       encoded as hexadecimal digits, but preserved as text.
      /L:lineSize      Specify the size of output lines (default: 78).
      /F[:fileSize]    /F switch specify to generate a Full installer file.
                       The optional fileSize specify the maximum output file size.
    
    BinToBat encode the given data files as hexadecimal digits (or preserve they
    as compressed text) and insert they into InstallFiles.bat program; when this
    program run, it generates the original data files.
    
    You may rename the InstallFiles.bat program as you wish, but preserving the
    "Install" prefix is suggested.
    
    You may use wild-cards in the filename list.
    
    If the /F switch is not given, a Partial installer is created:
    - You may insert a short description for each file.
    - You may insert divisions in the file listing via a dash in the parameters.
    - The installer allows to select which files will be downloaded and ask
      before overwrite existent files.
    
    If the /F switch is given, a Full installer is created:
    - The installer always download all files.
    - You may specify commands that will be executed after the files were copied.
    - You may specify the maximum size of the output file via /F:fileFize, so in
      this case the output file will be divided in parts with a numeric postfix.
    
      If you use /F switch you can NOT rename the InstallFiles??.bat files; the
      first one is the installer and the rest just contain data.
    

    You may download BinToBat.bat program from this site.

    0 讨论(0)
提交回复
热议问题