Ru-Board.club
← Вернуться в раздел «Прикладное программирование»

» Работа с файлами в Delphi

Автор: Markell
Дата сообщения: 09.04.2005 18:13
Надо из программы открыть файл с расширением xls или mdb.
Если кто-то знает, как это сделать, пожалуйста, приведите пример кода.
Но, что самое главное, как потом из этого файла вытаскивать данные? Например, если это Excel'евский файл, и в отдельных ячейках содержится какая-то инфа, то как мне ее достать оттуда и поместить в массив для дальнейшей обработки?
Я работал с текстовыми файлами, и там все считывается построчно, а как быть в таких случаях, никогда не сталкивался...
Автор: mutano
Дата сообщения: 09.04.2005 20:46
Помойму тут нужна технология .com
Автор: OdesitVadim
Дата сообщения: 10.04.2005 13:03
Markell
структура екселевского файла охраняется майкрософтом. Поэтому так просто открыть и читать его нельзя. Но можна, как сказал mutano пользоваться com (mutano, точка там не надо, это не .NET)
Вот рабочий код, правда выполняется он за пару секунд. Проверено, рабочий

Код:
uses
ComObj;
function Xls_To_StringGrid(AGrid: TStringGrid; AXLSFile: string): Boolean;
const
xlCellTypeLastCell = $0000000B;
var
XLApp, Sheet: OLEVariant;
RangeMatrix: Variant;
x, y, k, r: Integer;
begin
Result := False;
XLApp := CreateOleObject('Excel.Application');
try
XLApp.Visible := False;
XLApp.Workbooks.Open(AXLSFile);
// Sheet := XLApp.Workbooks[1].WorkSheets[1];
Sheet := XLApp.Workbooks[ExtractFileName(AXLSFile)].WorkSheets[1];
Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;
x := XLApp.ActiveCell.Row;
y := XLApp.ActiveCell.Column;
AGrid.RowCount := x;
AGrid.ColCount := y;
RangeMatrix := XLApp.Range['A1', XLApp.Cells.Item[X, Y]].Value;
k := 1;
repeat
for r := 1 to y do
AGrid.Cells[(r - 1), (k - 1)] := RangeMatrix[K, R];
Inc(k, 1);
AGrid.RowCount := k + 1;
until k > x;
RangeMatrix := Unassigned;
finally
if not VarIsEmpty(XLApp) then
begin
XLApp.Quit;
XLAPP := Unassigned;
Sheet := Unassigned;
Result := True;
end;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if Xls_To_StringGrid(StringGrid1, 'C:\All OLD\Мои документы\Розклад.xls') then
ShowMessage('Table has been exported!');
end;
Автор: Markell
Дата сообщения: 10.04.2005 16:10
Спасибо большое, мужики! Попробую так сделать. Если что - еще спрошу...

Добавлено:
Выдается ошибка Undeclared identifier: TStringGrid
Какого он должен быть типа?
OdesitVadim, не бог бы ты дать кусок кода побольше, включая описание типов?
Автор: wellwisher
Дата сообщения: 11.04.2005 00:08
Markell
Вставляешь uses Grids --> дальше все ОК (можно и help посмотреть)
Автор: ShIvADeSt
Дата сообщения: 11.04.2005 01:35

Цитата:
mdb.

А это стандартно открывается через ADO подключаешься как к обычной базе и работаешь. Посмотри фильтром по Акцезу здесь уже обсуждалась работа с ним.
Автор: OdesitVadim
Дата сообщения: 11.04.2005 10:22
Markell
Положи просто на форму StringGrid. Туда данные записываются.
wellwisher
Добавление модуля ничем не поможет. (в данном случае)
Автор: koldovsky
Дата сообщения: 11.04.2005 22:55
Markell
Если задача стоит не в модификации файлов, а в чтении, либо создании, то можно использовать библиотеки импорта/экспорта, например, вот эти: http://www.sqlmanager.net/products/tools/quickexport и http://www.sqlmanager.net/products/tools/quickimport
Автор: Dim2004
Дата сообщения: 12.04.2005 14:18
OdesitVadim

Цитата:
структура екселевского файла охраняется майкрософтом. Поэтому так просто открыть и читать его нельзя

