added -filemask parameter to allow bulk conversions...
..., some refactoring
| ... | ... |
@@ -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 |
|
| ... | ... |
@@ -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 |
} |