в Excel - Сбор данных из однотипных файлов по именам папок, в которых они находятся

Весь MS Office, программирование на Visual Basic for Applications и MS VB

Модератор: Naeel Maqsudov

pashulka
Сообщения: 831
Зарегистрирован: 24 ноя 2004, 03:46
Контактная информация:

05 мар 2014, 22:18

Вообще-то речь шла о том, чтобы выложить только сводный файл, причём без финансовой конкретики, но если Вы не хотите облегчить жизнь людям, которые пытаются Вам помочь :( то вот один из примеров извлечения данных, где часть пути (название каталога) хранится в ячейке B1 первого рабочего листа текущей рабочей книги.

Код: Выделить всё

Private Sub Test()

    Dim iPath$, iFormula$
    
    iPath = ThisWorkbook.Worksheets(1).Range("B1")
    iFormula = "='W:\Документы\" & iPath & "\[Карточка.xlsx]Карточка'!A1"
    
    With ThisWorkbook.Worksheets(1).Range("A1")
         .Formula = iFormula
         .Value = .Value
    End With
    
End Sub
Герман
Сообщения: 10
Зарегистрирован: 01 мар 2014, 12:09

06 мар 2014, 13:23

somewhere писал(а):1. Составляем список найденых файлов вместе с полным путем
2. Unzip xlsx
3. xl\worksheets\sheet1.xml (или другой нужный лист)
4. Смотрим содержимое нужной ячейки
5. Записываем в нужную ячейку каталога

Не знаю насчет макросов на VBA, но на других языках вполне реально. Причем скорость работы будет в десятки раз быстрее, нежели юзать Workbooks(filename).Activate/Open/Close, которые по нескольку секунд один файл открывают и это только ради одной ячейки)
Для отладки все равно нужна конкретная структура
Ну, смысл-то да - такой (я только про Unzip xlsx не понял). Вопрос как мышке стать ежиком? И разумеется, что ни одна, а несколько ячеек будут вытягиваться - но для VBA я и сам по аналогии смог бы дополнить, а ести там С++ то конечно не осилю. Если вопрос только в структуре, я готов файлы сбросить, с пояснением разумеется, что в какой папке должно находиться. Вообще там задача конечно сложнее - я просто не хотел перегружать вопрос, расчитывал сам доработать (если на VBA конечно).

А так, если прямо программными средствами, так может есть возможность тогда сразу функцию по аналогии с "Morefunc"-овской =INDIRECT.EXT() сделать, но чтоб по 64-бит шла? Вам бы юзеры, вроде меня памятник при жизни поставили.
Герман
Сообщения: 10
Зарегистрирован: 01 мар 2014, 12:09

06 мар 2014, 13:31

