Showing 7 changed files with 88 additions and 15 deletions
+15 -7
README.md
... ...
@@ -11,11 +11,11 @@ license below), you may download the binary.
11 11
 
12 12
 Here are the SHA-256 checksums for the binaries:
13 13
 
14
-    f209b32d6fcc07bb5788789bf38419b80ceace8e37b12fd395adfabce1e861f1  csv2xlsx_386.exe
15
-    76be18318b797742985b4547ddb502688b014bb13f19a1b5d9e886869446e33e  csv2xlsx_amd64.exe
16
-    97fce8d687a73c770dd5463c01ee126bc82fafb1da5fd49dd4751dce06f2cebd  csv2xlsx_linux_386
17
-    a931741383cb68a10bad6a107b0956d5f9e1e23eecb4c11c399bb463307c77bc  csv2xlsx_linux_amd64
18
-    7fbfce2072fedb66fe1a26b1e28399e3ef3b68fc3179778f1c59230fecbda904  csv2xlsx_osx
14
+    9cd013ac244c0d364302da1eab724ea93831f6088188bcaaae08545f00a4582a  csv2xlsx_386.exe
15
+    535c3937447497bd0769296d434c809b41e1ead7bc463f560888ec51cfb95794  csv2xlsx_amd64.exe
16
+    d491329c16f44d82c6d50bb4afa74bd704f25ade7e93b28d0ec0b747648c9a6e  csv2xlsx_linux_386
17
+    cfa63a9eb6ab4d9c418afe95cf54524b32611a01d970e95ed57831b1368406f1  csv2xlsx_linux_amd64
18
+    daa9ff8f2ccb49b6ccf4fd7d7b600011a8bd4ba9fe1b3870ce15dcbbe6fa1092  csv2xlsx_osx
19 19
 
20 20
 ### Usage
21 21
 
... ...
@@ -41,13 +41,18 @@ Please see below for a list of command line options.
41 41
       encoding string to use for the CSV file, case-insensitive (defaults to "utf-8")
42 42
   -exceldateformat string
43 43
     	Excel format for date cells (default as in Excel)
44
-  -h	display usage information
44
+  -filemask
45
+        bulk mode, specify a file mask here (e.g. "/use/docs/datalib/2018*.csv")
46
+        make sure to quote the filespace to prevent shell globbing
47
+  -h	
45 48
   -help
46 49
     	display usage information
47 50
   -infile string
48 51
     	full pathname of input file (CSV file)
49 52
   -outfile string
50 53
     	full pathname of output file (.xlsx file)
54
+  -outdir 
55
+        path to a target directory for the xlsx files (must exist and be writable)      
51 56
   -rows string
52 57
     	list of line numbers to use (1,2,8 or 1,3-14,28)
53 58
   -sheet string
... ...
@@ -143,9 +148,12 @@ I am still amazed what you can accomplish within less than 200 lines of code in
143 148
     2017-12-21 0.2
144 149
                 Added option --encoding
145 150
 
146
-    2017-06-20 0.3
151
+    2018-06-20 0.3
147 152
                 Added better version of ParseFloat to allow scientific number notation
148 153
 
154
+    2018-06-21 0.3.1
155
+                Added -filemask option to allow bulk processing
156
+
149 157
 
150 158
 ### License
151 159
 
