github.com/vertgenlab/gonomics@v1.0.0/fileio/easyio.go (about) 1 package fileio 2 3 import ( 4 "bufio" 5 "compress/gzip" 6 "fmt" 7 "io" 8 "log" 9 "os" 10 "strings" 11 12 "github.com/vertgenlab/gonomics/exception" 13 ) 14 15 // EasyReader provides a simplified wrapper of the builtin golang io functions. 16 // Will silently handle reading gziped files. EasyReader is a valid io.Reader. 17 type EasyReader struct { 18 File *os.File 19 internalGzip *gzip.Reader 20 BuffReader *bufio.Reader 21 } 22 23 // EasyWriter provides a simplified wrapper of the builtin golang io functions. 24 // Will silently gzip output files when the input filename ends with '.gz'. 25 // EasyWriter is a valid io.Writer. 26 type EasyWriter struct { 27 file *os.File 28 internalBuff *bufio.Writer 29 internalGzip *gzip.Writer 30 } 31 32 // EasyOpen opens the input file. Panics if errors are encountered. 33 func EasyOpen(filename string) *EasyReader { 34 if strings.Contains(filename, "http") { 35 return EasyHttp(filename) 36 } 37 38 answer := EasyReader{} 39 var hasMagicGzip bool 40 var readerInput io.Reader 41 42 if strings.HasPrefix(filename, "stdin") { 43 // when reading stdin we will assume the input is gzipped 44 // if the file begins with the two magic gzip bytes 1f8d. 45 // If it does, append .gz to the filename so it is parsed 46 // as gzip in the following switch case. 47 answer.File = os.Stdin 48 readerInput, hasMagicGzip = newStdinMagicReader(magicGzip) 49 if hasMagicGzip { 50 filename += ".gz" 51 } 52 } else { 53 answer.File = MustOpen(filename) 54 hasMagicGzip = IsGzip(answer.File) 55 readerInput = answer.File 56 } 57 58 var err error 59 switch { 60 case strings.HasSuffix(filename, ".gz") && hasMagicGzip: 61 answer.internalGzip, err = gzip.NewReader(readerInput) 62 exception.PanicOnErr(err) 63 answer.BuffReader = bufio.NewReader(answer.internalGzip) 64 65 case strings.HasSuffix(filename, ".gz"): 66 log.Fatalf("ERROR: input file '%s' has the .gz suffix, but is not a gzip file", filename) 67 68 case hasMagicGzip: 69 log.Printf("WARNING: The input file '%s' looks like it may be gzipped, "+ 70 "but does not have the .gz suffix. Processing as a non-gzip file. Add the .gz "+ 71 "suffix to process as a gzip file.", filename) 72 fallthrough 73 74 default: 75 answer.BuffReader = bufio.NewReader(readerInput) 76 } 77 78 return &answer 79 } 80 81 // EasyCreate creates a file with the input name. Panics if errors are encountered. 82 func EasyCreate(filename string) *EasyWriter { 83 answer := EasyWriter{} 84 85 switch { 86 case strings.HasPrefix(filename, "stdout"): 87 answer.file = os.Stdout 88 case strings.HasPrefix(filename, "stderr"): 89 answer.file = os.Stderr 90 default: 91 answer.file = MustCreate(filename) 92 } 93 94 answer.internalBuff = bufio.NewWriter(answer.file) 95 96 if strings.HasSuffix(filename, ".gz") { 97 answer.internalGzip = gzip.NewWriter(answer.internalBuff) 98 } else { 99 answer.internalGzip = nil 100 } 101 return &answer 102 } 103 104 // EasyNextLine returns the next line of the input EasyReader. 105 // Returns true at EOF. 106 func EasyNextLine(file *EasyReader) (string, bool) { 107 return NextLine(file.BuffReader) 108 } 109 110 // EasyNextRealLine returns the next line of the input EasyReader that does not begin with '#'. 111 // Returns true at EOF. 112 func EasyNextRealLine(file *EasyReader) (string, bool) { 113 return NextRealLine(file.BuffReader) 114 } 115 116 // EasyPeekReal will advance a reader past any lines beginning with '#' and read the first n bytes without advancing the reader. 117 func EasyPeekReal(file *EasyReader, n int) ([]byte, error) { 118 return PeekReal(file.BuffReader, n) 119 } 120 121 // EasyReadHeader will read any leading comments lines from the file and return them as a slice of strings 122 // with each element in the slice being a comment line. 123 func EasyReadHeader(file *EasyReader) ([]string, error) { 124 return ReadHeader(file.BuffReader) 125 } 126 127 // EasyRemove deletes the input file. 128 func EasyRemove(filename string) { 129 MustRemove(filename) 130 } 131 132 // Read inputs a file and returns each line in the file as a string. 133 func Read(filename string) []string { 134 var answer []string 135 var err error 136 file := EasyOpen(filename) 137 reader := bufio.NewReader(file) 138 for line, doneReading := NextRealLine(reader); !doneReading; line, doneReading = NextRealLine(reader) { 139 answer = append(answer, line) 140 } 141 err = file.Close() 142 exception.PanicOnErr(err) 143 return answer 144 } 145 146 // WriteToFileHandle will write a string to an io.Writer and panic on 147 // any error. 148 func WriteToFileHandle(file io.Writer, rec string) { 149 var err error 150 _, err = fmt.Fprintf(file, "%s\n", rec) 151 exception.PanicOnErr(err) 152 } 153 154 // Write writes a slice of strings to a file with a newline 155 // placed after each element of the slice. 156 func Write(filename string, records []string) { 157 var err error 158 file := EasyCreate(filename) 159 160 for i := range records { 161 WriteToFileHandle(file, records[i]) 162 } 163 err = file.Close() 164 exception.PanicOnErr(err) 165 }