Programmering

opdelt kommando til DOS / Windows via Groovy

En af de kommandoer, jeg savner mest fra Linux, når jeg arbejder i Windows / DOS-miljøer, er splitkommandoen. Denne ekstremt praktiske kommando giver en mulighed for at opdele en stor fil i flere mindre filer bestemt af specifikationen af ​​enten efter antal linjer eller antal bytes (eller kilobytes eller megabyte), der ønskes for de mindre filer. Der er mange anvendelser for sådan funktionalitet, herunder tilpasning af filer til bestemte medier, hvilket gør filer "læsbare" af applikationer med fillængdebegrænsninger osv. Desværre er jeg ikke opmærksom på en splitækvivalent til Windows eller DOS. PowerShell kan scriptes til at gøre noget som dette, men implementeringen er specifik for PowerShell. Der er også tredjepartsprodukter tilgængelige, der udfører lignende funktionalitet. Imidlertid lader disse eksisterende løsninger lige nok tilbage at ønske, at jeg har motivationen til at implementere en splitækvivalent i Groovy, og det er emnet for dette indlæg. Fordi Groovy kører på JVM, kan denne implementering teoretisk køres på ethvert operativsystem med en moderne Java Virtual Machine-implementering.

For at teste og demonstrere det Groovy-baserede split-script kræves en eller anden type kildefil. Jeg bruger Groovy til nemt at generere denne kildefil. Følgende enkle Groovy-script, buildFileToSplit.groovy, opretter en simpel tekstfil, der kan opdeles.

#! / usr / bin / env groovy // // buildFileToSplit.groovy // // Accepterer et enkelt argument for antallet af linjer, der skal skrives til den genererede fil. // Hvis der ikke er angivet et antal linjer, bruges standard på 100.000 linjer. // if (! args) {println "\ n \ nUsage: buildFileToSplit.groovy fileName lineCount \ n" println "hvor fileName er navnet på den fil, der skal genereres, og lineCount er det" println "antal linjer, der skal placeres i den genererede fil." System.exit (-1)} fileName = args [0] numberOfLines = args.length> 1? args [1] som Heltal: 100000 fil = ny fil (filnavn) // sletter outputfil, hvis den allerede eksisterede file.delete () 1.upto (numberOfLines, {file << "Dette er linje # $ {it}. \ n "}) 

Dette enkle script bruger Groovys implicit tilgængelige "args" -håndtag til at få adgang til kommandolinjeargumenter til scriptet buildFileToSplit.groovy. Derefter oprettes en enkelt fil med størrelse baseret på det angivne antal linjer-argument. Hver linje er stort set uoriginal og siger "Dette er linje #" efterfulgt af linjenummeret. Det er ikke en fancy kildefil, men den fungerer til splittelseseksemplet. Det næste skærmbillede viser, at det kører og dets output.

Den genererede source.txt-fil ser sådan ud (kun begyndelsen og slutningen af ​​den vises her):

Dette er linje nr. 1. Dette er linje nr. 2. Dette er linje nr. 3. Dette er linje nr. 4. Dette er linje nr. 5. Dette er linje nr. 6. Dette er linje nr. 7. Dette er linje nr. 8. Dette er linje nr. 9. Dette er linje nr. 10. . . . Dette er linje nr. 239. Dette er linje 240. Dette er linje # 241. Dette er linje # 242. Dette er linje # 243. Dette er linje # 244. Dette er linje # 245. Dette er linje # 246. Dette er linje # 247. Dette er linje # 248. Dette er linje # 249. Dette er linje # 250. 

Der er nu en kildefil tilgængelig, der kan opdeles. Dette script er betydeligt længere, fordi jeg har fået det til at kontrollere for flere fejltilstande, fordi det skal håndtere flere kommandolinjeparametre og simpelthen fordi det gør mere end det script, der genererede kildefilen. Manuskriptet, simpelthen kaldet split.groovy, vises derefter:

