Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Microsoft Office и VBA программирование > Microsoft Office Excel
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Закрытая тема
Ваша тема закрыта, почему это могло произойти? Возможно,
Нет наработок или кода, если нужно готовое решение - создайте тему в разделе Фриланс и оплатите работу.
Название темы включает слова - "Помогите", "Нужна помощь", "Срочно", "Пожалуйста".
Название темы слишком короткое или не отражает сути вашего вопроса.
Тема исчерпала себя, помните, один вопрос - одна тема
Прочитайте правила и заново правильно создайте тему.
 
Опции темы Поиск в этой теме
Старый 26.12.2008, 14:31   #1
cent
Пользователь
 
Аватар для cent
 
Регистрация: 26.12.2008
Сообщений: 73
По умолчанию Экспорт в csv и импорт из csv

Задача:
1. В результате вычислений получаю массивы данных типа Ar(1 to 10)
необходимо этот массив добавлять в конец csv-файла
2. Затем по ходу работы макроса необходимо вытянуть эти данные из csv-файла, обращаясь к определенному массиву, т.е. вытягивать построчно.

Подскажите как реализовать задачу, т.к. с внешними файлами пока не приходилось сталкиваться.
Четко сформулированная задача - половина решения!
<= Спасибо оставляем в отзывах
cent вне форума
Старый 26.12.2008, 15:41   #2
EducatedFool
Программист VBA
СуперМодератор
 
Аватар для EducatedFool
 
Регистрация: 13.07.2008
Сообщений: 6,856
По умолчанию

Примерно так:

Код:
Sub test()
    Dim Ar(): Ar = Array("1", "2", "3", "4", "5", "11", "22", "33", "44", "55")
    delimiter = "; "

    ArrText = Join(Ar, delimiter):    'MsgBox ArrText

    Filename = "C:\Documents and Settings\Администратор\Рабочий стол\test.csv"
    Filename2 = "C:\Documents and Settings\Администратор\Рабочий стол\test2.csv"

    Open Filename For Output As #1
    Print #1, ArrText
    Close #1

    Dim NewAr(), text As String

    Open Filename2 For Input As #2
    Line Input #2, text
    Close #2

    NewAr = Split(text, delimiter)
End Sub
С конструкциями типа Open ... For Input As #... я ранее не работал, так что в коде возможны ошибки.

Также существуют другие способы работы с файлами.
EducatedFool вне форума
Старый 26.12.2008, 17:19   #3
cent
Пользователь
 
Аватар для cent
 
Регистрация: 26.12.2008
Сообщений: 73
По умолчанию

Вот пытаясь разобраться, разбил код на 2 части: экспорт в csv и импорт .
Попытался подкорректировать для теста под свою задачу, чтоб убедиться в работоспособности и правильности результата и наткнулся на ошибку.
Все пересмотрел, не могу понять почему выдает ошибку "Type mismastch"?

Код:
Sub export()
    Dim Ar(1 To 10)
    Dim i As Long, j As Long, ArrText As String
    
    For i = 1 To 3
        For j = 1 To 10
            Cells(i, j).Value = Int(Rnd() * 100)
        Next j
    Next i
    
    delimiter = "; "
    
    For i = 1 To 3
        For j = 1 To 10
           Ar(j) = Cells(i, j).Value
        Next j
        For j = 1 To 10
             ArrText = Join(Ar(j), delimiter)
        Next j
        MsgBox ArrText
        Filename = "C:\test.csv"
    
        Open Filename For Output As #1
        Print #1, ArrText
        Close #1
    Next i
End Sub
Код генерирует на странице 3 строки случайных чисел по 10 в ряду.
После генерирования заполняется массив на 10 чисел.
А затем на этапе объединения данных в переменную ArrText получаю ошибку.


В догонку... решил все таки проверить Ваш код в чистом виде
тоже получил ошибку, но уже другого типа "Input past end of file" в строке
Код:
...
    Open Filename2 For Input As #2
    Line Input #2, text 
    Close #2
...
Четко сформулированная задача - половина решения!
<= Спасибо оставляем в отзывах

