Search code examples
windowsbatch-filevbscriptscriptingfile-manipulation

Remove character from file in-place with native Windows tools


I'd like to remove the last character off a large file. The restrictions are that:

  • the file has to be modified in-situ, without using the disk space required for a similar second file
  • it's a windows machine
  • I cannot copy any compiled code onto the machine so I cannot create a small c# program of c++ program to manipulate the file
  • this also means any non-native scripting is not available, like python.

As far as I know, this limits me to bat, VB (or JScript) but it does not look like there is a viable option in these. VB requires a TextStream to be created from a systemfile object, but then this stream I believe must be saved elsewhere, using diskspace.

Is there a way to do this simply?


Solution

  • Following the idea from Noodles (of course you need to have some .net framework version installed), you can try this

    (save as trim.cmd and call as trim.cmd "fileToTrim.dat")

    @if (@this==@isBatch) @then
    @echo off
        setlocal enableextensions disabledelayedexpansion
    
        rem check arguments
        set "fileToTrim=%~1"
        if not exist "%fileToTrim%" goto :eof
    
        rem search for a valid framework version
        set "frameworks=%SystemRoot%\Microsoft.NET\Framework"
        set "jsc="
        for /f "tokens=* delims=" %%a in (
            'dir /b /a:d  /o:-n "%frameworks%\v*"'
        ) do if not defined jsc if exist "%frameworks%\%%a\jsc.exe" set "jsc=%frameworks%\%%a\jsc.exe"
    
        if not defined jsc goto :eof
    
        set "executable=%~dpn0.%random%.exe"
        %jsc% /nologo /out:"%executable%" "%~f0"
        if exist "%executable%" (
            "%executable%" "%fileToTrim%"
            del "%executable%" >nul 2>nul 
        )
        endlocal
        exit /b 0
    @end
    import System;
    import System.IO;
    
    var arguments:String[] = Environment.GetCommandLineArgs();
    
        if (arguments.length > 1) {
            var fi:FileInfo = new FileInfo(arguments[1]);
            var fs:FileStream = fi.Open(FileMode.Open);
            fs.SetLength (
                Math.max(0, fi.Length - 1)
            );
            fs.Close();
        };
    

    This is far from efficient, the jscript code is compiled each time. Better directly write the program, compile and use. But just as an example ...