+73 -8
csv2xlsx.go
... ...
@@ -24,6 +24,8 @@ var (
24 24
 	parmSheet           string
25 25
 	parmInFile          string
26 26
 	parmOutFile         string
27
+	parmOutDir          string
28
+	parmFileMask        string
27 29
 	parmEncoding        string
28 30
 	parmColSep          rune
29 31
 	parmDateFormat      string
... ...
@@ -133,6 +135,8 @@ func parseRangeString(rangeStr string) map[int]string {
133 135
 func parseCommandLine() {
134 136
 	flag.StringVar(&parmInFile, "infile", "", "full pathname of input file (CSV file)")
135 137
 	flag.StringVar(&parmOutFile, "outfile", "", "full pathname of output file (.xlsx file)")
138
+	flag.StringVar(&parmFileMask, "filemask", "", "file mask for bulk processing (overwrites -infile/-outfile)")
139
+	flag.StringVar(&parmOutDir, "outdir", "", "target directory for the .xlsx file (not to be used with outfile)")
136 140
 	flag.StringVar(&parmDateFormat, "dateformat", "2006-01-02", "format for CSV date cells (default YYYY-MM-DD)")
137 141
 	flag.StringVar(&parmExcelDateFormat, "exceldateformat", "", "Excel format for date cells (default as in Excel)")
138 142
 	flag.StringVar(&parmCols, "columns", "", "column range to use (see below)")
... ...
@@ -175,10 +179,18 @@ func parseCommandLine() {
175 179
 		`)
176 180
 		os.Exit(1)
177 181
 	}
178
-	if _, err := os.Stat(parmInFile); os.IsNotExist(err) {
179
-		fmt.Println("Input file does not exist, exiting.")
182
+
183
+	if parmOutFile != "" && parmOutDir != "" {
184
+		fmt.Println("Cannot use -outfile and -outdir together (-outdir to be used with -filemask), exiting.")
180 185
 		os.Exit(1)
181 186
 	}
187
+
188
+	if parmFileMask == "" {
189
+		if _, err := os.Stat(parmInFile); os.IsNotExist(err) {
190
+			fmt.Println("Input file does not exist, exiting.")
191
+			os.Exit(1)
192
+		}
193
+	}
182 194
 }
183 195
 
184 196
 // loadInputFile reads the complete input file into a matrix of strings.
... ...
@@ -407,11 +419,36 @@ func processDataColumns(excelRow *xlsx.Row, rownum int, csvLine []string) {
407 419
 	}
408 420
 }
409 421
 
410
-// the main entry function
411
-func main() {
412
-	// preflight stuff
413
-	parseCommandLine()
414
-	rows := loadInputFile(parmInFile)
422
+// getInputFiles retrieves a list of input files for a given filespec
423
+// returns a slice of strings or aborts the program on error
424
+func getInputFiles(inFileSpec string) []string {
425
+	files, err := filepath.Glob(inFileSpec)
426
+	if err != nil {
427
+		fmt.Println(err)
428
+		os.Exit(1)
429
+	}
430
+	return files
431
+}
432
+
433
+// buildOutputName generates the .xlsx file name for a given input file
434
+// if the user specified the -outdir option, use this directory as target path
435
+// return a string with the target file name
436
+func buildOutputName(infile string) string {
437
+	outfile := strings.TrimSuffix(infile, filepath.Ext(infile)) + ".xlsx"
438
+	if parmOutDir != "" {
439
+		if _, err := os.Stat(parmOutDir); err == nil {
440
+			outfile = filepath.Join(parmOutDir, filepath.Base(outfile))
441
+		} else {
442
+			fmt.Println(fmt.Sprintf("Output directory %q does not exist, exiting.", parmOutDir))
443
+			os.Exit(1)
444
+		}
445
+	}
446
+	return outfile
447
+}
448
+
449
+// convertFile does the conversion from CSV to Excel .xslx
450
+func convertFile(infile, outfile string) {
451
+	rows := loadInputFile(infile)
415 452
 	setRangeInformation(len(rows), len(rows[0]))
416 453
 
417 454
 	// excel stuff, create file, add worksheet, define a right-aligned style
... ...
@@ -429,5 +466,33 @@ func main() {
429 466
 			processDataColumns(excelRow, rownum, line)
430 467
 		}
431 468
 	}
432
-	workBook.Save(parmOutFile)
469
+	err := workBook.Save(outfile)
470
+	if err != nil {
471
+		fmt.Println(err)
472
+		os.Exit(1)
473
+	}
474
+}
475
+
476
+// the main entry function
477
+func main() {
478
+	// preflight stuff
479
+	var fileList []string
480
+	parseCommandLine()
481
+
482
+	// either glob the file mask or retrieve the single input file
483
+	// this way we can just iterate over the slice (and maybe later
484
+	// add an option for a specified list of files)
485
+	if parmFileMask != "" {
486
+		fmt.Println("Found -filemask parameter, running in bulk mode")
487
+		fileList = getInputFiles(parmFileMask)
488
+	} else {
489
+		fileList = getInputFiles(parmInFile)
490
+	}
491
+
492
+	// iterate over list of files to process and convert them
493
+	for _, infile := range fileList {
494
+		outfile := buildOutputName(infile)
495
+		fmt.Println("Converting", infile, "=>", outfile)
496
+		convertFile(infile, outfile)
497
+	}
433 498
 }
BIN
csv2xlsx_386.exe
Binary file not shown.
BIN
csv2xlsx_amd64.exe
Binary file not shown.
BIN
csv2xlsx_linux_386
Binary file not shown.
BIN
csv2xlsx_linux_amd64
Binary file not shown.
BIN
csv2xlsx_osx
Binary file not shown.