Как получить список файлов и папок в директории на Go? (ioutil.ReadDir vs os.ReadDir)
Правильный способ: используем os.ReadDir (Go 1.16+)
Начиная с Go 1.16, пакет ioutil объявлен устаревшим (deprecated). Вместо него рекомендуется использовать функции из пакетов os и io. Для чтения содержимого директории теперь есть две основные функции: os.ReadDir и os.ReadFile (вместо ioutil.ReadFile).
Вот минимальный, современный и корректный пример получения списка файлов и папок:
package main
import (
"fmt"
"log"
"os"
)
func main() {
entries, err := os.ReadDir(".")
if err != nil {
log.Fatal(err)
}
for _, entry := range entries {
fmt.Println(entry.Name())
}
}
Ключевые отличия os.ReadDir от старого ioutil.ReadDir
- Тип возвращаемого значения:
os.ReadDirвозвращает срез[]os.DirEntry, а не[]os.FileInfo.DirEntry— это более лёгкий интерфейс, который не загружает полную информацию о файле (размер, права доступа и т.д.), пока вы это явно не запросите. - Производительность:
os.ReadDirработает быстрее, так как не делает лишних системных вызововstatдля каждого элемента. - Использование памяти:
DirEntryзанимает меньше памяти, чемFileInfo.
Как отличить файл от папки?
Используйте метод IsDir() у DirEntry:
for _, entry := range entries {
if entry.IsDir() {
fmt.Printf("[DIR] %s\n", entry.Name())
} else {
fmt.Printf("[FILE] %s\n", entry.Name())
}
}
Как получить полную информацию о файле (размер, дата изменения)?
Если вам нужны метаданные (размер, время модификации, права доступа), вызовите entry.Info():
for _, entry := range entries {
info, err := entry.Info()
if err != nil {
log.Printf("Ошибка получения информации о %s: %v", entry.Name(), err)
continue
}
fmt.Printf("%s — размер: %d байт, изменён: %v\n",
entry.Name(), info.Size(), info.ModTime())
}
Сортировка результатов
os.ReadDir не гарантирует порядок элементов. Если вам нужна сортировка по имени, используйте sort.Slice:
import "sort"
entries, _ := os.ReadDir(".")
sort.Slice(entries, func(i, j int) bool {
return entries[i].Name() < entries[j].Name()
})
Когда использовать filepath.Walk?
Функция filepath.Walk (или filepath.WalkDir в Go 1.16+) предназначена для рекурсивного обхода всех поддиректорий. Если вам нужно только содержимое одной папки (без вложенных), используйте os.ReadDir.
// Рекурсивный обход всех файлов и папок
err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
fmt.Println(path)
return nil
})
Полный пример с обработкой ошибок и фильтрацией
package main
import (
"fmt"
"log"
"os"
"sort"
"strings"
)
func main() {
dir := "." // можно заменить на любую папку
entries, err := os.ReadDir(dir)
if err != nil {
log.Fatalf("Не удалось прочитать директорию %s: %v", dir, err)
}
// Сортируем по имени
sort.Slice(entries, func(i, j int) bool {
return entries[i].Name() < entries[j].Name()
})
fmt.Printf("Содержимое папки '%s':\n", dir)
fmt.Println(strings.Repeat("-", 40))
for _, entry := range entries {
if entry.IsDir() {
fmt.Printf("📁 %s/\n", entry.Name())
} else {
info, _ := entry.Info()
fmt.Printf("📄 %s (%d байт)\n", entry.Name(), info.Size())
}
}
}
Итог: начиная с Go 1.16 всегда используйте os.ReadDir для чтения содержимого одной директории. Это быстрее, современнее и соответствует рекомендациям разработчиков Go.
Альтернативный подход: os.Open + Readdir
Если вам нужен более тонкий контроль над процессом чтения (например, чтение порциями или работа с файловым дескриптором), можно использовать низкоуровневый способ через os.File.Readdir:
package main
import (
"fmt"
"log"
"os"
)
func main() {
f, err := os.Open(".")
if err != nil {
log.Fatal(err)
}
defer f.Close()
// Читаем не более 10 записей за раз
for {
entries, err := f.Readdir(10)
if err != nil {
break // конец директории или ошибка
}
for _, entry := range entries {
fmt.Println(entry.Name())
}
}
}
Этот метод возвращает []os.FileInfo (не DirEntry), поэтому он менее эффективен, но может быть полезен для очень больших директорий, когда вы хотите читать данные частями, чтобы не держать всё в памяти.
Важно: f.Readdir(n) с параметром n <= 0 читает все записи сразу, что эквивалентно ioutil.ReadDir. Передавайте положительное число для постраничного чтения.
Дополнительный совет: Если вам нужно только количество файлов или проверить, пуста ли папка, можно использовать os.ReadDir и проверить длину среза. Это проще и читаемее.
Ответов пока нет.
Войдите чтобы оставить ответ