Последний раз редактировалось cent; 26.12.2008 в 17:35.
cent вне форума
Старый 26.12.2008, 17:43   #4
cent
Пользователь
 
Аватар для cent
 
Регистрация: 26.12.2008
Сообщений: 73
По умолчанию

Разобрался в своей ошибке:
Вместо этой части:
Код:
        For j = 1 To 10
             ArrText = Join(Ar(j), delimiter)
        Next j
Надо так:
Код:
        ArrText = Join(Ar, delimiter)
Но вот обнаружилось, что данный код не добавляет данные к csv, а заменяет их, т.е. в csv-файле всегда находится только один набор, одна строка. А по условиям задачи необходимо, чтобы новые данные добавлялись к уже существующим, чтобы их потом можно было оттуда импортировать построчно.


У кого-нибудь есть еще предложения?
Четко сформулированная задача - половина решения!
<= Спасибо оставляем в отзывах
cent вне форума
Старый 28.12.2008, 17:34   #5
EducatedFool
Программист VBA
СуперМодератор
 
Аватар для EducatedFool
 
Регистрация: 13.07.2008
Сообщений: 6,856
По умолчанию

Цитата:
У кого-нибудь есть еще предложения?
А обязательно ли для Вас использование именно csv-файла?
Если файл используется лишь для временного хранения данных, и осуществлять чтение/запись данных будут только Ваши макросы, - то можно использовать какие-нибудь другие форматы файлов.

Я, к примеру, для сохранения в виде файла экземпляров классов использую ini - файлы (чтение и запись произвожу через API-функции)

То есть файл выглядит примерно так:
Цитата:
[Properties]
WarrantFileVersion=1
Index=1
Done=False
Printed=True
Name=Наряд на выполнение работ № 23 от 15.09.2008
TracesCount=0
LinksCount=36
Author=***
LastAuthor=***
Date_Created=15.09.2008 8:17:03
Date_Modified=15.09.2008 8:55:45
[Link_1]
Index=1
Tag=0
XWB_name=11111111.xls
LinkType=2
Applied=True
Comment=
[Node_1_of_Link_1]
Index=0
NewIndex=0
EducatedFool вне форума
Старый 28.12.2008, 17:48   #6
EducatedFool
Программист VBA
СуперМодератор
 
Аватар для EducatedFool
 
Регистрация: 13.07.2008
Сообщений: 6,856
По умолчанию

Цитата:
Затем по ходу работы макроса необходимо вытянуть эти данные из csv-файла
Что-то меня немного смутили слова "Затем по ходу работы макроса"

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

Другой вопрос, что может понадобиться пересмотреть структуру хранения данных (например, в некоторых случаях вместо массивов сподручнее использовать коллекции или экземпляры классов).

Ну а если наличие файла обязательно, я бы поступил так:

1) при запуске макроса считал бы всё содержимое файла в память
2) во время выполнения макроса работал бы только с массивом данных в памяти (чтение и изменение значений)
3) при завершении макроса выгрузил бы весь массив (частично обновлённый) обратно в файл (с полной перезаписью содержимого файла)
EducatedFool вне форума
Старый 28.12.2008, 18:26   #7
cent
Пользователь
 
Аватар для cent
 
Регистрация: 26.12.2008
Сообщений: 73
По умолчанию

Цитата:
Сообщение от EducatedFool Посмотреть сообщение
Что-то меня немного смутили слова "Затем по ходу работы макроса"

Так если выполнение макроса не прекращается, зачем скидывать информацию в файл?
Пусть она хранится в памяти... такие массивы, если, конечно, их не миллионы, занимают совсем немного места.
На первом этапе работы макрос создает масив 184756х10, т.е. 184756 строк по 10 значений. Держать в памяти такой объем данных не представляется возможным, т.к. для этого необходимо 32ГБ оперативной памяти.
Поэтому необходимо выгружать "построчно" эти данные во внешний файл.
Затем же необходимо так же построчно выдергивать их оттуда для дальшнейших вычислений.

