Fortschrittsanzeige in Batch Datei?
Hallo zusammen,
ich habe für unsere neue Warenwirtschaft eine Batch-Datei erstellt, um Lagerbestände von verschiedenen Lieferanten einzuspielen. Ist es möglich beim einspielen der CSV Datei einen Fortschrittsanzeige in % anzugeben ?
Liebe Grüße und Danke im voraus!
6 Antworten
Erstmal möchte ich mich entschuldigen ,das es solang mit der Antwort gedaert hat.
ich bin ehrlich... mir sind 400qm Garten und 1Kasten Bier dazwischen gekommen...
Gesten Nachmittag habe ich mich hingesetzt um die paar Zeilen Code in meinen Editor zu hacken.
Nun zum Thema:
Die Fortschrittsanzeige selbst war kein Thema die meisten Routinen hatte ich irgendwann mal Stückweise geschrieben und in meiner Batchbibliothek.
...was kann denn so schwer sein den Kram um zwei For-loops mit findstr herumzubauen? der Klassiker...
nur hat kein Batchschreiber , der mal ein paar 100 Zeilen CSV liest auf dem Schirm das findstr ein paar Tücken hat. über welche auch Du gestolpert bist.
Es ist elendiglich langsam. ...und buffert erstmal jegliche Anzeige nur um dann alles auf einmal auszuspucken... Man hockt tatsächlich ewigkeiten vorm blinden Fenster...
dabei geht es doch , wenn man mit...
for /f "usebackq tokens=* delims=:" %%a in ("%quell-CSV%") do (
echo %%a | find /i "irgendwas" >> "%ziel-CSV%" )
...filtert ohne zu Buffern.
die Krux an dem die meisten scheitern, ist, das obiger Loop ohne usebackq nur Dateien ohne Leerzeichen im Namen liest, weil dafür Anführunszeichen nötig sind, diese jedoch anderen Funktionen vorbehalten sind. usebackq macht es möglich... Batchirrsinn.
Egal... es klappt... Zeilen werden 90mal schneller und Einzeln gelesen als mit findstr im in Block. Diese Methode Filtert automatisch alle Leerzeilen aus.(besser geht es kaum...)
Finstr ist damit Disqalifiziert... raus...!!!
Mit 4 Sekunden / 100.000 Zeilen merkt man fast garnicht das eine primitiver for-loop zählt. Demo1
Ich war der Meinung das wäre noch zu toppen und habe gaanz tief in die Batcher Trickkiste gelangt... Chimera... ein mix aus mehreren Schriptsprachen in einer Batchdatei .
Die Batch enthält ein kleines Javascript-programm welches nichts weiter kann als Zeilen zu zählen und das Ergebnis auszugeben...
wenns dazu Fragen gibt, später...
Diese Methode benötigt etwa 1,15 Sekunde für die 100.000 Zeilen. da ist sogar C# langsamer...:p
siehe Demo2 .
Demo3 nur zum Testen.
In Demo 1 ist alles bestens? kommentiert.
bei den anderen beiden Code-Listings habe ich alles weggelassen, was das gleiche wie in Demo 1 ist....
Zum Schluss noch eine kleine Batch die 100000 zufällige Datensätze zum Testen erzeugt.
jetzt bete ich das Gutefrage so viele Zeilen erlaubt....
Die Listings:
Demo1:
@echo off
setlocal enabledelayedexpansion
call :init_clrln
set "quell-CSV=mein Quelle.csv"
set "ziel-CSV=mein Ziel.csv"
set "lineOffLast_Record=0"
set "currentLine=0"
echo %time%
rem die "fileRead-Methode mit ist ca. 90 mal schneller als das zählen mit Findstring!
rem Leerzeilen werden automatisch entfernt ca.4 Sec /100000 Zeilen!
rem Zeilen Zählen...
for /f "usebackq " %%a in ("%quell-CSV%") do (set /a "lineOffLast_Record+=1")
echo %time% %lineOffLast_Record%
rem Datensätze Verarbeiten:
rem Dito wie Oben, jedoch wird nun der Rest im token * an %%b übergeben
for /f "usebackq tokens=* delims=:" %%a in ("%quell-CSV%") do (
rem einen Datensatz aus der Quell-CSV-Datei auslesen
rem und an die ZielCSV-Datei anhängen
rem statt einfach an eine andere CSV-Datei anzuhängen können auch andere
rem auf den Datensatz bezogene Befehle/Umformatierungen eingesetzt werden.
echo %%a >> "%ziel-CSV%"
rem Filtern kann man mit einer Pipe..
rem zB. echo %%a |find /i /v "Rudi" >>datei verwirft alle Zeilen mit Rudi
rem hier beginnt der Fortschritt-Kram
rem mitzählen bei welchem Datensatz wir sind..
rem aktuelle Zeilennummer...
set /a "currentLine+=1"
rem Unterprogramm aufrufen
call :show_progress 30
)
echo:
echo %time%
pause
exit /b
rem ================Subroutines===============================
:show_progress
rem parameter : Number >0 (eg. Div by Zero)
rem schreibt nur wenn die aktuell Zeilennummer nach modulo 1 ist.
rem verhindert Flackern der Anzeige
set /a "refreshLine=%currentLine% %% %~1"
if %currentLine% neq %lineOffLast_Record% if %refreshLine% neq 1 exit /b
call :calc_PerMille progress %lineOffLast_Record% %currentLine%
call :ppmToPecentString percentStr %progress%
call :formatString currentLine currLnStr 10
call :formatString percentStr percentStr 7
rem lösche aktuelle Zeile rückwärts bis zum Zeilenanfang und schreibe Text
rem entspricht "echo ...." jedoch wechselt der cursor nicht in die nächste Zeile
<nul set /p =%clrln%Fortschritt: %percentStr% Zeile: %currLnStr% Die Zeit vergeht: %time% ||ver>nul
exit /b
:calc_PerMille
rem params: Zielvariable %Grundwert% %Promillewert%
rem nein... hat nicht mit saufen zu tun!
rem fiese Batchalgebra: an die GrundwertVariable %3 einfach 3 Nullen "malen" (mal 1000)
set /a "%~1=%3000 / %2 "
exit /b
:ppmToPecentString
rem params outVariablename Number
rem Batch kennt keine Fließomma-Berechnug, also wird einfach die Ganzzahl Zerschnitten
rem und um das Komma wieder zusammen gefiedelt
set "ppm=%2"
if !ppm! gtr 9 (
set "%~1=!ppm:~0,-1!,!ppm:~-1! %%"
) else (
set "%~1=0,!ppm:~-1! %%"
)
exit /b
:formatString
rem params: inVar outVar outStringLenght (max.50)
set "%~2= !%~1:~-%~3!"
rem jetzt ist er wieder bis zu 21 Zeichen lang und wir holen uns wieder die letzten 10
rem nun h
set "%~2=!%~2:~-%~3!"
exit /b
:init_clrln
rem Zeile mit 80 Backspaces erzeugen ... (löscht eine Zeile vom end zum Anfang) erzeugt die Variablen %bkspc% und %clrln%
for /f "delims=;" %%. in ('"prompt $H; & for %%. in (nul) do call"') do ( set "bkspc=%%." & set "clrln=!bkspc!" & for /l %%: in (1,1,4) do (set "clrln=!clrln!!clrln!!clrln!"))
exit /b
rem ================Subroutines end===============================
Demo2:
<!-- : diese Zeile nicht löschen
@echo off
setlocal enabledelayedexpansion
call :init_clrln
set "quell-CSV=mein Quelle.csv"
set "ziel-CSV=mein Ziel.csv"
set "lineOffLast_Record=0"
set "currentLine=0"
echo %time%
rem die "Batch-fileRead-Methode ist ca. 300 mal schneller als das zählen mit Findstr!
rem Jascript benötigt nur 1,15 Sekunden für 100000Zeilen in ist damit etwa 200 mal schneller als zählen mit Findstr ...
for /f "usebackq " %%a in (`mshta "%~f0" "%quell-CSV%"`) do (set "lineOffLast_Record=%%a")
echo %time% %lineOffLast_Record%
for /f "usebackq tokens=* delims=:" %%a in ("%quell-CSV%") do (
echo %%a >> "%ziel-CSV%"
set /a "currentLine+=1"
rem Unterprogramm aufrufen
call :show_progress 30
)
echo:
echo %time%
pause
exit /b
rem ================Subroutines===============================
...
wie Demo1
...
rem ================Subroutines end===============================
und diese auch nicht -->
<hta:application
ID="oHTA"
applicationname="CountLines"
windowState="minimize" >
<script>
if(typeof oHTA.commandLine !== "undefined")
{
args=oHTA.commandLine;
args=args.replace(/" "/g, String.fromCharCode(34,1,34)).replace(/"/g,'');
res = args.split(String.fromCharCode(1));
shortcut=res[1];
countlines();
}
close();
function countlines()
{
var x=0;
fso=new ActiveXObject('Scripting.FileSystemObject');
iS=fso.OpenTextFile(shortcut,1, false);
while(!iS.AtEndOfStream)
{
line=iS.ReadLine()
if ( line.length > 0 )
{ //leerzeilen ausschließen
x+=1;
} ;
};
iS.Close();
fso.GetStandardStream(1).Write(x);
}
</script>
Demo3
wie demo1
...
rem lahhhhm.... 375 Sekunden um 100000 Zeilen zu zählen...
for /f "usebackq tokens=1 delims=:" %%a in (`findstr /n /c:"," "%quell-CSV%"`) do (set "lineOffLast_Record=%%a")
echo %time% %lineOffLast_Record%
pause
rem Datensätze Verarbeiten:
rem Dito wie Oben, jedoch wird nun der Rest im token * an %%b übergeben
for /f "usebackq tokens=1* delims=:" %%a in (`findstr /n /c:"," "%quell-CSV%"`) do (
rem ...und da sieht man ewig keinen Fortschritt,
rem findstr liest erstmal gemächlich im Blindflug alle Zeilen bevor es ein Lebenszeichen von sich gib.
rem durchgefallen....
echo %%b >> "%ziel-CSV%"
set /a "currentLine+=1"
rem Unterprogramm aufrufen
call :show_progress 30
)
echo:
echo %time%
pause
exit /b
rem ================Subroutines===============================
wie Demo1
rem ================Subroutines end===============================
csv erzeugen:
@echo off
setlocal enabledelayedexpansion
for /l %%f in (1,1,100000) do (
echo %%f
echo !random!,!random!,!random!,!random!,!random!,!random!,!random!,!random!,!random!,%%f>>"mein Quelle.csv")
pause
exit /b
Ja.
Benutze statt des normalen Copy Befehl das tool robocopy.
Das ist bei jedem Windows mit dabei.
Ist ein sehr leistungsfähiges Copy mit vielen Kommandozeilenparametern.
Unter anderem auch welchen für eine Art Fortschrittsanzeige
(mit % - aber keinen grafischen Balken)
...
Eine andere Möglichkeit wäre, statt des cmd copy ein selbstgebasteltes VBS script zu nutzen.
Da man im Batch Variablen verwenden kann und man Schleifen programmieren kann, sollte das möglich sein.
Bin kein Batch-Experte, aber Variablen macht man meine ich mit Set und %Variable% und eine for-Schleife gibt es meine ich auch. Notfalls nimmst du GoTo.
Schön wäre es, wenn du noch ein Kommando finden würdest, mit dem du den Cursor genau auf dem Bildschirm positionieren könntest.
Mit welchem Programm (/Befehl) liest du die CSV denn ein? Oder kopierst du diese einfach nur?
So viel ich weiss nicht ohne externe Programme. Aber auch dann ist es überhaupt nicht schön. Solche arbeiten sollte man eigentlich nicht mit einem Batch erledigen ;)