Здравствуйте, участники форума! Я далеко не знаток экселя, поэтому мне требуется ваша помощь. Суть описана мною в одной из прежних веток и она в следующем: 1. есть программа, которая экспортирует данные в csv файл (файл пересоздается 1 раз в секунду с тем же названием и в том же месте) 2. эксель должен его считать (импортировать), 3. рассчитать и скомпоновать оценку полученным данным (внутренние расчёты экселя с меня, пока я их дорабатываю) и 4. экспортировать его в tri-файл (суть та же, что и у тхт-файла, только расширение другое), чтоб начальная программа могла его принять и реализовать. Все это должно происходить без моего участия. Я сегодня сам поискал на форуме, нашел макрос на импорт, макрос на экспорт (спасибо, ещё раз Моте), макрос на цикл (спасибо Igor67), скомпоновал это всё (сам удивлён, что вышло успешно), но... не всё так здорово. Отсюда вопросы: 1. Я так и не разобрался как сделать так чтоб данные экспортировались не в активную ячейку, как сейчас, а в указанную (например, файл "импорт-экспорт", лист "Расчёты", начальная ячейка B2). Временами я оставляю выделенной не ту ячейку и это влечёт перезапись поверх формул и прочие сложности. 2. Главное. В файле-экспортере около 4000 строк (может становиться и больше), соответственно процесс импорта в эксель занимает слишком много времени. Выход вижу в том, чтобы ограничить экспорт последними, например, 100 строками. Полагаю макрос сработает достаточно оперативно, а информативность в 100 строк меня устроить. Если есть другой выход - буду рад узнать. Поиск юзал: про импорт есть, про ограничение его последней сотней строк - не нашел.
Не понял смысла в таком сложном коде импорта... и долгом. Так проще и быстрее:
Код
Sub import()
Set ts = CreateObject("Scripting.FileSystemObject").OpenTextFile("c:\Documents and Settings\Игорь\Мои документы\Downloads\SBER03_M1.CSV", 1) 'Подставьте свой путь к txt-файлу
arr = Split(ts.ReadAll, vbCrLf) 'массив строк текста целиком
ts.Close
ReDim a(1 To UBound(arr) + 1, 1 To 7)
For i = 0 To UBound(arr)
b = Split(arr(i), ";")
For x = 0 To UBound(b)
a(i + 1, x + 1) = b(x)
Next
Next
[b1].Resize(UBound(a), UBound(a, 2)) = a
End Sub
Но если там был смысл - тогда извините. Расскажите смысл - может его и в этот код можно добавить
Здравствуйте, Hugo! Ваш вариант действительно сделал импорт молниеносным! Благодарю от души! На данный момент не вижу никаких вопросов - сделали даже лучше чем я ожидал!)) Спасибо!
Ещё как вариант - использовать стандартный импорт данных из текста. Но в моём коде можно "гибче извернуться" - выкинуть лишние строки, изменить на лету данные, может быть вообще не грузить на лист, а сразу и всё посчитать, и создать итоговый файл вообще не выгружая данные на лист - ведь Вы в arr (ну или позже они же в массиве a(), разбитые на столбцы) получаете все исходные данные, можно считать.
Hugo, про стандартный импорт я ничего даже не слышал)) Если не трудно - закомментируйте код - я хоть потихоньку буду вникать в макросоведение. По поводу расчета "на лету" это интересный вариант. У него, очевидно, есть преимущества по скорости, но в данном проекте скорость расчётов даже в 3-5 секунд приемлема.
Но есть у меня один замысел, в котором скорость будет весьма таки важна... правда он пока в самом зачаточном состоянии. Там мне будет интересно Ваше содействие.
Sub import()
Set ts = CreateObject("Scripting.FileSystemObject").OpenTextFile("c:\Documents and Settings\Игорь\Мои документы\Downloads\SBER03_M1.CSV", 1) 'Подставьте свой путь к txt-файлу
arr = Split(ts.ReadAll, vbCrLf) 'массив строк текста целиком
ts.Close 'закрыли файл
ReDim a(1 To UBound(arr) + 1, 1 To 7) 'создаём массив для выгрузки
For i = 0 To UBound(arr) 'перебор строк массива из строк файла
b = Split(arr(i), ";") 'разбиваем строку в массив на поля
For x = 0 To UBound(b) 'перебор массива
a(i + 1, x + 1) = b(x) 'заполняем данными очередную строку итогового массива
Next
Next
[b1].Resize(UBound(a), UBound(a, 2)) = a 'выгрузка итогового массива в ячейку B1
End Sub
Можно лишнее повыкидывать, чуть сократить строк:
Код
Sub importOpt()
arr = Split(CreateObject("Scripting.FileSystemObject").OpenTextFile("c:\Documents and Settings\Игорь\Мои документы\Downloads\SBER03_M1.CSV", 1).ReadAll, vbCrLf)
ReDim a(1 To UBound(arr) + 1, 1 To 7)
For i = 0 To UBound(arr)
b = Split(arr(i), ";")
For x = 0 To UBound(b): a(i + 1, x + 1) = b(x): Next
Next
[b1].Resize(UBound(a), UBound(a, 2)) = a
End Sub
Продолжение. Снова здравствуйте, уважаемые участники форума. Вопрос мой касается существа нынешнего обсуждения, посему продолжаю (если, необходимо создать новое обсуждение – укажите, пожалуйста, мне на это, переделаю). Суть вопроса вот в чем: Эксель импортирует из цсв (*.csv) файла некоторые данные в определённую ячейку (J33). Тут всё вроде норм, но объём импортируемой информации многократно превышает необходимый. Так вышло от того что разработчик предыдущей утилиты (которая ведает появлением инфы в цсв-файле) прекратил разработку всех проектов (не только моих) по своему желанию, так что – работаю с тем что есть. Теперь суть – из массива переданной информации мне нужны только те строки, которые относятся к началу часа (ЧЧ:00:СС) плюс текущее состояние (последняя строка). Сейчас с помощью формул в Экселе я вытаскиваю нужную инфу и анализирую только её, но из-за этого время расчётов составляет около 14 сек, а это много даже для этого проекта. Если напрямую поставить только необходимые данные, то расчет, я так полагаю, должен пройти в течении 1 секунды, что очень меня устроит. При подстановке нужной инфы копированием обработка происходила мгновенно. Перечитал написанное – возможно, выглядит сумбурно, поэтому приведу пример:
Скрытый текст
Дано: 20140912;105827;SRU4;7633;7633;7524;7588;125161;130774.96;НЕТ;0 20140912;105926;SRU4;7633;7633;7524;7591;126376;130774.96;НЕТ;0 20140912;110027;SRU4;7591;7613;7591;7611;6182;130774.96;НЕТ;0 20140912;110125;SRU4;7591;7614;7591;7596;9714;130774.96;НЕТ;0 20140912;110225;SRU4;7591;7614;7590;7595;10316;130774.96;НЕТ;0 … 20140912;115827;SRU4;7591;7697;7590;7671;108453;130774.96;НЕТ;0 20140912;115927;SRU4;7591;7697;7590;7666;108941;130774.96;НЕТ;0 20140912;120028;SRU4;7670;7674;7668;7671;456;114730.96;НЕТ;0 20140912;120127;SRU4;7670;7687;7668;7683;2051;114730.96;НЕТ;0 20140912;120228;SRU4;7670;7687;7668;7683;2747;114730.96;НЕТ;0 … 20140912;125935;SRU4;7670;7690;7633;7643;57638;130774.96;НЕТ;0 20140912;130034;SRU4;7640;7646;7639;7642;753;130774.96;НЕТ;0 20140912;130135;SRU4;7640;7648;7639;7641;1435;130774.96;НЕТ;0 20140912;130235;SRU4;7640;7648;7639;7646;1616;130774.96;НЕТ;0 … Желаемый результат: 20140912;110027;SRU4;7591;7613;7591;7611;6182;130774.96;НЕТ;0 // данные по состоянию на начало 11 часа (итог за период с 10:00:00 до 11:00:00) 20140912;120028;SRU4;7670;7674;7668;7671;456;114730.96;НЕТ;0 // данные по состоянию на начало 12 часа (итог за период с 11:00:00 до 12:00:00) 20140912;130034;SRU4;7640;7646;7639;7642;753;130774.96;НЕТ;0 // данные по состоянию на начало 13 часа (итог за период с 12:00:00 до 13:00:00) 20140912;130235;SRU4;7640;7648;7639;7646;1616;130774.96;НЕТ;0// данные по состоянию на сейчас (итог за период с 13:00:00 до 13:02:35)
Возможно, есть альтернативные пути ускорения расчётов – буду благодарен, если подскажете. Сам экселевский файл отчего-то не загружается ("При сохранении файла произошла ошибка." ) Попробую отдельно выложить. P.S. приложить эксель не выходит - вес около 4,71 МБ. Могу на почту кинуть или еще как.
Пока навскидку несколько вопросов - второй элемент нужной строки всегда будет иметь 3 и 4 цифры - 00? То есть, всегда есть строка из первой минуты? - время - всегда 6 цифр, или может быть 5? - нужно ли каждый раз выгружать весь массив, или достаточно дописать последние строки, которых не было с последнего обновления?
Так в моём варианте кода как раз всё это просто реализовать - при переборе массива строк каждую сперва анализируем, если в нужном месте 00, то увеличиваем индекс результирующего массива и по этому индексу импортируем данные. С последней строкой сложнее - самая последняя может быть пустой (которая в UBound(arr)), поэтому как вариант - проверять каждую строку на наличие значений и запоминать в переменную (если есть значения), а после цикла перебора строк взять последнее значение.
Здравствуйте, Hugo! Рад Вас снова видеть в этой теме! Признаться, надеялся, что Вы появитесь в этой дискуссии, т.к. мы закончили в прошлый раз как раз на том, что некоторые вычисления можно проводить "на лету", но тогда мне хватало того, что есть и я не хотел Вас грузить просьбами о функционале, в котором тогда не нуждался. Теперь потребность возникла. Я в очень общих чертах понял то, что Вы написали, но полагаю, что этот вопрос решаем через корректировку Вашего макроса. Если Вы сможете его соответственным образом подкорректировать, то буду признателен!
Цитата
Максим Зеленский пишет: - второй элемент нужной строки всегда будет иметь 3 и 4 цифры - 00? - время - всегда 6 цифр, или может быть 5? - нужно ли каждый раз выгружать весь массив///?
Здравствуйте, Максим! 1. Возможно, я не вполне точно понял вопрос... Второй элемент - это время прописанное сплошняком без символа ":" между часами, минутами и секундами. Обновление и возвращение данных происходит каждые 60 секунд, так что каждый час среди элементов обязательно появится код времени, в котором 3-ья и 4-ая позиции будут 0 и 0. Формат выгружаемых данных стандартен: 20140912 (дата);105926 (время в формате ЧЧ:ММ:СС);SRU4 (код инструмента);7633 (Цена открытия);7633 (высочайшая цена с начала часа);7524 (самая низкая цена с начала часа);7591 (текущая цена);126376 (объём);130774.96 (доп параметр);НЕТ (наличие текущей сделки);0 (количество актива в текущей сделке). 2. Время всегда 6 цифр, обозначения часа из одной цифры будет обозначено как 09ММСС, но по факту минимальное число, которое может возникать это 100000. 3. На Ваше усмотрение. Мне нужны только строки, которые отражают показатели за последние 14 часовых периодов. Рискну предположить что догрузка последнего значения будет более скорострельной, чем обновление массива с прежними данными, но, повторюсь, когда я напрямую копировал искомые значения в необходимые ячейки, то расчет становился достаточно оперативным даже при копировании всего массива. Думаю, тот факт, что искомые значения вписал макрос, а не пользователь вручную не будет иметь значения.
По хорошему можно реализовать так, 1. Контролируем поступление (обновление файла) 2. При событии (п. 1) запускается обработка. 3. Нужные данные импортируются в excel 4. В excel делаются необходимые для Вас операции ------------ Все работает в автоматическом режиме.
Скрытый текст
Могу реализовать, о сроках и стоимости пишите в личку
MaksExcel пишет: Возможно, есть альтернативные пути ускорения расчётов – буду благодарен, если подскажете
никогда не понимала, зачем котировки грузить в excel чтобы что-то считать, когда во всех торговых платформах уже давно всё посчитано, что надо... разве что сменить мониторинг СБЕРа на акции, торгуемые на Nyse - и софт удобнее и акции более ликвидные... ну да ладно.. может здесь что найдёте чтобы доработать http://investexcel.net/ ... успехов вам
p.s. с yahoo.finance часто налаживают нормальное подключение для выгрузки в xl... не csv ... но это вряд ли про СБЕР... да и через DDE можно из торговой платформы брать котировки... котировки без торговой платформы не нужны, а функционал торговой платформы зависит от вашего брокера... ищите брокера (на ру-акции) с нормальной торговой платформой... чтобы не дёргать csv...
чтобы не гадать на кофейной гуще, кто вам отвечает и после этого не совершать кучу ошибок - обратитесь к собеседнику на ВЫ - ответ на ваш вопрос получите - а остальное вас не касается (п.п.п. на форумах)
JeyCi пишет: никогда не понимала, зачем котировки грузить в excel чтобы что-то считать, когда во всех торговых платформахуже давно всё посчитано, что надо...
Здравствуйте, JeyCi ! Ну, всё да не всё... Можно, конечно, дописывать свои особые пожелания, но у Квика свой язык, у Транзака, как мне известно, - свой, и т.д.. С Вэлс-Лабом поковыряюсь ещё, но позже. Кроме того, отзывы об этих языках позитивом на пышут)) Ну а главное - пока я научусь, писать что либо в платформах или отдельным приложением всё же логично затестить идею имеющимися средствами - для меня это Эксель. С формулами я более-менее разбираюсь, а вот за макросами приходится обращаться за помощью. Так что, как говорится, "не ругайте пианиста - он играет как умеет" ))
А за сайт спасибо от души - внимательно поизучаю на выходных!
К сожалению, все кто отозвался на запрос, в настоящий момент пропали со связи... Я всё же надеюсь, что озвученная задача сложна для меня, но не для вас, участники форума. Может кто-нибудь еще отзовётся?
дорабатываем код Hugo, ровно под ваш CSV файл из примера (11 столбцов с данными, выгрузка в J33
Код
Sub importOpt_2()
Dim arr, a, b, i&, x&, n&
arr = Split(CreateObject("Scripting.FileSystemObject").OpenTextFile("C:\Users\Максим Зеленский\Desktop\XLS\История параметров - копия (2).CSV", 1).ReadAll, vbCrLf)
n = 1
ReDim a(1 To 11, 1 To 1)
For i = UBound(arr) To 0 Step -1
If arr(i) <> "" And Mid(arr(i), 12, 2) = "00" Then
ReDim Preserve a(1 To 11, 1 To n)
b = Split(arr(i), ";")
For x = 0 To UBound(b): a(x + 1, n) = b(x): Next
n = n + 1
End If
Next
[j33].Resize(UBound(a, 2), 11) = Application.Transpose(a)
End Sub
Из файла-примера вытащил и выгрузил 12 строк с "часовыми" данными. Это надо было?
MaksExcel пишет: логично затестить идею имеющимися средствами - для меня это Эксель. ... Я всё же надеюсь, что озвученная задача сложна для меня, но не для вас, участники форума. Может кто-нибудь еще отзовётся?
имеющиеся средства - это люди, которые сделают всё за вас?.. у вас очень многоплановое тз и никаких шагов к его реализации... нужны не подсказки, а работа с нуля... (поэтому и подсказывать сложно, по-видимому)... хотя не понимаю, чем вас не устраивает ваш проф ресурс - берите txt/csvза ту периодичность, которая вам нужна и тестите свою идею... успехов
чтобы не гадать на кофейной гуще, кто вам отвечает и после этого не совершать кучу ошибок - обратитесь к собеседнику на ВЫ - ответ на ваш вопрос получите - а остальное вас не касается (п.п.п. на форумах)
Я обычно без пресервов делаю - ведь при таком подходе сразу известно максимальное количество строк, значит можно сразу объявить массив по максимуму, и двумерный в нужном виде, чтоб и без транспозов обойтись. Далее если строка подошла - увеличиваем индекс, по нему заполняем массив, по нему же в итоге и выгружаем заполненную верхушку массива. Ну будет чуть перерасход памяти - если напрягает, то можно сперва пробежаться и определить количество нужных строк, сразу запомнить их например в словаре, затем уже циклом по словарю переложить в массив (а исходный можно уже и убить, чтоб память освободить). Или писать сразу на лист построчно - долго, зато без лишних заморочек с массивами/словарями.
Доброго времени суток, уважаемые участники! Спасибо Вам большое за участие и помощь! Максим, импорт «летает» и выполняет работу на 5+! Спасибо Вам лично - массив получился аккуратным и, что особо приятно - без пустых строк!)) Вечером применю его в "боевых" условиях, но уверен - всё будет ок!
Максим, целые часы ("00" минут) макрос возвращает, а возврат последней строки не получится ли сделать? Если это сложно вписать в текущий макрос, то можно и просто отдельный, а я уже совмещу с существующей "коллекцией".
Я помню, Hugo писал, что там не всё так просто. Если там сложность, то пусть так останется - я формулами добрал необходимое значение. Правда получилось ооочень коряво, но скорость вроде сохранилась приемлемая, хоть и есть некоторый временнОй лаг.
P.S. При совмещении всех макросов в один получаю ошибку "Run time error 9. Subscrirt out of range". Почитал, что за косяк - пишут, что-то типа "Элемент за пределами диапазона". Не понимаю почему так ведь поодиночке макросы работают корректно. Подскажите, пожалуйста, что я не учёл. Пока я это избегаю этой ошибки тем, что запускаю макросы последовательно помощью ОнТайма - но, наверняка, можно и более интеллигентно сработать.
Вот совмещенный макрос (некоторые переменные дублировались, поэтому переименованы так чтоб уж наверняка не повторились):
Код
Sub MyMacroEXCHANGE2HugoMaxWay()
Dim sh As Worksheet
' Application.OnTime Now() + TimeSerial(0, 5, 0), "MyMacroEXCHANGE2HugoMaxWay"
' импорт всей истории цены
Set ts = CreateObject("Scripting.FileSystemObject").OpenTextFile("C:\Users\1_H1.CSV", 1) 'Подставьте свой путь к txt-файлу
arr = Split(ts.ReadAll, vbCrLf) 'массив строк текста целиком
ts.Close
ReDim a(1 To UBound(arr) + 1, 1 To 7)
For i = 0 To UBound(arr)
b = Split(arr(i), ";")
For x = 0 To UBound(b)
a(i + 1, x + 1) = b(x)
Next
Next
[b1].Resize(UBound(a), UBound(a, 2)) = a
' импорт всей истории счёта
Set ts = CreateObject("Scripting.FileSystemObject").OpenTextFile("C:\История параметров.CSV", 1) 'Подставьте свой путь к txt-файлу
arr = Split(ts.ReadAll, vbCrLf) 'массив строк текста целиком
ts.Close
ReDim a(1 To UBound(arr) + 1, 1 To 11)
For i = 0 To UBound(arr)
b = Split(arr(i), ";")
For x = 0 To UBound(b)
a(i + 1, x + 1) = b(x)
Next
Next
[V33].Resize(UBound(a), UBound(a, 2)) = a
' импорт текущего состояния счёта
Dim arrA, aA, bA, iA&, xA&, nA&
arrA = Split(CreateObject("Scripting.FileSystemObject").OpenTextFile("C:\История параметров.CSV", 1).ReadAll, vbCrLf)
n = 1
ReDim aA(1 To 11, 1 To 1)
For iA = UBound(arrA) To 0 Step -1
If arrA(iA) <> "" And Mid(arrA(iA), 12, 2) = "00" Then
ReDim Preserve aA(1 To 11, 1 To n)
bA = Split(arrA(iA), ";")
For xA = 0 To UBound(bA): aA(xA + 1, nA) = bA(xA): Next
nA = nA + 1
End If
Next
[j33].Resize(UBound(aA, 2), 11) = Application.Transpose(aA)
' импорт последних данных о цене
Set ts = CreateObject("Scripting.FileSystemObject").OpenTextFile("C:\Users\1_H1_LAST.CSV", 1) 'Подставьте свой путь к txt-файлу
arr = Split(ts.ReadAll, vbCrLf) 'массив строк текста целиком
ts.Close ReDim a(1 To UBound(arr) + 1, 1 To 7)
For i = 0 To UBound(arr)
b = Split(arr(i), ";")
For x = 0 To UBound(b)
a(i + 1, x + 1) = b(x)
Next
Next
[x3].Resize(UBound(a), UBound(a, 2)) = a
'экспорт в сторонний файл
Application.ScreenUpdating = 0
Application.DisplayAlerts = 0
Dim PUT_FILE_out, lst As Variant
lst = "К экспорту"
PUT_FILE_out = Application.ActiveWorkbook.Path + "\" + lst + ".tri"
Sheets(lst).Copy
'ActiveWorkbook.SaveAs Filename:=PUT_FILE_out, FileFormat:=xlUnicodeText
ActiveWorkbook.SaveAs Filename:=PUT_FILE_out, FileFormat:=xlText
ActiveWindow.Close
Application.ScreenUpdating = 1
Application.DisplayAlerts = 1
End Sub
Максим, спасибо за подсказку - моя невнимательность. Поправил - всё заработало. С последней строкой получится что-нибудь сделать? Я сам пытался на основе Вашего макроса сделать - занятие увлекательное, но пока безрезультатное. Прилагаю закомментированный код. Если не трудно поправьте где я ошибаюсь.
Код
Sub importOptLast_3() ' объявили макрос
Dim arr, a, b, i&, x&, n& ' ввели переменные
arr = Split(CreateObject("Scripting.FileSystemObject").OpenTextFile("C:\BCS_Work\QUIK\QPILE\История параметров.CSV", 1).ReadAll, vbCrLf) ' присвоили переменной "arr" значение из файла, который для этого открыли и прочли записанную в нем инфу (массив)
n = 1 ' переменной "n" присвоено начальное значение
ReDim a(1 To 11, 1 To 1) ' не понял, но может здесь формируется массив определённого вида (количество элементов в строке и т.д.)
If i = UBound(arr) Then ' если значение "i" равно верхней границе массива "arr" (последнее значение), то...
'ReDim Preserve a(1 To 11, 1 To n) ' каким-то образом отформатировать массив?
b = Split(arr(i), ";") ' разбить элемент "i" массива "arr" по разделителю ";"
'For x = 0 To UBound(b): a(x + 1, n) = b(x): Next ' для введённых ранее переменных "Х" со значениями от 0 до верхней границы массива... дальше не понял
n = n + 1 ' увеличить переменную "n" на 1 (сделать ещё шаг)
End If ' закончить оператор "if"
[AI33].Resize(UBound(a, 2), 11) = Application.Transpose(a) ' записываем в AI33... больше не понял((
MsgBox ("importOptLast_3 прочтён!") ' сделал для того чтоб видеть что код вообще считывается
End Sub ' закрыли макрос
Sub importOptLast_3() ' объявили макрос
Dim arr, a, i& ' ввели переменные
' присвоили переменной "arr" значение из файла, который для этого открыли и прочли записанную в нем инфу (массив)
arr = Split(CreateObject("Scripting.FileSystemObject").OpenTextFile("C:\BCS_Work\QUIK\QPILE\История параметров.CSV", 1).ReadAll, vbCrLf)
' ReDim a(1 To 1, 1 To 11) ' здесь формируется массив из 1 строки и 11 столбцов, но если нам нужна всего 1 строка, то это не нужно
For i = UBound(arr) To 0 Step -1 ' цикл по строкам снизу вверх
If arr(i) <> "" Then ' если последняя строка не пустая, то
a = Split(arr(i), ";") ' разбить элемент "i" массива "arr" по разделителю ";" и записать в массивную переменную a
If Not IsArray(a) Then ' если вдруг строка состоит из одного слова и нет ";" то a может оказаться просто строкой.
[AI33].Value = a
Else
[AI33].Resize(1, UBound(a)+1) = a ' если это всё же массив, то просто выгружаем его
' предварительно расширили выходной диапазон до количества столбцов в массиве a
End If
MsgBox ("importOptLast_3 прочтён!") ' сделал для того чтоб видеть что код вообще считывается
Exit Sub ' последнюю непустую строку нашли, выходим
End If ' закончить оператор "if"
Next ' если последняя строка пустая, переходим на строку выше
End Sub