DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: liangjiping168
今日帖子: 16
在线用户: 8
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 tuao (tuao) ★☆☆☆☆ -
盒子活跃会员
2022/7/13 21:12:03
标题:
求可以解析Doc文件(*.doc,不是*.docx)的方法 浏览:2772
加入我的收藏
楼主: 控件、类、函数,delphi能使用的Dll都可以,只需要能解析出文档文本就行。
----------------------------------------------
tuao
作者:
男 hz_2009 (盒子) ★☆☆☆☆ -
普通会员
2022/7/14 8:10:37
1楼: OLE?
----------------------------------------------
-
作者:
男 lordaeron (Terry) ★☆☆☆☆ -
禁用账号
2022/7/14 8:28:17
2楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
该账号是个傻逼
作者:
男 kwer (★★★★★) ★☆☆☆☆ -
普通会员
2022/7/14 8:30:38
2楼: doc协议好像不公开的,wps能用是因为N年前人家就有相互公开许可,,,破解工作也不知道有没有人做?
----------------------------------------------
==========-==========-==========-==========-==========
     多隆, 给我备一匹最快的马, 我有事要走先~~~
==========-==========-==========-==========-==========
作者:
男 doersoft (hnysoft.com) ★☆☆☆☆ -
普通会员
2022/7/14 8:47:35
3楼: Delphi中一般都是通过OLE读取,像JAVA可以通过XWPFDocument去读取
----------------------------------------------
delphi|vue|golang hnysoft|hnyerp+mes+srm
作者:
男 chen9900 (chen) ★☆☆☆☆ -
盒子活跃会员
2022/7/14 9:15:09
4楼: 你这思路太死。ole把doc转换成docx.再来解析docx。
----------------------------------------------
-
作者:
男 ddrfan (若苗瞬) ▲▲▲▲▲ -
普通会员
2022/7/14 10:24:32
5楼: 就OLE了吧,看到以前读表格的代码大概:
...
  WordApp: TWordApplication;
  WordDoc: TWordDocument;
  一堆OleVariant变量。。。
...
  WordApp:= TWordApplication.Create(nil);
  WordDoc:= TWordDocument.Create(nil);
  WordApp.Documents.open(FileName,EmptyParam,true,EmptyParam,EmptyParam,...);
  WordDoc.ConnectTo(WordApp.Documents.Item(1));
  For i := 1 To WordDoc.Tables.Count do
  begin
    myRow:=WordDoc.Tables.Item(i).Rows.Item(1);
    ...
    For j:= 1 To myRow.Cells.Count do
    begin
      myCell:=WordDoc.Tables.Item(i).Cell(1,j);
      ...
    end;
  end;
  ...
----------------------------------------------
Bye bye DDRFAN...
作者:
男 lordaeron (Terry) ★☆☆☆☆ -
禁用账号
2022/7/14 11:19:20
6楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
该账号是个傻逼
作者:
男 wk_knife (wk_knife) ★☆☆☆☆ -
盒子活跃会员
2022/7/14 12:55:48
7楼: github上有,类似rtf格式。解析还算好说,要回显就难了。
----------------------------------------------
-
作者:
男 lordaeron (Terry) ★☆☆☆☆ -
禁用账号
2022/7/14 13:44:35
8楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
该账号是个傻逼
作者:
男 xuchuantao (暗黑天使) ★☆☆☆☆ -
普通会员
2022/7/14 18:19:27
9楼: XtremeDocumentStudio Delphi控件
----------------------------------------------
按此在新窗口浏览图片
作者:
男 tuao (tuao) ★☆☆☆☆ -
盒子活跃会员
2022/7/19 21:14:00
10楼: 我的目的就只是获取doc文件的正文文本,不用显示,不用编辑。
现在用的就是ole方式,它太慢了。
我从这里找到点资料,但看起来太复杂
http://t.zoukankan.com/Leo_wl-p-2966180.html
就想在论坛里看看有没有人已经实现了的。
----------------------------------------------
tuao
作者:
男 tony2u (tony2u) ★☆☆☆☆ -
普通会员
2022/7/19 21:16:29
11楼: https://github.com/tony2u/docxx
C++的
----------------------------------------------
-
作者:
男 yookee (yookee) ★☆☆☆☆ -
盒子活跃会员
2022/7/20 0:53:04
12楼: Binary File Format(BIFF)
https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-doc/ccd7b486-7881-484c-a137-51170af7cc22
----------------------------------------------
-
作者:
男 xuchuantao (暗黑天使) ★☆☆☆☆ -
普通会员
2022/7/20 22:06:56
13楼: uses Vcl.gtxDOCDocument, gtWordDOMClasses,gtClasses;