#! / usr / bin / env groovy // // split.groovy // // Opdel enkelt fil i flere filer på samme måde som Unix / Linux split // kommando fungerer. Denne version af scriptet er kun beregnet til tekstfiler. // // Dette script adskiller sig fra Linux / Unix-varianten på visse måder. For eksempel: // dette scripts outputmeddelelser adskiller sig i flere tilfælde, og dette // script kræver, at navnet på den fil, der deles, er angivet som // kommandolinjeargument snarere end at give mulighed for at give det som // standardinput . Dette script giver også en "-v" ("--version") mulighed ikke // annonceret til Linux / Unix versionen. // // FORSIGTIG: Dette script er kun beregnet som en illustration af brugen af ​​Groovy til at // emulere Unix / Linux-scriptkommandoen. Det er ikke beregnet til produktion // brug som det er. Dette script er designet til at lave sikkerhedskopier af genererede filer // fra opdeling af en enkelt kildefil, men kun en sikkerhedskopieringsversion oprettes // og tilsidesættes af yderligere anmodninger. // // //marxsoftware.blogspot.com/ // import java.text.NumberFormat NEW_LINE = System.getProperty ("line.separator") // // Brug Groovy's CliBuilder til kommandolinjeargumentbehandling // def cli = ny CliBuilder (brug: 'split [OPTION] [INPUT [PREFIX]]'] cli.with {h (longOpt: 'help', 'Usage Information') a (longOpt: 'suffix-length', type: Number, ' Brug suffikser af længden N (standard er 2) ', args: 1) b (longOpt:' bytes ', type: Number,' Størrelse af hver outputfil i bytes ', args: 1) l (longOpt:' linjer ', type: Antal, 'Antal linjer pr. outputfil', args: 1) t (longOpt: 'verbose', 'Print diagnostisk til standardfejl lige før hver outputfil åbnes', args: 0) v (longOpt: 'version ',' Outputversion og afslut ', args: 0)} def opt = cli.parse (args) hvis (! Opt || opt.h) {cli.usage (); return} hvis (opt.v) {println "Version 0.1 (juli 2010)"; return} hvis (! opt.b &&! opt.l) {println "Angiv længden på splitfiler med enten antal bytes eller antal linjer" cli.usage () return} hvis (opt.a &&! opt.a. isNumber ()) {println "Suffikslængden skal være et tal"; cli.usage (); return} hvis (opt.b &&! opt.b.isNumber ()) {println "Filstørrelse i byte skal være et tal"; cli.usage (); return} hvis (opt.l &&! opt.l.isNumber ()) {println "Linjenummer skal være et tal"; cli.usage (); return} // // Bestem om splitfiler vil blive dimensioneret efter antal linjer eller antal byte // private enum LINES_OR_BYTES_ENUM {BYTES, LINES} bytesOrLines = LINES_OR_BYTES_ENUM.LINES def suffixLength = opt.a? opt.a.toBigInteger (): 2 if (suffiksLængde 1? opt.arguments () [1]: "x" prøv {file = new File (filnavn) hvis (! file.exists ()) {println "Kildefil $ {filnavn} er ikke en gyldig kildefil. "System.exit (-4)} int fileCounter = 1 firstFileName =" $ {prefix} $ {fileSuffixFormat.format (0)} "if (verboseMode) {System.err.println "Opretter fil $ {firstFileName} ..."} outFile = createFile (firstFileName) if (bytesOrLines == LINES_OR_BYTES_ENUM.BYTES) {int byteCounter = 0 file.eachByte {if (byteCounter <numberBytes) {outFile << new String (it )} andet {nextOutputFileName = "$ {prefix} $ {fileSuffixFormat.format (fileCounter)}" hvis (verboseMode) {System.err.println "Opretter fil $ {nextOutputFileName} ..."} outFile = createFile (nextOutputFileName) outFile << ny streng (it) fileCounter ++ byteCounter = 0} byteCounter ++}} andet {int lineCounter = 0 file.eachLine {if (lineCounter <numberLines) {outFile << it << NEW_LINE} ellers {nextOutputFileName = "$ {præfiks} $ {fileSuffixFormat.format (fileCounter)} " hvis (verboseMode) {System.err.println "Opretter fil $ {nextOutputFileName} ..."} outFile = createFile (nextOutputFileName) outFile << it << NEW_LINE fileCounter ++ lineCounter = 0} lineCounter ++}}} fangst (FileNotFoundException fnfEx) { println System.properties println "$ {fileName} er ikke en gyldig kildefil: $ {fnfEx.toString ()}" System.exit (-3)} fangst (NullPointerException npe) {println "NullPointerException fundet: $ {npe.toString ()} "System.exit (-4)} / ** * Opret en fil med det angivne filnavn. * * @param fileName Navnet på den fil, der skal oprettes. * @return-fil oprettet med det angivne navn; null, hvis det angivne navn er null eller * tomt. * / def File createFile (String fileName) {if (! fileName) {println "Kan ikke oprette en fil fra et null eller tomt filnavn." returner null} outFile = ny fil (filnavn) hvis (outFile.exists ()) {outFile.renameTo (ny fil (filnavn + ".bak")) outFile = ny fil (filnavn)} retur outFile} 

Dette script kunne optimeres og bedre modulariseres, men det opfylder sit formål med at demonstrere, hvordan Groovy giver en god tilgang til implementering af platformuafhængige utility-scripts.

Det næste skærmbillede viser scriptets brug af Groovys indbyggede CLI-understøttelse.

De næste to skærmbilleder viser, at kildefilen opdeles i mindre filer efter henholdsvis linjenumre og byte (og ved hjælp af forskellige indstillinger for suffiks og filnavn). Det første billede viser, at der genereres tre outputfiler, når de opdeles i 100 linjer (250 linjer i kildefilen). Indstillingen -a angiver, at fire heltal steder vil være i filnavnet. I modsætning til Linux-split garanterer dette script ikke, at det antal brugere, der leveres af brugeren, er tilstrækkeligt til at dække antallet af nødvendige outputfiler.

Det andet billede (næste billede) viser scriptet, der opdeler kildefilen baseret på antallet af byte og bruger et andet filnavn og kun to heltal til nummereringen.

Som nævnt ovenfor er dette script et "groft snit." Det kunne forbedres med hensyn til selve koden såvel som med hensyn til funktionalitet (udvidet til bedre understøttelse af binære formater og for at sikre, at filnavnesuffikser er tilstrækkeligt lange til antallet af outputfiler). Imidlertid viser scriptet her en af ​​mine foretrukne anvendelser af Groovy: at skrive platformuafhængige scripts ved hjælp af velkendte Java- og Groovy-biblioteker (SDK og GDK).

Denne historie, "split Command for DOS / Windows Via Groovy" blev oprindeligt udgivet af JavaWorld.