LINUX.ORG.RU

Rust рекурсивный обход дирректорий.

 


0

5

Вот необходимо обойти дерево каталогов и собрать пути к файлам. Без всяких сторонних библиотек и тд. Вопрос в следующем можно ли использовать для обхода обычную рекурсию, а результаты складировать в вектор, не вызовет ли это переполнение стека, где будет расти вектор в куче или в стеке? В принципе можно ли использовать рекурсию для обхода дерева на сколько это правильно? Псевдо код такой:

pub fn walk(path: dir) -> io::Result<()> {
    for i in dirs{
        if i=="dirs"{
            walk(i);
        }else {
            all_files.push(i);
        }
    }
}



Последнее исправление: Loafter (всего исправлений: 1)

В принципе можно ли использовать рекурсию для обхода дерева на сколько это правильно?

Можно, если дерево не слишком глубокое.

где будет расти вектор в куче или в стеке

В куче, конечно же.

quantum-troll ★★★★★
()
Ответ на: комментарий от quantum-troll

ну вот я прочел что размер стека около 5-9 мегабайт. ну вот получается что на каждой итерации съедается по несколько десятков байт на указатель IP в стэке, и передаваемые параметры. ну грубо 200 байт на каждую итерацию. Очень грубо уровень вложенности 350 000.

Loafter
() автор топика
Ответ на: комментарий от Loafter

Можно и на расте

extern crate failure;

use std::{
    path::Path,
    fs::metadata,
};

use failure::Error;

fn walk(root: impl AsRef<Path>, callback: impl Fn(&Path)) -> Result<(), Error> {
    let root = root.as_ref().to_path_buf();
    let mut tasks = vec![root];

    while let Some(path) = tasks.pop() {
        if path.is_file() {
            callback(&path);
        } else if path.is_dir() {
            for dir in read_dir(&path)? {
                tasks.push(dir?.path());
            }
        }
    }

    Ok(())
}

fn main() {
    walk("./", |path| println!("{:?}", path.display()))
        .unwrap();
}

mersinvald ★★★★★
()
Последнее исправление: mersinvald (всего исправлений: 1)

не вызовет ли это переполнение стека, где будет расти вектор в куче или в стеке

не знаю этих ваших рустов, но в сишечке и плюсплюсиках не переполняет же) Тамшуто глубина рекурсии не слишком велика - глубина вложенности в ф.с. определяется ограничением на длинну имени файла.

bonta ★★★★★
()
Ответ на: комментарий от quantum-troll

Можно, если дерево не слишком глубокое.

С учётом того, что у него дерево каталогов в ФС, я сильно сомневаюсь, что на практике может встретиться ситуация, когда возникнет переполнение стека. Ибо есть банальное ограничение на длину пути в ОС.

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 1)
Ответ на: комментарий от KivApple

Тамшуто глубина рекурсии не слишком велика - глубина вложенности в ф.с. определяется ограничением на длинну имени файла.

Ибо есть банальное ограничение на длину пути в ОС.

по пивку нам! ;)

bonta ★★★★★
()

Вот необходимо обойти дерево каталогов и собрать пути к файлам. Без всяких сторонних библиотек и тд. Вопрос в следующем можно ли использовать для обхода обычную рекурсию, а результаты складировать в вектор

Можно.

не вызовет ли это переполнение стека

Зависит от размера стека и максимальной вложенности каталогов.

где будет расти вектор в куче или в стеке

Вектор в куче, стек вызовов в стеке.

В принципе можно ли использовать рекурсию для обхода дерева на сколько это правильно?

Можно, но лучше не использовать. Рекурсию вообще лучше избегать.

Legioner ★★★★★
()
Ответ на: комментарий от Virtuos86

А я что-такое даже видел в rust для futures-rs. Но, наверное, не делают и широко не используют по той же причине, почему не добавили приличный сахарок для монад в scala (там какая-то лажа сейчас вместо такого сахарка). Или откровенно не понимают и не хотят, или достаточно тех средств, а часто откровенных костылей, что есть в наличии прямо сейчас. Или все даже проще: поезд ушел, менять язык уже никто не будет. Никто не будет исправлять старые ошибки в страхе потерять последователей, уже написавших кучу кода. Это же сколько воплей будет!)