procedure TForm1.sButton1Click(Sender: TObject);
var
  Run: TgtRun;
  DOCDocument: TgtxDOCDocument;
  Section: TgtSection;
  Paragraph: TgtParagraph;
  RunItem, ParaItem, TextItemItem: TgtDocItem;
  TextItem: TgtTextItem;
  PageElements: TObjectList<TgtDocItem>;
begin
  DOCDocument := TgtxDOCDocument.Create;
  DOCDocument.LoadFromFile(sFilenameEdit1.Text);
  for Section in DOCDocument.DOCHandler.Sections do
  begin
    for ParaItem in Section.Items do
    begin
      Paragraph := ParaItem as TgtParagraph;
      for RunItem in Paragraph.Items do
      begin
        if RunItem Is TgtRun then
        begin
          Run := RunItem as TgtRun;
          for TextItemItem in Run.Items do
          begin
          if TextItemItem is TgtTextItem then
          begin
          TextItem := TextItemItem as TgtTextItem;
          Showmessage(TextItem.Text);
          end;
          end; // }
        end;
      end;
    end;
  end;
  DOCDocument.Free;
end;
XtremeDocumentStudio Delphi解析类可以处理,但对doc中文文档有兼容性问题.
----------------------------------------------
按此在新窗口浏览图片
作者:
男 zhangshelly (雪莱) ★☆☆☆☆ -
盒子活跃会员
2022/7/23 7:52:59
14楼: WPtools 试过没有?
----------------------------------------------
-
作者:
男 qq81709989 (战石电子) ▲▲△△△ -
普通会员
2022/7/23 9:56:37
15楼: WPtools对.docx的兼容性都不太好!
----------------------------------------------
《Z-Gantt战石智慧时间管理进度计划甘特图软件》:WWW.Z-SHi.NET
作者:
男 tuao (tuao) ★☆☆☆☆ -
盒子活跃会员
2022/7/24 16:55:14
16楼: 正在尝试自己解析doc文本,在对类Free时产生错误,实在找不到原因,请教各位:
原码如下:
constructor TDocFile.Create(filename: string);
begin
  FOK:=false;
  FIsdoc := false;
  try
    FStream := TFileStream.Create(filename, fmOpenRead or fmShareDenyNone);
    if FStream.Size>512 then
    GetDocheader
    else  raise Exception.Create('Doc文件打开失败:' + filename);
  except
    raise Exception.Create('Doc文件打开失败:' + filename);
  end;
end;

destructor TDocFile.Destroy;
begin
 if Assigned(FStream) then
  FreeAndNil(FStream);
 inherited;
end;// 就是在执行到这里时,会跳到system单元的这个函数
    //procedure TMonitor.Destroy;
    //begin
    //  if (MonitorSupport <> nil) and (FLockEvent <> nil) then 在这句里出错
    //    MonitorSupport.FreeSyncObject(FLockEvent);
    //  SysFreeMem(@Self);
    //end;

procedure TDocFile.free;
begin
if self<>nil then
  Destroy;
end;

function TDocFile.GetDirectory: TDOC_Directory;
begin
 //
end;


function TDocFile.GetDocheader: TDocHeader;
begin
if Assigned(FStream) then
begin
  FStream.Position := 0;
  if FStream.Read(FHeaderinfo, SizeOf(TDocHeader)) <> 512 then
    raise Exception.Create('Doc文件头信息获取失败。')
    else
    begin
     FOk:=true;
     setisdoc;
     if fisdoc then
     GetFirstDirectory;
    end;
end;
end;

function TDocFile.GetFirstDirectory: TDOC_Directory;
 function IntPower(Base: integer; const Exponent: LongWord):Int64;
  var
    I: Integer;
begin
  if Expon_ent=0 then result:=1
  else if Expon_ent=1 then result:=base
   else
    begin
      result:=Base;
    for I := 2 to Exponent do
      result:=result*base;
    end;
end;

begin
 Fstream.Position:=512+IntPower(2,fheaderinfo.sectorSize)*fheaderinfo.startDirectory;
 FStream.Read(FFirstDirectory,128);
