Pobieranie całego folderu lub na raz listy plików

0

Witam,

Nie znalazłem na razie niczego sensownego w "googlu".
Męczę się z tematem pobrania z wskazanej ścieżki do folderu listy zawartych w nim plików.
Próbowałem pobrać cały folder ale dostaję odmowę dostępu. Pojedyncze pliki bez problemu , dlatego cały ww folder spakowałem wcześniej do .zip i tu aplikacja już pozwoliła mi pobrać wskazany folder (rozumiem, że zip jest traktowany wówczas jako plik a nie folder. ). Ale to rozwiązanie odrzucił biznes.

Niestety we wskazanym pliku muszę pobrać nieznaną liczbę zip-ó. Więc szukam sensownego rozwiązania.

public IActionResult GetDocument(_path)
    {

        string files = _configuration.GetConnectionString("FileRepository");

        files = files[..^6];
        string path = files + _path;

        foreach (string file in Directory.GetFiles(path))
        {
            using var fileStream = new FileStream(file, FileMode.Open);

            byte[] fileArray = fileStream.ReadAsBytes();
            string fileName = Path.GetFileName(file);

            fileStream.Close();
            fileStream?.Dispose();

            File(fileArray, "application/force-download", fileName); // tu chciałem wymusić pobieranie kolejnego pliku z listy
        }
        return RedirectToAction("WskazanyWidok");

    }

Jeśli moglibyście pomóc co robię źle lub podpowiedzieć jak wymusić pobranie całego folderu byłbym zobowiązany.

1

Problemem nie jest tylko twój system, a przeglądarka też. Jak sobie wyobrażasz pobranie "folderu"? Nie ma czegoś takiego, bo folderów się nie pobiera. Możesz pobrać zawartość danego folderu, ale wtedy przeglądarka będzie pytać, czy zezwolić na pobieranie wielu plików, a użytkownik może kliknąć na "NIE" i nic z tym nie zrobisz. To samo nawet robią dyski w chmurze, np Google. Też nie da się pobrać kilku plików, bo Google je automatycznie zipuje.

0
AdamWox napisał(a):

Problemem nie jest tylko twój system, a przeglądarka też. Jak sobie wyobrażasz pobranie "folderu"? Nie ma czegoś takiego, bo folderów się nie pobiera. Możesz pobrać zawartość danego folderu, ale wtedy przeglądarka będzie pytać, czy zezwolić na pobieranie wielu plików, a użytkownik może kliknąć na "NIE" i nic z tym nie zrobisz. To samo nawet robią dyski w chmurze, np Google. Też nie da się pobrać kilku plików, bo Google je automatycznie zipuje.

Rozumiem, czy znasz może sposób, żeby w pętli wymusić pobranie kolejnych plików
tak jak wczytuje sobie w tym moim przykładowym kodzie?

2

Nie ma szans. Nie da się tego zrobić w MVC, czy WebAPI, bo requesty do backendu są na zasadzie pytanie => odpowiedź. Jeśli zwrócisz odpowiedź z pierwszym plikiem to drugi już nie wyjdzie, bo to "połączenie" się zakończyło. Masz dwa wyjścia

  1. Pętla po stronie frontu - odpytujesz backend tyle razy ile masz plików, za każdym razem inny plik jest zwracany
  2. Zipujesz listę plików i wysyłasz jako jeden zip
0
AdamWox napisał(a):

Nie ma szans. Nie da się tego zrobić w MVC, czy WebAPI, bo requesty do backendu są na zasadzie pytanie => odpowiedź. Jeśli zwrócisz odpowiedź z pierwszym plikiem to drugi już nie wyjdzie, bo to "połączenie" się zakończyło. Masz dwa wyjścia

  1. Pętla po stronie frontu - odpytujesz backend tyle razy ile masz plików, za każdym razem inny plik jest zwracany
  2. Zipujesz listę plików i wysyłasz jako jeden zip