pashulka писал(а):Вообще-то речь шла о том, чтобы выложить только сводный файл, ... , но если Вы не хотите облегчить жизнь людям, которые пытаются Вам помочь :( .
...
End Sub[/code]

Ой, ну Вы чего, я ж не думал, что только сводный... просто он простой до опупения.

Прицепил Ваш пример, буквально с мизерными правками и Вуаля - работает!!! Спасибо!!!

Мне теперь только цикл сделать, чтоб выгружал в iPath начиная с B1 до пока на пустую ячейку в столбце В не наткнется. Ну и привязать к событию, чтоб макрос запускался при открытии (где-то видел).
Если поможете, чтоб не запутался, - с меня еще литр пива, - а нет, так и без того спасибо агромадное!
Аватара пользователя
somewhere
Сообщения: 1837
Зарегистрирован: 31 авг 2006, 17:14
Откуда: 71 RUS
Контактная информация:

06 мар 2014, 14:27

(я только про Unzip xlsx не понял)
Xlsx файл - это упакованая в zip-архив структура XML-файлов. Соответственно, чтобы вытащить данные из конкретного листа файла, нужно распаковать XLSX в память и найти файл, который хранит данные листа (возможно и файл с общими строками). Не смотря на кажущуюся громоздкость, операция очень быстрая и не сравнится с методами VBA, которые запускают отдельный процесс Excel для открытия данных листа.
То есть, если у вас 100 файлов, то для сбора информации с них методами VBA нужно 100 раз запустить Excel, а это дело может занять десятки минут даже на относительно быстрых компьютерах.
А вообще, я бы подумал организовать такую работу, как сбор данных - средствами хотя бы MS Access. Соответственно вся ваша задача сведется к выполнению одного запроса, который с помощью связи отобразится а в ячейках Excel
It's a long way to the top if you wanna rock'n'roll
Герман
Сообщения: 10
Зарегистрирован: 01 мар 2014, 12:09

06 мар 2014, 15:31

somewhere писал(а):Xlsx файл - это упакованая в zip-архив структура XML-файлов. ...
А вообще, я бы подумал организовать такую работу, как сбор данных - средствами хотя бы MS Access. Соответственно вся ваша задача сведется к выполнению одного запроса, который с помощью связи отобразится а в ячейках Excel

Спасибо за консультацию, про свойства Xlsx файла я действительно не знал.

А насчет Access я думал. Я на нем б.м. умею строить, но тут у нас нет возможности прописать один раз запрос, поскольку файлы "Карточки" постоянно добавляются и добавляются в новые места (подпапки с заранее не определенным именем). Может и существует способ формирования такого динамического запроса, но это пожалуй выше моего уровня.

Насчет функции аналога =INDIRECT.EXT() не думали ;) .
Полагаю это действительно сложно, потому что мои поиски аналога в других наборах не увенчались успехом, да и Morefunc от Excel MVP давно не обновляется (последняя версия под 32-бит Эксель 2007) - значит не такое уж это простое дело.
pashulka
Сообщения: 831
Зарегистрирован: 24 ноя 2004, 03:46
Контактная информация:

06 мар 2014, 19:03

В цикле это может быть, например, так :

Модуль ThisWorkbook(ЭтаКнига)

Код: Выделить всё

Private Sub Workbook_Open()
    With Application
         .ScreenUpdating = False
         .DisplayAlerts = False
         .Calculation = xlManual
    End With
    
    Dim iCell As Range
    With Me.Worksheets(1) 'ThisWorkbook.Worksheets(1)
         For Each iCell In .Range(.Cells(1, "B"), .Cells(1, "B").End(xlDown))
             With iCell.Offset(, 1)
                  .Formula = "='W:\Документы\" & iCell.Value & "\[Карточка.xlsx]Карточка'!A1"
                  .Value = .Value
             End With
         Next
    End With
    
    With Application
         .Calculation = xlAutomatic
         .DisplayAlerts = True
         .ScreenUpdating = True
    End With
End Sub
Герман
Сообщения: 10
Зарегистрирован: 01 мар 2014, 12:09

06 мар 2014, 22:03

pashulka писал(а):В цикле это может быть, например, так :
...

Искреннее человеческое спасибо - завтра буду разбираться - уверен, все получится.
А Вы не в Киеве случайно проживаете? - насчет пива я не шутил. :)

Если позволите, еще вопрос, по поводу подсказанной вами функции =INDIRECT.EXT() от "Morefunc". Я кажется нашел макрос, который по слухам был положен в основу этой функции. Вот здесь можно скачать .xla файл, в котором она прописана в модуле: http://www.4shared.com/file/L_eA8s4G/pull.html
А вот здесь (там листинг тоже есть, но копируется с ошибками) активно обсуждают ее нюансы: http://numbermonger.com/2012/02/11/exce ... workbooks/
Моих знаний, к сожалению, не достаточно, чтоб эти нюансы понять (и главное не связаны ли отказы с моими 64-бит). Щас буду еще пробовать, но почему-то почти уверен, что без доработок точно не пойдет.
Если Вам эта тема не обрыдла, скажите, пожалуйста, что Вы думаете по этому поводу.
Герман
Сообщения: 10
Зарегистрирован: 01 мар 2014, 12:09

