|
1 | 1 | package csvtag |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "bytes" |
4 | 5 | "encoding/csv" |
5 | 6 | "fmt" |
6 | 7 | "io" |
@@ -113,6 +114,8 @@ func LoadFromString(str string, destination interface{}, options ...CsvOptions) |
113 | 114 | // @param separator: the separator used in the csv file. |
114 | 115 | // @param header: the optional header if the file does not contain one. |
115 | 116 | func readFile(file io.Reader, separator rune, header []string) ([]string, [][]string, error) { |
| 117 | + file = skipBOM(file) |
| 118 | + |
116 | 119 | // Create and configure the csv reader. |
117 | 120 | reader := csv.NewReader(file) |
118 | 121 | reader.TrimLeadingSpace = true |
@@ -141,6 +144,24 @@ func readFile(file io.Reader, separator rune, header []string) ([]string, [][]st |
141 | 144 | return header, content, nil |
142 | 145 | } |
143 | 146 |
|
| 147 | +// Skip the Byte Order Mark (BOM) if it exists. |
| 148 | +// @param file: the io.Reader to read from. |
| 149 | +func skipBOM(file io.Reader) io.Reader { |
| 150 | + // Read the first 3 bytes. |
| 151 | + bom := make([]byte, 3) |
| 152 | + _, err := file.Read(bom) |
| 153 | + if err != nil { |
| 154 | + return file |
| 155 | + } |
| 156 | + |
| 157 | + // If the first 3 bytes are not the BOM, reset the reader. |
| 158 | + if bom[0] != 0xEF || bom[1] != 0xBB || bom[2] != 0xBF { |
| 159 | + return io.MultiReader(bytes.NewReader(bom), file) |
| 160 | + } |
| 161 | + |
| 162 | + return file |
| 163 | +} |
| 164 | + |
144 | 165 | // Map the provided content to the destination using the header and the tags. |
145 | 166 | // @param header: the csv header to match with the struct's tags. |
146 | 167 | // @param content: the content to put in destination. |
|
0 commit comments