end;

function TDocFile.loadfromfile(filename: string): boolean;
begin
FreeAndNil(FStream);
Fstream:=TFileStream.Create(filename,fmOpenRead or fmShareDenyNone);
    if FStream.Size>512 then
    GetDocheader
    else  raise Exception.Create('Doc文件打开失败:' + filename);
end;

function TDocFile.loadfromstream(stream: tstream): boolean;
begin
Fstream.CopyFrom(stream);
    if FStream.Size>512 then
    GetDocheader
    else  raise Exception.Create('Doc文件打开失败');
end;

procedure TDocFile.setisdoc;
begin
 if FOk then
  begin
   if (FHeaderinfo.doctag[0] = $D0) and (FHeaderinfo.doctag[1] = $CF) and
    (FHeaderinfo.doctag[2] = $11) and (FHeaderinfo.doctag[3] = $E0) and
    (FHeaderinfo.doctag[4] = $A1) and (FHeaderinfo.doctag[5] = $B1) and
    (FHeaderinfo.doctag[6] = $1A) and (FHeaderinfo.doctag[7] = $E1) then
    FIsdoc := True
  end
  else FIsdoc:=false;
end;

错误信息看图片
此帖子包含附件:
PNG 图像
大小:5.3K
----------------------------------------------
tuao
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2022/7/25 0:57:29
17楼: 你的 TDocFile 是从什么东西继承的?

你的错误是 TMonitor 里面出来的。那么,你的程序会用到 TMonitor 吗?

这个 TMonitor 是多线程用的。你在线程中使用 TDocFile?

你的 TDocFile 有没有用到 OLE 去处理 WORD 文档?如果使用 OLE 的话,同时又是在多线程中使用的话,可能会有很多问题。至少需要考虑执行 ActiveX.CoInitialization 这样的代码来使得多线程中调用 OLE (实际上是 COM 或者 DCOM)满足多线程调用 COM 的基本要求。
----------------------------------------------
-
作者:
男 tuao (tuao) ★☆☆☆☆ -
盒子活跃会员
2022/7/25 22:28:08
18楼: TDocfile直接从最基类继承,没有使用ole。

interface

uses
  Winapi.Windows, System.SysUtils, System.Variants, System.Classes;

type
  TDocHeader = record
    doctag: array [0 .. 7] of byte;
    classid: array [0 .. 15] of byte;
    ver1: word;
    ver2: word;
    littleendian: word;
    sectorSize: word;
    miniSectorSize: word;
    space: array [0 .. 9] of byte; // 预留空白
    fatCount: dword;
    startDirectory: dword; // 是Directory开始的SectorID
    affair: dword; // 事务 留空
    streamSize: dword;
    startMiniFat: dword;
    miniFatCount: dword;
    startDif: dword;
    difCount: dword;
    fat109: array [0 .. 108] of dword;
  end;
{$Z1}

  TDirectoryEntryType = (DET_Invalid, DET_Storage, DET_Stream, DET_LockBytes,
    DET_Property, DET_Root);

  TDOC_Directory= record
    name: array [0 .. 31] of WideChar; // 存储DirectoryEntry名称
    nameLength: word; // 是DirectoryEntry名称的长度
    _type: TDirectoryEntryType; // 是DirectoryEntry的类型
    leftID: dword; // 是该DirectoryEntry左兄弟的EntryID
    rightID: dword; // 是该DirectoryEntry右兄弟的EntryID。
    childrenID: dword; // 是该DirectoryEntry一个孩子的EntryID。
    sectorID: dword; // 是该DirectoryEntry开始的SectorID。
    contenLength: dword; // 是该DirectoryEntry存储的所有字节长度
  end;

  PDocHeader = ^TDocHeader;

  TDocFile = class
  private
    FOk:Boolean;
    FDirectoryEntry: TDOC_Directory;
    FFilename: string;
    FStream: TFileStream;
    FIsdoc: Boolean;
    FHeaderinfo: TDocHeader;
    FFirstDirectory:TDOC_Directory;
  protected
    function GetDocheader: TDocHeader;
    function GetFirstDirectory: TDOC_Directory;
    function GetDirectory: TDOC_Directory;
    procedure setisdoc;
  public
    constructor Create(filename: string);
    destructor Destroy;override;
    function loadfromfile(filename:string):boolean;
    function loadfromstream(stream:tstream):boolean;
    property headerinfo: TDocHeader read FHeaderinfo;
    property isdoc: Boolean read FIsdoc;
    property FirstDirectory:TDOC_Directory read FFirstDirectory;
    procedure free;
    { Public declarations }

  end;

