Como ler um .doc (MS Word) sem ter o Word instalado.

23/06/2008

1

Meu aplicativo precisa ler o texto, um texto simples sem nenhuma formatação de um .doc, o problema é que o usuário não tem o Word instalado, sendo assim preciso saber interpretar o binário do arquivo para recuperar o texto. Agradeço muito se alguém puder me ajudar.


Responder

Posts

24/06/2008

Mkoch

Preciso ler o binário de um .doc (sem o Word instalado), para recuperar o texto que contém nele alguém tem alguma sugestão.


Responder

24/06/2008

Massuda

A opção ideal seria a pessoa receber o arquivo em formato texto (.TXT) ao invés de .DOC.

De qualquer forma, algumas opções:[list:7b721ae97f][*:7b721ae97f]usar o OpenOffice para ler ou converter o arquivo (não sei como se faz isso via programa)[*:7b721ae97f]usar o :arrow: [url=http://www.abisource.com/]AbiWord[/url] (um clone do Word) para ler ou converter o arquivo (tb não sei como se faz isso via programa)[*:7b721ae97f]estudar a especificação do formato .DOC (em inglês, :arrow: [url=http://www.microsoft.com/interop/docs/OfficeBinaryFormats.mspx]nesta página[/url]) e tentar ler o arquivo[/list:u:7b721ae97f]


Responder

24/06/2008

Mkoch

Valeu Massuda encontrei alguma coisa, mas é bem estranho por que o conteúdo da variável ´xText´ parece que está com um monte de caracteres estranhos, mas se dar um ´Pos´ por alguma palavra no texto acha. Como pode isso, eu queria extrair o texto, mas não dá.

uses
  ComObj, ActiveX, AxCtrls;

procedure TForm1.OpenWord(const aFileName: WideString);
var
  Root: IStorage;
  EnumStat: IEnumStatStg;
  Stat: TStatStg;
  iStm: IStream;
  Stream: TOleStream;
  DocTextString: String;
  xText: String;
  i: Integer;
begin
  if not FileExists(aFileName) then Exit;

  // Check to see if it´s a structured storage file 
  if StgIsStorageFile(PWideChar(aFileName)) <> S_OK then Exit;

  // Open the file 
  OleCheck(StgOpenStorage(PWideChar(aFileName), nil, STGM_READ or STGM_SHARE_EXCLUSIVE, nil, 0, Root));

  // Enumerate the storage and stream objects contained within this file 
  OleCheck(Root.EnumElements(0, nil, 0, EnumStat));

  // Check all objects in the storage 
  while EnumStat.Next(1, Stat, nil) = S_OK do

    // Is it a stream with Word data
    if Stat.pwcsName = ´WordDocument´ then
    //if Stat.pwcsName <> ´mk´ then

      // Try to get the stream "WordDocument" 
      if Succeeded(Root.OpenStream(Stat.pwcsName, nil, 
                    STGM_READ or STGM_SHARE_EXCLUSIVE, 0, iStm)) then
      begin
        Stream:=TOleStream.Create(iStm);
        try 
          if Stream.Size > 0 then 
          begin 
            // Move text data to string variable
            SetLength(xText, Stream.Size);
            Stream.Seek(0, soFromBeginning);
            Stream.Read(PChar(xText)^, Stream.Size);
            if xText <> ´´ then
            begin
            end;
            
            // Find a necessary text
           // Memo1.Lines.Append(String(DocTextString));
            i := Pos(´Teste´, xText); //COMO PODE ACHAR (E ACHA), VEM CHEIO DE "SUJEIRA???".
            if i > 0 then
            begin
              ShowMessage(´Achou!!!´);
            end;
          end; 
        finally 
          Stream.Free;
        end; 
        //Exit; 
      end; 
end;



Responder

25/06/2008

Mkoch

Sobe ^


Responder

26/06/2008

Massuda

...estranho por que o conteúdo da variável ´xText´ parece que está com um monte de caracteres estranhos...
O texto contem marcadores de formatação usados pelo Word... teria que ler a especificação para saber do que se trata.

Tenho um sistema que depende da conversão de DOC para TXT. Sinceramente, esse caminho que você está seguindo tem complicações relacionadas com o modo que o texto foi digitado e com a versão do Word que foi utilizada.

A solução inicial foi usar o pacote :arrow: [url=http://wvware.sourceforge.net/]wvWare[/url] para fazer a conversão (vc precisa do MinGW ou do Cygwin para compilar um executável para Windows). Mas com frequencia o conversor travava ou perdia parte do texto devido ao documento Word conter algo diferente do padrão (por exemplo, uma imagem ou uma formatação mais complexa).

Para evitar isso, hj usamos um Word 2008 para converter os DOC para DOCX, que é um formato documentado pela MS e normatizado pela especificação OpenXML, de modo que hoje tenho um programa Delphi capaz de processar diretamente os DOCX. No futuro, espero não precisar mais do Word pois a MS está providenciando um conversor DOC para DOCX como parte do esforço para estabelecer o padrão OpenXML.


Responder

01/07/2008

Mkoch

Gostaria de contribuir com o pessoal do Forum, segue abaixo uma solução a princípio funcionando corretamente para extrair o texto (Plain Text) de um documento Word sem ter o office instalado. Para chegar a essa solução li a documentação da Microsoft onde especifica o binário dos arquivos .doc, não foi ,uito fácil, mas enfim está ai. Se mais alguém tiver alguma informação a acrescentar ou comentar é bem vindo.


interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, OleServer, ComCtrls;

implementation
uses
ComObj, ActiveX, AxCtrls;

procedure TForm1.OpenWord(const aFileName: WideString);
const
cFib = 1472;
var
Root: IStorage;
EnumStat: IEnumStatStg;
Stat: TStatStg;
iStm: IStream;
Stream: TOleStream;
DocText, xText: String;
xFib: String;
xFC, xLCB: Integer;
xFlag1Table: Boolean;
xTableStreamName: String;
fcMin, ccpText, fcClx, lcbClx: Integer;
begin
if not FileExists(aFileName) then Exit;

// Check to see if it´s a structured storage file
if StgIsStorageFile(PWideChar(aFileName)) <> S_OK then Exit;

// Open the file
OleCheck(StgOpenStorage(PWideChar(aFileName), nil, STGM_READ or STGM_SHARE_EXCLUSIVE, nil, 0, Root));

// Enumerate the storage and stream objects contained within this file
OleCheck(Root.EnumElements(0, nil, 0, EnumStat));

// Check all objects in the storage
while EnumStat.Next(1, Stat, nil) = S_OK do
// Try to get the stream ´WordDocument´
if Succeeded(Root.OpenStream(Stat.pwcsName, nil,
STGM_READ or STGM_SHARE_EXCLUSIVE, 0, iStm)) then
begin
Stream:=TOleStream.Create(iStm);

try
if Stream.Size > 0 then
begin
if Stat.pwcsName = ´WordDocument´ then
begin
Stream.Seek(24, soFromBeginning);
Stream.ReadBuffer(fcMin, SizeOf(Integer));

Stream.Seek(76, soFromBeginning);
Stream.ReadBuffer(ccpText, SizeOf(Integer));

Stream.Seek(418, soFromBeginning);
Stream.ReadBuffer(fcClx, SizeOf(Integer));

Stream.Seek(422, soFromBeginning);
Stream.ReadBuffer(lcbClx, SizeOf(Integer));

if (fcMin > 0) and (ccpText > 0) then
begin
SetLength(xText, ccpText);
Stream.Seek(fcMin + 512, soFromBeginning);
Stream.ReadBuffer(PChar(xText)^, ccpText);
RichEdit1.Text := xText;
end;
end;
end;
finally
Stream.Free;
end;
end;
end;


Responder