windowsfileactivexactivexobject

Read and Write File Section of File Only (Without Streams)


Most high-level representations of files are as streams. C's fopen, ActiveX's Scripting.FileSystemObject and ADODB.Stream - in fact, anything built on top of C is very likely to use a stream representation to edit files.

However, when modifying large (~4MiB) fixed-structure binary files, it seems wasteful to read the whole file into memory and write almost exactly the same thing back to disk - this will almost certainly have a performance penalty attached. Looking at the majority of uncompressed filesystems, there seems to me to be no reason why a section of the file couldn't be read from and written to without touching the surrounding data. At a maximum, the block would have to be rewritten, but that's usually on the order of 4KiB; much less than the entire file for large files.

Example:

00 01 02 03
04 05 06 07
08 09 0A 0B
0C 0D 0E 0F

might become:

00 01 02 03
04 F0 F1 F2
F3 F4 F5 0B
0C 0D 0E 0F

A solution using existing ActiveX objects would be ideal, but any way of doing this without having to re-write the entire file would be good.


Solution

  • Okay, here's how to do the exercise in powershell (e.g. hello.ps1):

    $path = "hello.txt"
    $bw = New-Object System.IO.BinaryWriter([System.IO.File]::Open($path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::ReadWrite))
    $bw.BaseStream.Seek(5, [System.IO.SeekOrigin]::Begin)
    $bw.Write([byte] 0xF0)
    $bw.Write([byte] 0xF1)
    $bw.Write([byte] 0xF2)
    $bw.Write([byte] 0xF3)
    $bw.Write([byte] 0xF4)
    $bw.Write([byte] 0xF5)
    $bw.Close()
    

    You can test it from command line:

    powershell -file hello.ps1
    

    Then, you can invoke this from your HTA as:

    var wsh = new ActiveXObject("WScript.Shell");
    wsh.Run("powershell -file hello.ps1");