const
  HeaderSize = 512;
  DEsize = 128;

implementation
{ TDocFile }
----------------------------------------------
tuao
作者:
男 138soft (138soft) ★☆☆☆☆ -
盒子活跃会员
2022/7/25 22:46:57
18楼: 很久以前做过。附件是Delphi7的dcu
此帖子包含附件:138soft_2022725224656.rar 大小:233.2K
----------------------------------------------
是你上错了车,还是我下错了站?
作者:
男 sail2000 (小帆工作室) ★☆☆☆☆ -
盒子活跃会员
2022/7/26 13:23:49
19楼: 涛哥都被炸出来了啊
----------------------------------------------
delphi 是兴趣,和工作无关,即使它倒闭。又不靠它 delphi 吃饭,怕甚?
作者:
男 138soft (138soft) ★☆☆☆☆ -
盒子活跃会员
2022/7/26 14:34:09
20楼: 因为实在看不下去了
----------------------------------------------
是你上错了车,还是我下错了站?
作者:
男 tuao (tuao) ★☆☆☆☆ -
盒子活跃会员
2022/7/26 22:43:55
21楼: @138soft
能不能给个源码学习一下,或给个10.4能用的dcu
----------------------------------------------
tuao
作者:
男 138soft (138soft) ★☆☆☆☆ -
盒子活跃会员
2022/7/27 15:06:50
22楼: 根据你的问题标题要求,给你一个Dll吧。

office的文件格式是公开的,可以在微软网站找到。

office的文件格式分为两种,一种是旧的,可以使用复合文件API来读取、分析,一种是以x结尾的新式文件(比如说:docx),这种格式实际上使用了XML文件,文件本身实际上是zib格式,可以把文件扩展名改为zip然后就可以直接用解压缩软件打开。
此帖子包含附件:138soft_202272715649.rar 大小:198.7K
----------------------------------------------
是你上错了车,还是我下错了站?
作者:
男 hardnut (麦轲数据管家) ★☆☆☆☆ -
普通会员
2022/7/28 8:18:45
23楼: rtf的格式就已经非常头大了,  docx 更是复杂的不得了,如果不是核心功能,不打算长期发展, 还是用第三方的东西吧, 比如 RichView 19开始就有导入,导入 docx的功能.
----------------------------------------------
UniKeeper V10.40 -- 您最贴心的个人数据管理助手
作者:
男 138soft (138soft) ★☆☆☆☆ -
盒子活跃会员
2022/7/28 14:22:39
24楼: docx是最简单的,改为zip文件名称,打开,word\document.xml就是所有文字内容了,基本上无需解释,只需要找一个zlib直接解开docx即可。
一般提取文字,用于搜索引擎、资料数据自动入库等等,如果是显示,方案多的很。
此帖子包含附件:
PNG 图像
大小:61.3K
----------------------------------------------
是你上错了车,还是我下错了站?
作者:
男 tuao (tuao) ★☆☆☆☆ -
盒子活跃会员
2022/7/28 23:11:02
25楼: 非常感谢@138soft (138soft)
docx我已经自己搞定了,doc用你的dll的话,在delphi10.4下有问题:
1.对docx支持不够好,存在内容获取不全、错乱等问题
2.对于doc,当文档字数较多(比如超过5000个中文字)时,引起程序崩溃
 if OfficeFileToStr(PwideChar(od.FileName),@Ptext) then  //Ptext不能是局部变量
  begin
  ss:=StrPas(pchar(@Ptext));//这句可以执行
  memo1.Lines.Text:=ss;  //超过约5000字时,程序崩溃,就算再将ss:='abc'后再给memo赋值也一样崩溃
  LocalFree(HLOCAL(pText));
  end;
----------------------------------------------
tuao
作者:
男 lordaeron (Terry) ★☆☆☆☆ -
禁用账号
2022/7/28 23:23:59
26楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
该账号是个傻逼
作者:
男 lordaeron (Terry) ★☆☆☆☆ -
禁用账号
2022/7/29 11:15:48
27楼: ……
被禁用帐号,帖子内容自动屏蔽!
……