Цитата:
Сообщение от EducatedFool Посмотреть сообщение
Другой вопрос, что может понадобиться пересмотреть структуру хранения данных (например, в некоторых случаях вместо массивов сподручнее использовать коллекции или экземпляры классов).
К сожалению данная терминология меня пугает ... не знаком еще с "...коллекции или экземпляры классов...", или знаком, но не знал, что они так называются.

Цитата:
Сообщение от EducatedFool Посмотреть сообщение
А обязательно ли для Вас использование именно csv-файла?
Если файл используется лишь для временного хранения данных, и осуществлять чтение/запись данных будут только Ваши макросы, - то можно использовать какие-нибудь другие форматы файлов.
Нет, csv не принципиально. Просто хотелось сформулировать задачу более конкретно.

Цитата:
Сообщение от EducatedFool Посмотреть сообщение
Я, к примеру, для сохранения в виде файла экземпляров классов использую ini - файлы (чтение и запись произвожу через API-функции)
Даже не знаю что ответить

Я с удовольствием применю любой вариант, лишь бы он помог решить задачу.
Четко сформулированная задача - половина решения!
<= Спасибо оставляем в отзывах
cent вне форума
Старый 28.12.2008, 18:43   #8
EducatedFool
Программист VBA
СуперМодератор
 
Аватар для EducatedFool
 
Регистрация: 13.07.2008
Сообщений: 6,856
По умолчанию

Цитата:
На первом этапе работы макрос создает масив 184756х10, т.е. 184756 строк по 10 значений. Держать в памяти такой объем данных не представляется возможным, т.к. для этого необходимо 32ГБ оперативной памяти.
Узнал много нового
Это всего-то 1 847 560 значений.
Чтобы набралось 32 Гб, надо, чтобы каждый элемент массива "весил" по 18 кБ...
Что такое ужасное Вы храните в этом массиве?

Ну а если в массиве хранятся значения ячеек Excel, то смею заметить, что на листе Excel 2003 находится в 9 раз больше ячеек, чем у Вас элементов в массиве. (не говоря уж про Excel 2007)

Как в таком случае мой комп с 256 Мб оперативки работает с файлами Excel - не понимаю


А организовать работу с ini-файлами - совсем несложно. У меня есть все наработки. Например:

Объявляем WinAPI-функции:
Код:
'Функции для записи INI файлов
Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA"  _ 
(ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, _ 
 ByVal lpReturnedString As String, ByVal nSize As Long, ByVal lpFileName As String) As Long

Declare Function WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA"  _ 
(ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpString As Any,  _ 
ByVal lpFileName As String) As Long
Пишем оболочку для этих функций:
Код:
'=======================================================================================
'============================= работа с INI - файлами ==================================
'=======================================================================================
Public Sub WIF(ByVal sName As String, ByVal val As String, ByVal sPart As String, ByVal FilePath As String)
    '   sName  = Название параметра, val = Значение параметра, sPart  = Название раздела, filePath - путь к файлу
    Dim intRet As Integer: intRet = WritePrivateProfileString(sPart, sName, val, FilePath)
    'If intRet <> 1 Then 'Неудачное завершение'(Проверка результата записи)
End Sub

Public Function RIF(ByVal sName As String, ByVal DefVal As String, ByVal sPart As String, ByVal FilePath As String) As String
    '   sName  = Название параметра,   DefVal = Значение по умолчанию (на случай его отсутствия),   sPart  = Название раздела, filePath - путь к файлу
    'Значение возвращаемое функцией GetPrivateProfileString если искомое значение параметра не найдено
    Const strNoValue As String = ""
    Dim intRet As Integer    'Длина возвращаемой строки (функцией GetPrivateProfileString)
    Dim strRet As String    'Возвращаемая строка
    'Получаем значение из файла - если его нет будет возвращен 3й аргумент = strNoValue
    strRet = String(255, Chr(0)): intRet = GetPrivateProfileString(sPart, sName, strNoValue, strRet, 255, FilePath)
    strRet = Left$(strRet, intRet)
    'Определяем было найдено значение или нет (если возвращено знач. константы strNoValue то = НЕТ)
    If strRet = strNoValue Then strRet = DefVal              'Значение не было найдено - возвращаем знач по умолчанию
    RIF = strRet: Exit Function