06 мар 2014, 22:36

pashulka писал(а):В цикле это может быть, например, так :
....

Странно, не выгрузился в ветку мой предыдущий ответ. Не буду повторяться, остановлюсь на главном: во-первых, все работает, во-вторых, в Киеве два литра пива ждут Вас с моими искренними благодарностями в комплекте (идентификация по E-mail) :) .

Еще раз, огромное спасибо.
zidane
Сообщения: 1
Зарегистрирован: 08 июн 2015, 16:52

08 июн 2015, 16:58

Всем привет.
У меня аналогичная задача.. нужно свести в таблицу значения из разных книг, которые находятся в разных папках, и папки каждый день добавляются, как и книги в них...
Хотелось бы следующее...
В таблицу нужно заполнить данные исходя из номеров в столбце например A1, там будут указанны номера 001, 002, 003 и тд. Исходя из первой ячейки должны заполняться следующие ячейки в строке сканируя определенный каталог на диске, с вложенными подпапками с названием таким же как первая ячейка. Ячейки которые должны заполняться всегда одинаковые, данные разные...
Например. В строке А325 ставлю номер 325, макрос находит файл с названием 325.xls в подпапках каталога "работа" и берет данные из нужных ячеек к примеру F55, H83, A5 (всегда статичны) и тд, и вставляет их в соответсвующие ячейки B1, C1, D2... и тд.
Заранее спасибо.
pashulka
Сообщения: 831
Зарегистрирован: 24 ноя 2004, 03:46
Контактная информация:

08 июн 2015, 22:41

Zidane, Если взять за образец файл "Пример_112.rar", который Вы разбросали на других форумах и разместить нижеопубликованный макрос в рабочей книге "Отчет_.xlsm" , то :

Код: Выделить всё

'http://allapi.mentalis.org/apilist/SearchTreeForFile.shtml

Private Declare Function SearchTreeForFile _
        Lib "imagehlp.dll" ( _
        ByVal RootPath As String, _
        ByVal InputPathName As String, _
        ByVal OutputPathBuffer As String) As Long

Private Sub Test()
    With Application
         .ScreenUpdating = False
         .DisplayAlerts = False
         .Calculation = xlManual
    End With
   
    Dim iSource As Range, iCell As Range
    Dim iPath$, iFileName1$, iFileName2$, iAddress$, iCount%
    
    iPath = ThisWorkbook.Path 'Можно указать 'родительскую' папку самостоятельно
    
    With ThisWorkbook.Worksheets(1)
         Set iSource = .Range(.Cells(1, "A"), .Cells(.Rows.Count, "A").End(xlUp))
         'Set iSource = .[A:A].SpecialCells(xlConstants, xlNumbers)
    End With
         
    For Each iCell In iSource
        iFileName1 = iCell & ".xlsx": iFileName2 = Space(255)
        
        If SearchTreeForFile(iPath, iFileName1, iFileName2) <> 0 Then        
           iFileName2 = Application.Trim(iFileName2)
           iFileName2 = Replace(iFileName2, iFileName1, "[" & iFileName1 & "]", , , vbTextCompare)
           
           For iCount = 1 To 3
               iAddress = Choose(iCount, "F54", "H83", "A5")
               With iCell.Offset(, iCount)
                    .Formula = "='" & iFileName2 & "Лист1'!" & iAddress
                    .Value = .Value
                    'Возможно имеет смысл заменять формулы на значения, либо
                    'сразу в трёх ячейках строки, либо вообще во 'всём' диапазоне
               End With
           Next           
        Else
           iCell.Offset(, 1).Resize(, 3) = CVErr(xlErrNA) '#Н/Д
        End If
    Next
   
    With Application
         .Calculation = xlAutomatic
         .DisplayAlerts = True
         .ScreenUpdating = True
    End With
End Sub
Ответить