Dziękuję za podpowiedź, decyzja padła na logikę pobierania w widoku. A nie cierpię dłubać we froncie. Rozumiem, że bez skryptu js lub jq się nie obędzie.

1

Moim zdaniem nie. Może się znajdzie ktoś mądrzejszy i zapropnuje inne rozwiązanie, ale sam fakt pobierania więcej niż jednego pliku jest w przeglądarce domyślnie zabronione.

0

Ok, nie mam czasu więc zacząłem dłubać w widoku, w którym będzie przycisk do pobierania.

A że nie znam się na tym to pokaże, czy o coś takiego chodziło?
Jeśli ktoś więcej coś ogarnia ze skryptów.

<button class="btn btn-primary btn-sm" type="button" id="GetDoc" onClick="GetDoc()">Pobierz</button>
function GetDoc() {
        $.ajax({
            type: 'POST',
            url: '/Ajax/getFileList',
            dataType: 'json',
            data: {
                _path: @Model.Path,
            },
            success: function (result) {
                
                GetFile(result);

            },

            error: function (ex) {
            }
        });


    }

//poniższy fragment dodałem bo nie trafiam w powyższą funkcję i testowałem też takie rozwiązanie, niestety też nie chce mi zadziałać
$('body').on('click', '#GetDoc', function () {

        GetDoc();  
    });


    function GetFile(result) {
        $.ajax({
            type: 'Get',
            url: '/Document/Download',
            dataType: 'json',
            data: {
                _path: result,
            },

            error: function (ex) {
            }
        });

    }
public JsonResult getFileList(string _path)
    {
        string files = _configuration.GetConnectionString("FileRepository");

        files = files[..^6];
        string path = files + _path;

        string[] file = Directory.GetFiles(path);

        return Json(file);
    }

// tu poniżej z innego kontrolera zarządzającego dokumentami
[HttpGet]
    public IActionResult Download(string _path)
    {
        string files = _configuration.GetConnectionString("FileRepository");

        files = files[..^6];

        string path = files + _path;
            
        using var fileStream = new FileStream(path, FileMode.Open);

        byte[] fileArray = fileStream.ReadAsBytes();
        string fileName = Path.GetFileName(path);

        fileStream.Close();
        fileStream?.Dispose();

        return File(fileArray, "application/force-download", fileName);
    }

    
0
10 100 111 napisał(a):

Ja zwróciłbym się bardziej tak jak napisał @AdamWox do spakowania całego folderu razem z plikami. Na pewno będzie to prostsze i dużo szybsze, a skoro robią tak "wielcy" gracze jak google czy dropbox to chyba najlepsze rozwiązanie, przynajmniej ja nie mogę sobie nic innego wyobrazić.

wskazał dwa rozwiązania ;)

Natomiast aż się uśmiechnąłem na Twój post, bo dokładnie tego samego argumentu użyłem o wielkich w Internecie :D
Niestety pomysł odrzucony.

0
AdamAdam_MF napisał(a):
10 100 111 napisał(a):

Ja zwróciłbym się bardziej tak jak napisał @AdamWox do spakowania całego folderu razem z plikami. Na pewno będzie to prostsze i dużo szybsze, a skoro robią tak "wielcy" gracze jak google czy dropbox to chyba najlepsze rozwiązanie, przynajmniej ja nie mogę sobie nic innego wyobrazić.

wskazał dwa rozwiązania ;)

Natomiast aż się uśmiechnąłem na Twój post, bo dokładnie tego samego argumentu użyłem o wielkich w Internecie :D
Niestety pomysł odrzucony.

