functions/Split-File.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<#
.Synopsis
Splits a file to smaller files with choosable size.
.Description
Splits a file to smaller files with choosable size.
The source file remains unchanged.
The resulting files have the name of the source file with an appended forthcounting number.
.Parameter Path
Path of the source file
.Parameter NewSize
Size of the splitted parts (default is 100MB)
.Inputs
None
.Outputs
None
.Example
Split-File "BigFile.dat" 10000000
 
Divides the file BigFile.dat into parts of 10000000 byte size
.Notes
Author: Markus Scholtes
Version: 1.01
Date: 2020-05-03
#>

function Split-File([STRING] $Path, [INT64] $Newsize = 100MB)
{
    if ($Newsize -le 0)
    {
        Write-Error "Only positive sizes allowed"
        return
    }

    "Splitting file $Path to parts of $Newsize byte size"
    $FILEPATH = [IO.Path]::GetDirectoryName($Path)
    if ($FILEPATH -ne "") { $FILEPATH = $FILEPATH + "\" }
    $FILENAME = [IO.Path]::GetFileNameWithoutExtension($Path)
    $EXTENSION  = [IO.Path]::GetExtension($Path)

    $MAXVALUE = 1GB # Hard maximum limit for Byte array for 64-Bit .Net 4 = [INT32]::MaxValue - 56, see here https://stackoverflow.com/questions/3944320/maximum-length-of-byte
    # but only around 1.5 GB in 32-Bit environment! So I chose 1 GB just to be safe
    $PASSES = [MATH]::Floor($Newsize / $MAXVALUE)
    $REMAINDER = $Newsize % $MAXVALUE
    if ($PASSES -gt 0) { $BUFSIZE = $MAXVALUE } else { $BUFSIZE = $REMAINDER }

    $OBJREADER = New-Object System.IO.BinaryReader([System.IO.File]::Open($Path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read))
    [Byte[]]$BUFFER = New-Object Byte[] $BUFSIZE
    $NUMFILE = 1

    do {
        $NEWNAME = "{0}{1}{2,2:00}{3}" -f ($FILEPATH, $FILENAME, $NUMFILE, $EXTENSION)

        $COUNT = 0
        $OBJWRITER = $NULL
        [INT32]$BYTESREAD = 0
        while (($COUNT -lt $PASSES) -and (($BYTESREAD = $OBJREADER.Read($BUFFER, 0, $BUFFER.Length)) -gt 0))
        {
            if (!$OBJWRITER)
            {
                $OBJWRITER = New-Object System.IO.BinaryWriter([System.IO.File]::Create($NEWNAME))
                "Writing to file $NEWNAME"
            }
            "Reading $BYTESREAD bytes of $Path"
            $OBJWRITER.Write($BUFFER, 0, $BYTESREAD)
            $COUNT++
        }
        if (($REMAINDER -gt 0) -and (($BYTESREAD = $OBJREADER.Read($BUFFER, 0, $REMAINDER)) -gt 0))
        {
            if (!$OBJWRITER)
            {
                $OBJWRITER = New-Object System.IO.BinaryWriter([System.IO.File]::Create($NEWNAME))
                "Writing to file $NEWNAME"
            }
            "Reading $BYTESREAD bytes of $Path"
            $OBJWRITER.Write($BUFFER, 0, $BYTESREAD)
        }

        if ($OBJWRITER) { $OBJWRITER.Close() }
        ++$NUMFILE
    } while ($BYTESREAD -gt 0)

    $OBJREADER.Close()
}


<#
.Synopsis
Joins files whose names or filesystem objects are handed in the pipeline to one target file
.Description
Joins files whose names or filesystem objects are handed in the pipeline to one target file.
If the target file exists it will be overwritten. The source files remain unchanged.
.Parameter Path
Path to the source file
.Inputs
Array of strings or filesystem objects
.Outputs
None
.Example
dir *.pdf | Join-File All.pdf
 
Joins all PDF files to target file All.pdf
.Example
"E.pdf", "C.pdf", "G.pdf", "V.pdf", "P.pdf"| Join-File .\Result.dat
 
Joins the listed PDF files to target file Result.dat
.Notes
Author: Markus Scholtes
Version: 1.0
Date: 2017-09-04
#>

function Join-File([STRING] $Path)
{
    if ((!$Path) -or ($Path -eq ""))
    {    Write-Error "Target filename missing."
        return
    }

    $OBJARRAY = @($INPUT)
    if ($OBJARRAY.Count -eq 0)
    {    Write-Error "Source filename list missing."
        return
    }

    $OBJWRITER = New-Object System.IO.BinaryWriter([System.IO.File]::Create($Path))

    $OBJARRAY | ForEach-Object {
        "Appending $_ to $Path."
        $OBJREADER = New-Object System.IO.BinaryReader([System.IO.File]::Open($_, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read))

        $OBJWRITER.BaseStream.Position = $OBJWRITER.BaseStream.Length
        $OBJREADER.BaseStream.CopyTo($OBJWRITER.BaseStream)
        $OBJWRITER.BaseStream.Flush()

        $OBJREADER.Close()
    }

    $OBJWRITER.Close()
}