В scala частенько вижу лапшу из комбинаторов для Future там, где можно было бы красиво написать, будь в scala реализована нормальная поддержка синтаксического сахара для монад (computation expressions добавляют такую поддержку и для моноидов тоже - то, что нужно нашему топикстартеру для итерируемых последовательностей). Одна поддержка try-catch в таком сахарке насколько бы сделала нагляднее и проще код, а без обработки ошибок «промышленный» код не пишут почти никогда.

dave ★★★★★
()
Последнее исправление: dave (всего исправлений: 1)
Ответ на: комментарий от dave

Вкусно рассказываешь, но пробовать набросать PoC я не возьмусь. Скиллов не хватит, а про свободное время вообще молчу — беда, а, как правило, когда уровень навыков не дотягивает до нужного, компенсировать это можно только диким вложением времени.

Ну а тебе лень, я так понимаю :).

Virtuos86 ★★★★★
()
Ответ на: комментарий от Legioner

Можно, но лучше не использовать. Рекурсию вообще лучше избегать.

В общем да. Но некоторые штуки (при условии безопасности от переполнения) лучше через рекурсию, т.к. как правило рекурсивный код проще

//хотя опять посмотрю я на раст и ни одной строчки не понятно, толи дело с c-like языками, зная один всегда поймешь о чём речь на другом

в posix есть очень удобная ф-я рекурсивного обхода - nftw

Удалить директорию полностью? Что может быть проще? )

    //метод рекурсивного удаления каталога
    bool FilesManager::removeDirectory(const char* path) noexcept
    {
    	auto fl = [](const char *file, const struct stat *_stat, int type, struct FTW * _ftw) -> int
    	{
    		return remove(file);
    	};
    	return (!nftw(path, fl, getdtablesize()/2, FTW_PHYS|FTW_DEPTH)) ? true: false;
    }

bonta ★★★★★
()
Ответ на: комментарий от RazrFalcon

так не интересно. Раст на расте же написан? интересно что внутри а так это тоже самое что FilesManager::removeDirectory(«/some/dir») - просто уже кто-то это написал а не руками писать пришлось)

кстати в коде выше можно было просто return nftw(....) т.к. он возвращает то что вернет коллбек. В итоге там тавталогия какая-то )

bonta ★★★★★
()
Ответ на: комментарий от bonta

возможно они там тоже в расте какую-нить стандартную посикс ф-ю юзают же?

bonta ★★★★★
()
Ответ на: комментарий от bonta

Разница в том, что этого готовое, протестированное, кроссплатформенное решение, а не велосипед.

RazrFalcon ★★★★★
()
Ответ на: комментарий от MyTrooName

посмотрел, но к сожалению не увидел там про рекурсию. Может глаза замылились. Расскажите подробнее пожалуйста.

bonta ★★★★★
()
Ответ на: комментарий от bonta

dirfd - это дескриптор директории. его использование снимает ограничение с длины пути к файлу, оставляя его только для pathname - то есть при правильном использовании, только для имени файла

MyTrooName ★★★★★
()
Ответ на: комментарий от MyTrooName

собственно, ты можешь проверить на практике:

for i in `seq 1 1000`
do
	mkdir "longpath$i" || exit $?
	cd "longpath$i" || exit $?
done

sh в debian-e на этом скрипте вылетает на 346-й итерации, bash-a я не дождался, а zsh довольно оперативно закончил всю 1000

MAXPATH у меня 4096 если что

MyTrooName ★★★★★
()
Последнее исправление: MyTrooName (всего исправлений: 1)
Ответ на: комментарий от MyTrooName

спасибо, не знал что можно писать файлы-папки, дальше чем maxpath

bonta ★★★★★
()
Ответ на: комментарий от bonta

В общем да. Но некоторые штуки (при условии безопасности от переполнения) лучше через рекурсию, т.к. как правило рекурсивный код проще

Бывает и такое, конечно, но проблема, когда код написали по-быстрому и забыли, а потом в боевом режиме он падает от пустякового переполнения стека это неприятно. Чтобы переполнить кучу, это надо серьёзно постараться да и там хотя бы шанс есть словить null от malloc-а, стек такого шанса не даёт. Написал ты код, рассчитывая на 8 мегабайт стека, а его запустили в треде с 500 кБ и приехали.

в posix есть очень удобная ф-я рекурсивного обхода - nftw

Удалить директорию полностью? Что может быть проще? )

Сомневаюсь, что она рекурсивная, если речь про реализацию, а так согласен, для подобных задач лучше всего использовать специализированные функции.

Legioner ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.