----------------------------------------------
该账号是个傻逼
作者:
男 138soft (138soft) ★☆☆☆☆ -
盒子活跃会员
2022/7/29 18:12:59
28楼: ss:=StrPas(pchar(@Ptext));//这句可以执行
  memo1.Lines.Text:=ss; 

Ptext已经是指针了,为什么要获取指针的指针?指针的指针指向哪里?

直接memo1.Lines.Text:=Ptext就可以了。
----------------------------------------------
是你上错了车,还是我下错了站?
作者:
男 138soft (138soft) ★☆☆☆☆ -
盒子活跃会员
2022/7/29 23:28:12
29楼: 另外,你上面写的“//Ptext不能是局部变量”应该是不成立的。问题的根源应该还是你错误的引用了指针的指针,间接访问(计数器自动释放)了无效的内存。
----------------------------------------------
是你上错了车,还是我下错了站?
作者:
男 tuao (tuao) ★☆☆☆☆ -
盒子活跃会员
2022/7/30 9:57:11
30楼: 以上示例是在10.4下实际操作过的,
如果直接:memo1.lines.text:=Ptext;无论文档大小,均错误;
反而memo1.Lines.Text:=strpas(pchar(@ptext));在字数少时可以正确显示,字数多了就错误。
还有://Ptext不能是局部变量也是试验过的,如果是局部变量OfficeFileToStr(PwideChar(od.FileName),@Ptext)这句就通不过。

而且:如果字数多的话,下面过程也是错误:
 if OfficeFileToStr(PwideChar(od.FileName),@Ptext) then  //Ptext不能是局部变量
  begin
  memo1.Lines.Text:='abc';//这句也是出错  
  LocalFree(HLOCAL(pText));
end;
----------------------------------------------
tuao
作者:
男 138soft (138soft) ★☆☆☆☆ -
盒子活跃会员
2022/7/30 21:33:02
31楼: 不好意思,是DLL导出函数有问题。

function OfficeFileToStr(pwszFileName: PWideChar; ppText: PPWideChar): BOOL; stdcall;
var
  wstrText: WideString;
  nLen:Integer;
begin
  Result := False;
  wstrText := OfficeFileToTxt(pwszFileName);
  if wstrText = '' then Exit;

  nLen:=Length(wstrText)*2;

  ppText^:= Pointer(LocalAlloc(LPTR,nLen+2));
  if ppText^=nil then Exit;
  Move(wstrText[1],ppText^^,nLen);//原来写成了ppText^,这里应该是指针的指针
  Result:=True;
end;

应该没事了,因为手头没有office文档,无法测试,你可以测试看看。docx应该是手工解释XML的时候有些格式没有兼顾,使用第三方XML控件应该没事。
此帖子包含附件:138soft_2022730213256.rar 大小:810.2K
----------------------------------------------
是你上错了车,还是我下错了站?
作者:
男 tuao (tuao) ★☆☆☆☆ -
盒子活跃会员
2022/7/31 17:14:05
32楼: 感谢 138soft (138soft)不嫌麻烦的多次给我改代码。

我安装了delphi7,自己封装了一个dll,可以正常在D7和10.4下使用,直接使用Widestring作为参数和返回值,代码就一句,简单明了,对于其他语言可能不能兼容,但我仅仅用在delphi上,没有任何问题:
function OfficeFileToStr(FileName: Widestring): widestring; stdcall;
begin
 Result := OfficeFileToTxt(FileName);
end;
----------------------------------------------
tuao
作者:
男 sbcnet (sbc) ▲▲▲△△ -
普通会员
2022/8/1 15:27:49
33楼: 试了dll读取2021版word生成的docx,解析出文本不全
----------------------------------------------
-
作者:
男 138soft (138soft) ★☆☆☆☆ -
盒子活跃会员
2022/8/1 17:44:52
34楼: 试了dll读取2021版word生成的docx,解析出文本不全

是的,原因和解决方案上面几个帖子已经说了。x系列的都是zip格式,很容易弄的,非x的是对着微软的文档搞的,应该不会有问题。


最近都在搞c语言了,所以有时候迷糊了。Delphi访问指针内容是x^,C是*x,所以第一个demo直接messagebox &x了。


这个东西主要是出于安全提取,因为如果office文件有溢出的话,调用com接口,实际上会中马的,走文件格式解释就不会。
----------------------------------------------
是你上错了车,还是我下错了站?
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行136.7188毫秒 RSS