Где-то видел описание внутренней структуры .XLS, но, как водится, не помню, где слямзил... IMHO использовать Excel через OLE всё-таки бесхлопотнее.
Автор: bOND4784432
Дата сообщения: 12.04.2005 14:49
Вышеописаннык примеры годятся для чтения XLS файла.
Но у них есть недостаток - происходит считывание каждой ячейки отдельно.
Желательно создавать массив типа Variant - считывать через COM данные в этот массив,
А уже из массива - переносить их куда душа пожелает.
Увеличишь скорость раз в 10
Автор: OdesitVadim
Дата сообщения: 12.04.2005 16:05
bOND4784432
Полностью согласен. Просили пример - дал. Когдато добавив чтение массивом я зачитывал сразу около нескольки сотен - на ура просто
Автор: vserd
Дата сообщения: 13.04.2005 18:18
Dim2004

Цитата:
Где-то видел описание внутренней структуры .XLS, но, как водится, не помню,

на сайте разработчиков OpenOffice?
Автор: Markell
Дата сообщения: 20.04.2005 11:37
OdesitVadim

Цитата:
Положи просто на форму StringGrid. Туда данные записываются.


Спасибо огромное! Все получилось. Вот только еще вопрос возник. Бывает, что в Excel данные хранятся на разных листах.
Как сделать, чтобы по данные могли экспортироваться еще и из разных листов?
Автор: OdesitVadim
Дата сообщения: 20.04.2005 12:41
Markell

Цитата:
Sheet := XLApp.Workbooks[ExtractFileName(AXLSFile)].WorkSheets[1];

как думаеш, что означает 1? - номер листа. тоесть в нужном месте вставляеш эту строку с нужным листом, и теперь будеш работать с ним
Автор: Markell
Дата сообщения: 20.04.2005 14:31
OdesitVadim
Попробовал поработать с разными листами. Получается такая ситуация:
Например, если всего 3 листа, то первые два он почему-то экспортировать не хочет (выдает ошибку), а нормально экспортирует только третий (последний).
Аналогичная ситуация с двумя, четырьмя и т.д. листами. Нормально экспортируется только последний.
И еще... если лист переименован, т.е. например вместо "Лист 1" будет написано "world", то опять же, экспортировать отказывается и выдает ошибку.
Автор: OdesitVadim
Дата сообщения: 20.04.2005 15:23
лист нужно "активировать" - тоесть переключиться на него
Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;
поробуй эту строку розкоментировать (соответственно закоментировав нижнюю)

Цитата:
// Sheet := XLApp.Workbooks[1].WorkSheets[1];

Автор: Markell
Дата сообщения: 20.04.2005 15:42
Все равно не получается.

Я пробую сначала запустить так:

Цитата:
Sheet := XLApp.Workbooks[ExtractFileName(AXLSFile)].WorkSheets[1];
Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;

- выдается ошибка.
Потом пробую так:

Цитата:
Sheet := XLApp.Workbooks[ExtractFileName(AXLSFile)].WorkSheets[2];
Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;

- опять выдается ошибка.
И наконец пробую так:

Цитата:
Sheet := XLApp.Workbooks[ExtractFileName(AXLSFile)].WorkSheets[3];
Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;

И только этот лист экспортируется нормально, потому что он последний. С чем это связано, понять не могу, в самом коде кроме номера листа я ничего не меняю.


Добавлено:
И еще... извиняюсь за чайнический вопрос, в хелпе так и не нашел...
Как потом из StringGrid передать числовое значение какой-то конкретной ячейки в переменную типа real?
Автор: YurikGL
Дата сообщения: 20.04.2005 16:51
Выбрать лист

e1.activeworkbook.sheets[номер].select;

присвоить значение