End Function
Ну и используем наши функции: (WIF - сокращение от Write Ini File)
Код:
Sub test()
    Filename = "C:\Documents and Settings\Администратор\Рабочий стол\Тестовый документ.data"
    ' пишем данные в файл
    Section = "Properties"
    WIF "Свойство1", Значение1, Section, Filename
    WIF "Свойство2", Значение2, Section, Filename

    Section = "Прочая информация"
    WIF "Свойство3", Значение3, Section, Filename
    WIF "Свойство4", Значение4, Section, Filename

    ' читаем данные из файла
    Значение5 = CStr(RIF("Свойство5", "Значение по умолчанию - если запись не найдена в файле", Section, Filename))
End Sub

Последний раз редактировалось EducatedFool; 28.12.2008 в 18:56.
EducatedFool вне форума
Старый 28.12.2008, 18:59   #9
cent
Пользователь
 
Аватар для cent
 
Регистрация: 26.12.2008
Сообщений: 73
По умолчанию

Цитата:
Сообщение от EducatedFool Посмотреть сообщение
Узнал много нового
Это всего-то 1 847 560 значений.
Чтобы набралось 32 Гб, надо, чтобы каждый элемент массива "весил" по 18 кБ...
Что такое ужасное Вы храните в этом массиве?

Ну а если в массиве хранятся значения ячеек Excel, то смею заметить, что на листе Excel 2003 находится в 9 раз больше ячеек, чем у Вас элементов в массиве. (не говоря уж про Excel 2007)

Как в таком случае мой комп с 256 Мб оперативки работает с файлами Excel - не понимаю
да, где-то просчитался с объемом памяти, прошу простить...
но ведь количество строк в листе 65536, а данных в массиве - 184756 строк... на 3 листа хватит. Тем более что это временная информация. Именно поэтому хочется не замыкаться на расположении этих данных внутри листа, а просто вынести их во внешний файл.
Четко сформулированная задача - половина решения!
<= Спасибо оставляем в отзывах
cent вне форума
Старый 28.12.2008, 19:03   #10
EducatedFool
Программист VBA
СуперМодератор
 
Аватар для EducatedFool
 
Регистрация: 13.07.2008
Сообщений: 6,856
По умолчанию

Цитата:
Я с удовольствием применю любой вариант, лишь бы он помог решить задачу.
Так Вы хоть объясните суть задачи. Возможно, найдётся гораздо более простой способ решения.

Я поначалу (когда плохо знал Excel и VBA) тоже использовал огромные 3-мерные массивы для хранения информации (отъедавшие по 200 метров памяти)...
Как выяснилось позже, при правильной организации хранения информации можно ограничиться 5 - 10 мегабайтами...

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

Цитата:
Именно поэтому хочется не замыкаться на расположении этих данных внутри листа, а просто вынести их во внешний файл.
Не лучший вариант.
Вынос такого количества данных во внешний файл может занять кучу времени.

Зачем что-то изобретать, когда Excel как раз и предназначен для хранения информации?

Проще во время выполнения макроса создать новый лист (можно невидимый), и скинуть в него все данные.
И обращаться к ним будет проще, и посмотреть легко, и сохранится всё вместе с файлом.

Только не забудьте один важный момент - запись данных на лист надо производить, не перебирая ячейки в цикле (иначе это будет длиться очень долго), а, сначала сформировав массив, одной командой записать целиком весь массив на лист.
Скорость чтения/записи в этом случае будет вполне приемлемой.

Последний раз редактировалось EducatedFool; 28.12.2008 в 19:10.
EducatedFool вне форума
Закрытая тема


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Формат .csv. Rashanea Microsoft Office Excel 8 27.11.2008 15:57
Разделители в csv Aimo Microsoft Office Excel 13 09.10.2008 17:20
Импорт данных из *csv-файлов в БД bober Общие вопросы .NET 3 19.08.2008 17:20
Поиск *.csv и *.xls файлов Len@ Microsoft Office Excel 18 28.07.2008 22:31
Из TXT в CSV CodeName47 Помощь студентам 17 22.01.2008 09:14