patterngoMinor
Fetching files or directories in a given directory
Viewed 0 times
directoryfilesfetchinggivendirectories
Problem
This is a self-teaching implementation to get files for a given directory in order to simplify
I'm pretty new to the language and feel there is already something wrong with
the way the structure ""implements"" the interface. I feel that it should not be by value but rather by reference in order to avoid redundant copies, should it?
```
package main
import (
"os"
"fmt"
"path/filepath"
"time"
)
type FileDetail interface {
Path() string
Info() os.FileInfo
}
type fileDetail struct{
path string
info os.FileInfo
}
func (detail fileDetail) Path() string {
return detail.path
}
func (detail *ileDetail) Info() os.FileInfo {
return detail.info
}
func GetFiles(path string) []FileDetail {
var details []FileDetail
walkFunc := func (filePath string, fileInfo os.FileInfo, err error) error {
if err != nil {
return err
}
if !fileInfo.IsDir() {
var detail FileDetail = fileDetail{path: filePath, info: fileInfo}
details = append(details, detail)
}
return nil
}
filepath.Walk(path, walkFunc)
return details
}
func GetDirectories(path string) []FileDetail {
var details []FileDetail
walkFunc := func (filePath string, fileInfo os.FileInfo, err error) error {
if err != nil {
return err
}
if fileInfo.IsDir() {
var detail FileDetail = fileDetail{path: filePath, info: fileInfo}
details = append(details, detail)
}
return nil
}
filepath.Walk(path, walkFunc)
return details
}
func main() {
sandBoxDirectory := "F:/Perforce/eperret/XLC/R6Code/framework/source/scimitar/onlinemodule/Sandbox"
time.Now()
files := GetFiles(sandBoxDirectory)
for index, file := range files {
fileInfo := file.Info()
fmt.Println(index, file.Path())
os.Walk in Go (avoid to pass a func for recursively walking across the files and directories).I'm pretty new to the language and feel there is already something wrong with
the way the structure ""implements"" the interface. I feel that it should not be by value but rather by reference in order to avoid redundant copies, should it?
```
package main
import (
"os"
"fmt"
"path/filepath"
"time"
)
type FileDetail interface {
Path() string
Info() os.FileInfo
}
type fileDetail struct{
path string
info os.FileInfo
}
func (detail fileDetail) Path() string {
return detail.path
}
func (detail *ileDetail) Info() os.FileInfo {
return detail.info
}
func GetFiles(path string) []FileDetail {
var details []FileDetail
walkFunc := func (filePath string, fileInfo os.FileInfo, err error) error {
if err != nil {
return err
}
if !fileInfo.IsDir() {
var detail FileDetail = fileDetail{path: filePath, info: fileInfo}
details = append(details, detail)
}
return nil
}
filepath.Walk(path, walkFunc)
return details
}
func GetDirectories(path string) []FileDetail {
var details []FileDetail
walkFunc := func (filePath string, fileInfo os.FileInfo, err error) error {
if err != nil {
return err
}
if fileInfo.IsDir() {
var detail FileDetail = fileDetail{path: filePath, info: fileInfo}
details = append(details, detail)
}
return nil
}
filepath.Walk(path, walkFunc)
return details
}
func main() {
sandBoxDirectory := "F:/Perforce/eperret/XLC/R6Code/framework/source/scimitar/onlinemodule/Sandbox"
time.Now()
files := GetFiles(sandBoxDirectory)
for index, file := range files {
fileInfo := file.Info()
fmt.Println(index, file.Path())
Solution
Let's compare your two methods
This is a classic case where copy&paste code is a problem. How can this be simplified? In Go, a good use-case will be a "file test" function that returns true if a file passes a test. Consider the "general purpose" private function that takes a "test" function as an input:
Now, you can reuse that in your directories and files lists with:
Now you can also easily add interesting checks on file names, permissions, etc.
I realize that the interface
As for the implementation of the interface, it's not horrible. Your concerns about the pointers is not really valid since all the data is small, and static.
It's OK in Go default to real data structures where the data is copied around, the memory cost is considered trivial.
GetFiles and GetDirectories:func GetFiles(path string) []FileDetail {
var details []FileDetail
walkFunc := func (filePath string, fileInfo os.FileInfo, err error) error {
if err != nil {
return err
}
if !fileInfo.IsDir() {
var detail FileDetail = fileDetail{path: filePath, info: fileInfo}
details = append(details, detail)
}
return nil
}
filepath.Walk(path, walkFunc)
return details
}
func GetDirectories(path string) []FileDetail {
var details []FileDetail
walkFunc := func (filePath string, fileInfo os.FileInfo, err error) error {
if err != nil {
return err
}
if fileInfo.IsDir() {
var detail FileDetail = fileDetail{path: filePath, info: fileInfo}
details = append(details, detail)
}
return nil
}
filepath.Walk(path, walkFunc)
return details
}This is a classic case where copy&paste code is a problem. How can this be simplified? In Go, a good use-case will be a "file test" function that returns true if a file passes a test. Consider the "general purpose" private function that takes a "test" function as an input:
func filterFiles(path string, test func(os.FileInfo) bool) []FileDetail {
var details []FileDetail
walkFunc := func (filePath string, fileInfo os.FileInfo, err error) error {
if err != nil {
return err
}
if test(fileInfo) {
var detail FileDetail = fileDetail{path: filePath, info: fileInfo}
details = append(details, detail)
}
return nil
}
filepath.Walk(path, walkFunc)
return details
}Now, you can reuse that in your directories and files lists with:
func GetFiles(path string) []FileDetail {
return filterFiles(path, func(file os.FileInfo) bool {
return !file.IsDir()
})
}
func GetDirectories(path string) []FileDetail {
return filterFiles(path, func(file os.FileInfo) bool {
return file.IsDir()
})
}Now you can also easily add interesting checks on file names, permissions, etc.
I realize that the interface
FileDetail is there to teach you how they work, but in this instance, the interface is overkill, and I'd just keep things as a struct and move on.As for the implementation of the interface, it's not horrible. Your concerns about the pointers is not really valid since all the data is small, and static.
It's OK in Go default to real data structures where the data is copied around, the memory cost is considered trivial.
Code Snippets
func GetFiles(path string) []FileDetail {
var details []FileDetail
walkFunc := func (filePath string, fileInfo os.FileInfo, err error) error {
if err != nil {
return err
}
if !fileInfo.IsDir() {
var detail FileDetail = fileDetail{path: filePath, info: fileInfo}
details = append(details, detail)
}
return nil
}
filepath.Walk(path, walkFunc)
return details
}
func GetDirectories(path string) []FileDetail {
var details []FileDetail
walkFunc := func (filePath string, fileInfo os.FileInfo, err error) error {
if err != nil {
return err
}
if fileInfo.IsDir() {
var detail FileDetail = fileDetail{path: filePath, info: fileInfo}
details = append(details, detail)
}
return nil
}
filepath.Walk(path, walkFunc)
return details
}func filterFiles(path string, test func(os.FileInfo) bool) []FileDetail {
var details []FileDetail
walkFunc := func (filePath string, fileInfo os.FileInfo, err error) error {
if err != nil {
return err
}
if test(fileInfo) {
var detail FileDetail = fileDetail{path: filePath, info: fileInfo}
details = append(details, detail)
}
return nil
}
filepath.Walk(path, walkFunc)
return details
}func GetFiles(path string) []FileDetail {
return filterFiles(path, func(file os.FileInfo) bool {
return !file.IsDir()
})
}
func GetDirectories(path string) []FileDetail {
return filterFiles(path, func(file os.FileInfo) bool {
return file.IsDir()
})
}Context
StackExchange Code Review Q#160560, answer score: 4
Revisions (0)
No revisions yet.