E1.ActiveWorkbook.Activesheet.Range['A'+IntToStr(i),'A'+IntToStr(i)].Formula:=SimpleDataSet2.fieldByName('user').Value;
Автор: Markell
Дата сообщения: 20.04.2005 20:40
А какого типа должно быть E1?
И для чего нужно 'user'?
Автор: ShIvADeSt
Дата сообщения: 21.04.2005 01:17
YurikGL
Слушай, не подскажешь, надо на дельфи в екселе сделать след. действия.
1) Объединить несколько ячеек в одну и поместить в центре текст (стандартная кнопка есть такая, какая ей соотв команда, в хелпе не нашел)
2) Есть две ячейки одна выше, другая ниже, надо их сделать равной вышины, равной сумма высот двух ячеек /2
3) Как выделить границы ячейки, со всех сторон?
Автор: OdesitVadim
Дата сообщения: 21.04.2005 11:32
ShIvADeSt
Есть простой способ решения подобных вопросов - сам пользуюсь. Если Нужное действие можем выполнить в Excel'e то можем и в Delphi.
1) Запускаем Excel и запускаем запись макроса.
2) Делаем нужные действия
3) Открываем редактор макросов и смотрим наш макрос.
4) Удаляем мусор - например я устанавливаю курсив, а он запишет ещё и размер буковок. Код насколько прозрачен, что вычистить довольно легко.
5) Теперь переносим в Делфи. Делфи обладает возможностью писать практически на VBA (делая поправку на синтаксис Паскаля).
Автор: Markell
Дата сообщения: 21.04.2005 15:06
Как вытаскивать данные из StringGrid я разобрался. А данные с разных листов из Экселевского файла так и не читаются? Может все-таки кто-то подскажет как правильно это делать, или в чем я ошибаюсь.
Автор: ShIvADeSt
Дата сообщения: 22.04.2005 00:42
OdesitVadim

Цитата:
Есть простой способ решения подобных вопросов - сам пользуюсь. Если Нужное действие можем выполнить в Excel'e то можем и в Delphi.
1) Запускаем Excel и запускаем запись макроса.
2) Делаем нужные действия
3) Открываем редактор макросов и смотрим наш макрос.
4) Удаляем мусор - например я устанавливаю курсив, а он запишет ещё и размер буковок. Код насколько прозрачен, что вычистить довольно легко.

Ты не понял, я так же пробовал, маленкая проблема, я не смог найти этих команд в хелпе по VBA, иначе бы не спрашивал

Цитата:
А данные с разных листов из Экселевского файла так и не читаются? Может все-таки кто-то подскажет как правильно это делать, или в чем я ошибаюсь.

qq:=Sheets[здесь указывается номер листа].Cells(col,row).Value;
Автор: Markell
Дата сообщения: 22.04.2005 01:05

Цитата:
Код:

uses
ComObj;
function Xls_To_StringGrid(AGrid: TStringGrid; AXLSFile: string): Boolean;
const
xlCellTypeLastCell = $0000000B;
var
XLApp, Sheet: OLEVariant;
RangeMatrix: Variant;
x, y, k, r: Integer;
begin
Result := False;
XLApp := CreateOleObject('Excel.Application');
try
XLApp.Visible := False;
XLApp.Workbooks.Open(AXLSFile);
// Sheet := XLApp.Workbooks[1].WorkSheets[1];
Sheet := XLApp.Workbooks[ExtractFileName(AXLSFile)].WorkSheets[1];
Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;
x := XLApp.ActiveCell.Row;
y := XLApp.ActiveCell.Column;
AGrid.RowCount := x;
AGrid.ColCount := y;
RangeMatrix := XLApp.Range['A1', XLApp.Cells.Item[X, Y]].Value;
k := 1;
repeat
for r := 1 to y do
AGrid.Cells[(r - 1), (k - 1)] := RangeMatrix[K, R];
Inc(k, 1);
AGrid.RowCount := k + 1;
until k > x;
RangeMatrix := Unassigned;
finally
if not VarIsEmpty(XLApp) then
begin
XLApp.Quit;
XLAPP := Unassigned;
Sheet := Unassigned;
Result := True;
end;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if Xls_To_StringGrid(StringGrid1, 'C:\All OLD\Мои документы\Розклад.xls') then
ShowMessage('Table has been exported!');
end;

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



Цитата:
qq:=Sheets[здесь указывается номер листа].Cells(col,row).Value;

А этот вариант я попробовал сюда применить - к сожалению не получилось.
Может кто-то сможет меня поправить?
Автор: GrayElf
Дата сообщения: 22.04.2005 04:23
Markell
Попробуй так

