Стоит следующая задача. В папке у коллег собираются подпапки, в которых хранятся файлы, содержающие формы опросники. Уровней подпапок может быть от 1 до 5. Файлы опросники представляют собой стандартизированную форму, в которую респонденты вносят данные. Т.е. сам вид и структура форм не меняется. Но меняется порядок листов в книге и само название "Форма №" (см файлы вложения) сдвигается в рамках первой строки и 4го и 7го столбца.
Стоит задача написать макрос, который бы спрашивал, из какой корневой папки производить поиск файлов (в том числе в подпапках), идентифицировать в каждом файле (Файле-источнике) какой лист является какой формой (форма 1 или форма 2, ...), изымать данные (целый столбец) из соответствующего листа по порядку и вставлять транспонированно в файл-конечный.
Примеры файлов-источников и результат свода в приложении.
Нашел функцию, возвращающую путь к выбранной в диалоговом окне папке
[vba]
Код
Function GetFolderPath(Optional ByVal Title As String = "Выберите папку", _ Optional ByVal InitialPath As String = "c:\") As String ' функция выводит диалоговое окно выбора папки с заголовком Title, ' начиная обзор диска с папки InitialPath ' возвращает полный путь к выбранной папке, или пустую строку в случае отказа от выбора Dim PS As String: PS = Application.PathSeparator With Application.FileDialog(msoFileDialogFolderPicker) If Not Right$(InitialPath, 1) = PS Then InitialPath = InitialPath & PS .ButtonName = "Выбрать": .Title = Title: .InitialFileName = InitialPath If .Show <> -1 Then Exit Function GetFolderPath = .SelectedItems(1) If Not Right$(GetFolderPath, 1) = PS Then GetFolderPath = GetFolderPath & PS End With End Function
[/vba]
Ее результат использую для подмодуля
[vba]
Код
Sub GetAllFileNamesDict(FolderPath$, ByVal SearchDeep%, FSO, oDict1, oDict2) Dim oFile, oCurFolder, oSubFolder On Error Resume Next Set oCurFolder = FSO.GetFolder(FolderPath) If Not oCurFolder Is Nothing Then 'чтобы не зациклилось при рекурсивном вызове, когда нет подпапок и oSubFolder=Nothing Application.StatusBar = "Поиск в папке: " & FolderPath ' вывод пути к просматриваемой в текущий момент папке в строку состояния Excel For Each oFile In oCurFolder.Files ' перебираем все файлы в папке FolderPath With oFile oDict1.Item(oDict1.count + 1) = .Path oDict2.Item(oDict2.count + 1) = .Name End With Next oFile SearchDeep = SearchDeep - 1 ' один уровень поиска прошли If SearchDeep Then ' если надо искать в подпапках глубже For Each oSubFolder In oCurFolder.SubFolders ' перебираем все подпапки в папке FolderPath GetAllFileNamesDict oSubFolder.Path, SearchDeep, FSO, oDict1, oDict2 Next oSubFolder End If End If Set oFile = Nothing: Set oCurFolder = Nothing: Set oSubFolder = Nothing DoEvents ' чтобы можно было прервать слишком длинную рекурсию End Sub
[/vba]
Под модуль возвращает два словаря. В одном массив путей к файлам, во втором - имена. Пути затем использую для открытия в цикле файла, его название - для изъятия данных. Понимаю, что можно оптимизировать процесс, поэтому буду рад предложениям. Застрял на проблеме транспонирования. Решил вставлять поячеечно, но это очень замедляет процесс.
При оформлении постов используйте тэги!
Добрый день, форумчане.
Стоит следующая задача. В папке у коллег собираются подпапки, в которых хранятся файлы, содержающие формы опросники. Уровней подпапок может быть от 1 до 5. Файлы опросники представляют собой стандартизированную форму, в которую респонденты вносят данные. Т.е. сам вид и структура форм не меняется. Но меняется порядок листов в книге и само название "Форма №" (см файлы вложения) сдвигается в рамках первой строки и 4го и 7го столбца.
Стоит задача написать макрос, который бы спрашивал, из какой корневой папки производить поиск файлов (в том числе в подпапках), идентифицировать в каждом файле (Файле-источнике) какой лист является какой формой (форма 1 или форма 2, ...), изымать данные (целый столбец) из соответствующего листа по порядку и вставлять транспонированно в файл-конечный.
Примеры файлов-источников и результат свода в приложении.
Нашел функцию, возвращающую путь к выбранной в диалоговом окне папке
[vba]
Код
Function GetFolderPath(Optional ByVal Title As String = "Выберите папку", _ Optional ByVal InitialPath As String = "c:\") As String ' функция выводит диалоговое окно выбора папки с заголовком Title, ' начиная обзор диска с папки InitialPath ' возвращает полный путь к выбранной папке, или пустую строку в случае отказа от выбора Dim PS As String: PS = Application.PathSeparator With Application.FileDialog(msoFileDialogFolderPicker) If Not Right$(InitialPath, 1) = PS Then InitialPath = InitialPath & PS .ButtonName = "Выбрать": .Title = Title: .InitialFileName = InitialPath If .Show <> -1 Then Exit Function GetFolderPath = .SelectedItems(1) If Not Right$(GetFolderPath, 1) = PS Then GetFolderPath = GetFolderPath & PS End With End Function
[/vba]
Ее результат использую для подмодуля
[vba]
Код
Sub GetAllFileNamesDict(FolderPath$, ByVal SearchDeep%, FSO, oDict1, oDict2) Dim oFile, oCurFolder, oSubFolder On Error Resume Next Set oCurFolder = FSO.GetFolder(FolderPath) If Not oCurFolder Is Nothing Then 'чтобы не зациклилось при рекурсивном вызове, когда нет подпапок и oSubFolder=Nothing Application.StatusBar = "Поиск в папке: " & FolderPath ' вывод пути к просматриваемой в текущий момент папке в строку состояния Excel For Each oFile In oCurFolder.Files ' перебираем все файлы в папке FolderPath With oFile oDict1.Item(oDict1.count + 1) = .Path oDict2.Item(oDict2.count + 1) = .Name End With Next oFile SearchDeep = SearchDeep - 1 ' один уровень поиска прошли If SearchDeep Then ' если надо искать в подпапках глубже For Each oSubFolder In oCurFolder.SubFolders ' перебираем все подпапки в папке FolderPath GetAllFileNamesDict oSubFolder.Path, SearchDeep, FSO, oDict1, oDict2 Next oSubFolder End If End If Set oFile = Nothing: Set oCurFolder = Nothing: Set oSubFolder = Nothing DoEvents ' чтобы можно было прервать слишком длинную рекурсию End Sub
[/vba]
Под модуль возвращает два словаря. В одном массив путей к файлам, во втором - имена. Пути затем использую для открытия в цикле файла, его название - для изъятия данных. Понимаю, что можно оптимизировать процесс, поэтому буду рад предложениям. Застрял на проблеме транспонирования. Решил вставлять поячеечно, но это очень замедляет процесс.
Спасибо за ответ. Я тоже так думал. И тут у меня возникли проблемы. Первый раз скопировать данные через диапазон и вставить транспонированно получилось. Потом что-то пошло не так, как говорится. Транспонировать перестало получаться. Были мысли, что проблема в наличии пароля в файлах источниках. Но я их предварительно снимаю командой workbooks(...).unprotect
Спасибо за ответ. Я тоже так думал. И тут у меня возникли проблемы. Первый раз скопировать данные через диапазон и вставить транспонированно получилось. Потом что-то пошло не так, как говорится. Транспонировать перестало получаться. Были мысли, что проблема в наличии пароля в файлах источниках. Но я их предварительно снимаю командой workbooks(...).unprotect
Sub cp() Dim x x = Workbooks(2).Sheets(1).[a2:a6] Workbooks(1).Sheets(1).[a2].Resize(1, UBound(x)) = Application.WorksheetFunction.Transpose(x) End Sub
[/vba] Что бы не путаться в книгах и избежать ошибок, определите книги в переменные: Файл источник- [vba]
Код
Set wbOut = workbooks.open ...
[/vba] Файл приемник- [vba]
Код
Set wbIn = ThisWorkbook
[/vba]
Копирование через массив: [vba]
Код
Sub cp() Dim x x = Workbooks(2).Sheets(1).[a2:a6] Workbooks(1).Sheets(1).[a2].Resize(1, UBound(x)) = Application.WorksheetFunction.Transpose(x) End Sub
[/vba] Что бы не путаться в книгах и избежать ошибок, определите книги в переменные: Файл источник- [vba]