Read the redirected input file in ANY order
Posted: 19 Jan 2012 13:05
In this topic I presented TYPEOFHANDLE.COM program that get status information from the standard handles. However, a .COM program may also modify certain handle status that persists after the .COM program ends; for example, the File Pointer position.This program move handle's File Pointer to the position given in bytes. Use 0 to BOF; use an E letter to indicate EOF.
SETFILEPOINTER program allows to read lines from the redirected input file in any order via the starting position of each line. These positions can be obtained just once and stored in an auxiliary file to be used several times:File lines must end in CR+LF characters (Windows style) and must not have trailing control characters; also, they must not exceed the maximum SET /P input length of 1021 characters.
EDIT: I realized that previous process may be achieved in a simpler way via FINDSTR /O command this way:
By convention, we will use .DEX extension for line-position files. For example, this data file:... generate this index file:For example, this command:... create this index file:... display this result:
A data file may also contain the position of a field located in another data file, like a rudimentary Relational Data Base (see this post).
This method also allows to modify data in a redirected output file in any place of the file, not just appending data at the end. To do that, just move the File Pointer of handle 1 to the desired position before output the new data:Result:
Code: Select all
SETFILEPOINTER handle position
SETFILEPOINTER program allows to read lines from the redirected input file in any order via the starting position of each line. These positions can be obtained just once and stored in an auxiliary file to be used several times:
Code: Select all
:CreateLinePositions
set position=0
:nextLine
echo %position%
set line=
set /P line=
call :StrLen line lineLen=
set /A position+=lineLen+2
TypeOfHandle 0
set /A eof=%errorlevel% ^& 64
if %eof% == 0 goto nextLine
exit /B
EDIT: I realized that previous process may be achieved in a simpler way via FINDSTR /O command this way:
Code: Select all
:CreateLinePositions
for /F "delims=:" %%a in ('findstr /O "^"') do echo %%a
exit /B
By convention, we will use .DEX extension for line-position files. For example, this data file:
... with this command:Days.txt wrote:Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Code: Select all
call :CreateLinePositions < Days.txt > lines.dex
A data file may have several index files that allows to process the data in different orders. The following subroutine use the Bubble Sort method to sort the indexes of the lines, but does not modify the file itself:lines.dex wrote:0
8
16
25
36
46
54
Code: Select all
:BubbleSort baseIndex < inputFile > resultIndex
setlocal EnableDelayedExpansion
set n=0
for /F %%p in (%1) do (
set /A n+=1
set linePos[!n!]=%%p
)
:bubblePass
set anyChange=
set one=1
setFilePointer 0 !linePos[1]!
set /P line1=
for /L %%i in (2,1,%n%) do (
setFilePointer 0 !linePos[%%i]!
set /P line2=
if "!line1!" gtr "!line2!" (
set /A temp=linePos[!one!], linePos[!one!]=linePos[%%i], linePos[%%i]=temp
set "line2=!line1!"
set anyChange=True
)
set /A one+=1
set "line1=!line2!"
)
if defined anyChange goto bubblePass
for /L %%i in (1,1,%n%) do echo !linePos[%%i]!
exit /B
Code: Select all
call :BubbleSort lines.dex < Days.txt > alpha.dex
... so this code:alpha.dex wrote:46
8
54
0
36
16
25
Code: Select all
< Days.txt (
for /F %%p in (alpha.dex) do (
setFilePointer 0 %%p
set /P line=
echo !line!
)
)
DaysInAlphaOrder.txt wrote:Friday
Monday
Saturday
Sunday
Thursday
Tuesday
Wednesday
A data file may also contain the position of a field located in another data file, like a rudimentary Relational Data Base (see this post).
This method also allows to modify data in a redirected output file in any place of the file, not just appending data at the end. To do that, just move the File Pointer of handle 1 to the desired position before output the new data:
Code: Select all
(
setFilePointer 1 46
echo Line 6
) >> Days.txt
Remember that the repetitive execution of .COM end .EXE executable programs is achieved faster if the DOS Window is maximized with Alt-Enter key. This is the complete SETFILEPOINTER.COM test program:Result wrote:Sunday
Monday
Tuesday
Wednesday
Thursday
Line 6
Saturday
Code: Select all
@echo off
::SETFILEPOINTER.COM test program
::Antonio Perez Ayala - Jan/19/2012
setlocal EnableDelayedExpansion
if not exist SetFilePointer.com call :CreateSetFilePointer
cls
echo Days.txt:
(
echo Sunday
echo Monday
echo Tuesday
echo Wednesday
echo Thursday
echo Friday
echo Saturday
) > Days.txt
type Days.txt
echo/
echo lines.dex:
call :CreateLinePositions < Days.txt > lines.dex
type lines.dex
echo/
echo alpha.dex:
call :BubbleSort lines.dex < Days.txt > alpha.dex
type alpha.dex
echo/
echo DaysInAlphaOrder:
< Days.txt (
for /F %%p in (alpha.dex) do (
setFilePointer 0 %%p
set /P line=
echo !line!
)
)
echo/
echo Line 6 of Days.txt modified:
(
setFilePointer 1 46
echo Line 6
) >> Days.txt
type Days.txt
goto :EOF
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:CreateSetFilePointer
setlocal DisableDelayedExpansion
set SetFilePointer=2ÿ³‹û‹ó2íŠMÿãE° üó®t^>Š]ÿ€û0r6€û9w1€ë0Sã+€= u^&ó®t"Of3Àf3ɱ+€é!f3ÛGŠ]ÿ€ûEt+€ûeu(uÿë%%ëyGf3ÛŠ]ÿ€û0rs€û9wnf÷á€ë0f÷Ûf+ÃëáëØëäf‹È2Àf#ÉuTþÀþÀ€<EtK€<etFFÆDÿB‹Ñ±1€é!fÓé[´BÍ!r€|ÿBu§±1€é!fÓâ‹Ðf÷Úf‹Ê±1€é!fÓé2ÀþÀþÀ´BÍ!2À´LÍ!ë¢ë½
setlocal EnableDelayedExpansion
echo !SetFilePointer!> SetFilePointer.com
exit /B
:CreateLinePositions < inputFile > baseIndex
for /F "delims=:" %%a in ('findstr /O "^"') do echo %%a
exit /B
:BubbleSort baseIndex < inputFile > resultIndex
setlocal EnableDelayedExpansion
set n=0
for /F %%p in (%1) do (
set /A n+=1
set linePos[!n!]=%%p
)
:bubblePass
set anyChange=
set one=1
setFilePointer 0 !linePos[1]!
set /P line1=
for /L %%i in (2,1,%n%) do (
setFilePointer 0 !linePos[%%i]!
set /P line2=
if "!line1!" gtr "!line2!" (
set /A temp=linePos[!one!], linePos[!one!]=linePos[%%i], linePos[%%i]=temp
set "line2=!line1!"
set anyChange=True
)
set /A one+=1
set "line1=!line2!"
)
if defined anyChange goto bubblePass
for /L %%i in (1,1,%n%) do echo !linePos[%%i]!
exit /B