wstyd się przyznać ale nie do końca doczytałem pierwszy post i dlatego napisałem tego swojego.. :(
Swoją drogą wracając do tematu, jeśli ściągniesz plik do tempa, wypakujesz go do pobranych, to w jaki sposób biznes pozna, że działa to w taki sposób?

0

Jeśli ktoś znający się na froncie mógłby zerknąć na ten mój nowy kod, lub może ktoś ma coś podobnego co mógłbym pożyczyć był bym zobowiązany

0

Da się pobrać wiele plików, ale jak ktoś ma w przeglądarce ustawione pytanie gdzie zapisać każdy plik, to będzie musiał na te pytania odpowiadać w tej ilości ile jest plików do przesłania.

No chyba, że zawiesi się po pierwszym pobraniu, w zależności od przeglądarki, w końcu ktoś mógłby nam 100 różnych śmieci pobrać podsyłając jakiś syfny link :>

Czyli albo na front zwracasz pliki w postaci url lub fetchem pobierasz bloby tych plików i z poziomu javascript tworzysz te obiekty i robisz .click(), to ztriggeruje download tego pliku, nie jestem akurat pewien co się stanie jak ztriggeruejsz wiele tych plików na raz, czy przeglądarka jakoś to zablokuje? możliwe że zależy jaka.
Teoretycznie sprawdzenie tego to kilka minut :>

0

Ok, ostatecznie nie mogę testować i zmieniać wątków. Mam coś takiego na razie

$('body').on('click', '#getDoc', function () {
        alert('ajax z listą');
        $.ajax({
            type: 'POST',
            url: '/Ajax/getFileList',
            dataType: 'json',
            data: {
                _path: $("#Path").val(),
            },
            success: function (result) {
                $.each(result, function (i, item) {

                    GetFile(item);


                });

            },

            error: function (ex) {
            }
        });
    });


    function GetFile(item) {
        alert('GetFile');
        $.ajax({
            type: 'GET',
            url: '/Document/DownloadAll',
            dataType: 'json',
            data: {
                _path: item,
            },
            success: function (result) {
                alert('zakończenie');

            },
            error: function (ex) {
            }
        });

    }

I te funkcje skryptowe działają, ale po dotarciu poniżem nie pobieram zadnego z plików

[HttpGet]
    public  IActionResult DownloadAll(string _path)
    {
        using var fileStream = new FileStream(_path, FileMode.Open);

        byte[] fileArray = fileStream.ReadAsBytes();
        string fileName = Path.GetFileName(_path);

        fileStream.Close();
        fileStream?.Dispose();

        return File(fileArray, "application/force-download", fileName);
    }

na break point miałem wrażenie, że ta metoda "DownloadAll" co chwila dostawała kolejne zlecenia od skryptu i w efekcie nie skończyła żadnej.
jakieś sugestie?

0

Aktualizacja!
w końcu zmontowałem coś działającego.

Podobnie jak wyżej mam zewnętrzny kontroler Ajax, który zwraca mi listę plików

A całą operację wykonuje mi pętla JS

$('body').on('click', '#getDoc', function () {

        $.ajax({
            type: 'POST',
            url: '/Ajax/getFileList',
            dataType: 'json',
            data: {
                _path: $("#Path").val(),
            },
            success: function (result) {
            var x = Object.keys(result).length;
                $.each(result, function (i, item) {
                    alert('Pobieranie pliku ' + (i + 1) + ' z ' + x);
                    
                    window.location = '/Document/DownloadAll?_path=' + item;
                    

                });

            },

            error: function (ex) {
            }
        });
    });

Działa, jedyne w czym miałem probem to musiałem pozostawić alert. Bo pętla wykonuje się czybciej niż metoda DownloadAll była w stanie zwrócić plik i w efekcie otrzymywałem tylko ostatni.
Zastanawiałem się tu nad jakimś rodzajem opóźniacza, ale jeśli coś na serwerze się przytnie to zamiast np 1,2,3,4,5 itd plików mogę otrzymać 1, 3, 4,5, 7 itd.

Jeśli użytkownik będzie musiał sobie klikać po każdym pliku to ładują się w porządku. I może kiedyś docenią, że chciałem im zrobić jeden zbiorczy plik :D

1 użytkowników online, w tym zalogowanych: 0, gości: 1