uses
ComObj;
function Xls_To_StringGrid(AGrid: TStringGrid; AXLSFile: string;SheetNum:integer): Boolean;
const
xlCellTypeLastCell = $0000000B;
var
XLApp, Sheet: OLEVariant;
RangeMatrix: Variant;
x, y, k, r: Integer;
begin
Result := False;
XLApp := CreateOleObject('Excel.Application');
try
XLApp.Visible := False;
XLApp.Workbooks.Open(AXLSFile);
// Sheet := XLApp.Workbooks[1].WorkSheets[1];
Sheet := XLApp.Workbooks[ExtractFileName(AXLSFile)].WorkSheets[SheetNum];
Sheet.activate;
Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate;
x := XLApp.ActiveCell.Row;
y := XLApp.ActiveCell.Column;
AGrid.RowCount := x;
AGrid.ColCount := y;
RangeMatrix := XLApp.Range['A1', XLApp.Cells.Item[X, Y]].Value;
k := 1;
repeat
for r := 1 to y do
AGrid.Cells[(r - 1), (k - 1)] := RangeMatrix[K, R];
Inc(k, 1);
until k > x;
RangeMatrix := Unassigned;
finally
if not VarIsEmpty(XLApp) then
begin
XLApp.Quit;
XLAPP := Unassigned;
Sheet := Unassigned;
Result := True;
end;
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if Xls_To_StringGrid(StringGrid1, 'C:\All OLD\Мои документы\Розклад.xls',strtoint(edit1.Text)) then
ShowMessage('Table has been exported!');
end;

Не срабатывало, потому что нужно было еще лист активизировать
(Sheet.activate;)

Добавлено:
OdesitVadim
Очень понравилось в вашем примере считывание ячеек Excel`а целым блоком, работает намного быстрее, чем поячеечно, а не подскажете, как обратную операцию проделать, т. е. записать в Excel`евский файл массив.
Попробовал создать двумерный динамический массив string, а потом преобразовать его процедурой DynArrayToVariant, ругается что не может преобразовать (Invalid variant type conversion)
Автор: Markell
Дата сообщения: 22.04.2005 09:03
GrayElf

Цитата:
Не срабатывало, потому что нужно было еще лист активизировать
(Sheet.activate;)

Спасибо большое! Все получилось. Оказывается, это было совсем не сложно.

Автор: OdesitVadim
Дата сообщения: 22.04.2005 09:49
ShIvADeSt

Цитата:
Объединить несколько ячеек в одну и поместить в центре текст (стандартная кнопка есть такая, какая ей соотв команда, в хелпе не нашел)


Цитата:
Ты не понял, я так же пробовал, маленкая проблема, я не смог найти этих команд в хелпе по VBA, иначе бы не спрашивал

Ты наверное считаеш, что для этого существует одна комманда? Ага, недождёшся
вот набросок кода, разберёшся думаю

Код:
Range('C4:C5').Select;
With Selection do
HorizontalAlignment := xlCenter;
VerticalAlignment := xlBottom;
WrapText := False;
Orientation := 0;
AddIndent := False;
IndentLevel := 0;
ShrinkToFit := False;
ReadingOrder := xlContext;
MergeCells := False;
End;
Selection.Merge
Автор: ShIvADeSt
Дата сообщения: 25.04.2005 03:44
OdesitVadim
Решил свой вопрос просто,
Цитата:

Excel.Sheets[1].Range['C22:C25'].Merge(False);

Теперь этот ексель спрашивает насчет того что ячейки будут объединены и просит нажать одну из кнопок Ок или Отмена, как подавить этот диалог (можног конечно через поиск его найти и самому нажать, но как то не красиов )

Добавлено:
Нашел решение, надо просто перед объединением добавить Excel.DisplayAlerts:=False;
и все будет ок.
Автор: YurikGL
Дата сообщения: 25.04.2005 06:13
а не подскажете, как обратную операцию проделать, т. е. записать в Excel`евский файл массив.

посмотри здесь

http://allrussweb.com.ru/delphi/tehnology/olemsoffice/051.php

ключевые строчки

TableVals := VarArrayCreate([0, queSelectRecCount - 1, //кол-во строк
0, queSelectFieldsCount - 1], // кол-во столбцов
varOleStr);

...
TableVals[LineCounter, i] := Fields[i].AsString
...
XL.Range[XL.Cells[1, 1],
XL.Cells[queSelectRecCount,
queSelectFieldsCount]].Value := TableVals;



Автор: GrayElf
Дата сообщения: 25.04.2005 06:49
YurikGL
Большое спасибо, так все работает

Страницы: 123

Предыдущая тема: ??? Скрипт vbs отправки файла по почте ???


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.