您有大量PDF报告、银行对账单或监管申报,里面的表格被锁住 — 您需要这些数字进入Excel,以便排序、筛选和运行公式。从PDF复制粘贴很少能保持列对齐,手工重新格式化数百个文件不是工作,而是惩罚。Total PDF Converter X可通过命令行批量从PDF文件提取表格到XLS工作簿,无需GUI,无需安装Microsoft Excel。将其安装在Windows服务器上,通过脚本或ActiveX调用,即可实现无人值守运行。
*.pdf),转换器即可在一次运行中处理所有匹配文件-EachPageSeparate将每个PDF页面写入自己的工作表,或将所有页面合并到一个
Windows 7/8/10/11 • Server 2008/2012/2016/2019/2022
PDF是最终形式的文档格式。页面是固定的,布局是冻结的,里面的数据是用来阅读、打印或归档的 — 而不是重新计算的。PDF中的银行对账单显示余额;它不允许您调整利息假设并观察列更新。PDF中的表格看起来像表格,但底层只是定位在页面坐标上的文本。
XLS是工作格式。每个数字位于带有行、列和数据类型的单元格中。您可以排序、筛选、透视、添加公式、绘制图表,并将结果喂入下游模型。当表格数据以PDF形式到达,下一步是分析时,数据必须先变成XLS。
| XLS | ||
|---|---|---|
| 用途 | 用于阅读和打印的最终形式输出 | 用于分析和重新计算的工作格式 |
| 单元格和公式 | 无 — 定位在页面上的文本 | 原生单元格、公式、引用、图表 |
| 排序和筛选 | 不支持 | 内置 |
| 透视表 | 不可能 | 原生Excel功能 |
| 复制粘贴保真度 | 列经常合并到一个 | 列保持分离 |
| 受众 | 读者、归档、监管机构 | 分析人员、会计、控制员 |
从上方链接下载安装程序,在Windows服务器或工作站上运行。安装不到一分钟即可完成。无需安装浏览器或Microsoft Excel — 转换器使用自有引擎解析PDF文本层并直接写入XLS文件。
打开cmd.exe或PowerShell。转换器可执行文件为PDFConverter.exe,位于安装文件夹中(通常为C:\Program Files\CoolUtils\TotalPDFConverterX\)。将其添加到系统PATH,或在命令中使用完整路径。
最简单的命令是将文件夹中所有PDF文件转换为XLS:
PDFConverter.exe C:\Reports\*.pdf C:\Output\ -c XLS
此命令处理C:\Reports\中的每个.pdf文件,并将生成的XLS工作簿保存到C:\Output\。每个PDF生成一个同名的XLS文件。
使用附加标志控制工作簿输出:
PDFConverter.exe C:\Reports\*.pdf C:\Output\ -c XLS -EachPageSeparate -log C:\Logs\pdf2xls.log
-EachPageSeparate — 将每个PDF页面放在工作簿内自己的工作表上-log C:\Logs\pdf2xls.log — 写入转换日志以便验证将命令保存到.bat文件中,并通过Windows任务计划程序安排执行:
@echo off "C:\Program Files\CoolUtils\TotalPDFConverterX\PDFConverter.exe" C:\Incoming\*.pdf C:\Archive\XLS\ -c XLS -EachPageSeparate -log C:\Logs\pdf2xls.log
此脚本每晚(或按您设定的任何间隔)运行提取,并写入日志文件以便您验证结果。
Total PDF Converter X包含完整的ActiveX接口。您可以从任何兼容COM的环境调用转换器 — .NET、VBScript、PHP、Python、Ruby或ASP。这使您能够将PDF到XLS的提取嵌入自己的Web应用、内部网门户或会计工作流,无需通过命令行进程调用。
示例(C#/.NET):
PDFConverterX Cnv = new PDFConverterX();
Cnv.Convert("C:\\Reports\\statement.pdf", "C:\\Output\\statement.xls", "-c XLS -EachPageSeparate -log c:\\Logs\\pdf.log");
示例(PHP):
$c = new COM("PDFConverter.PDFConverterX");
$c->convert("C:\\Reports\\statement.pdf", "C:\\Output\\statement.xls", "-c XLS -EachPageSeparate -log c:\\Logs\\pdf.log");
同样的调用方式适用于ASP.NET、VBScript、Python、Ruby、Perl和JavaScript(Windows Script Host)。您的Web应用可以接受上传的PDF,并实时向用户返回Excel工作簿。
| 功能 | 在线转换器 | Total PDF Converter X |
|---|---|---|
| 批量处理 | 一次一个文件 | 每批次无限文件 |
| 文件隐私 | 对账单上传至第三方服务器 | 文件不会离开您的机器 |
| 列对齐 | 常常将列折叠到一个单元格中 | 从文本层检测列边界 |
| 多页工作簿 | 单工作表,无控制 | -EachPageSeparate每页一个工作表 |
| 自动化 | 仅手动操作 | 命令行、.bat、任务计划程序、ActiveX |
| 服务器部署 | 不可能 | 专为服务器设计,无需GUI |
| 需要安装Excel | 不适用 | 否 |
| 需要互联网 | 是 | 否 |
转换器直接生成有效的XLS文件。您无需在服务器上安装Microsoft Office、LibreOffice或任何电子表格程序。这避免了授权成本,也避免了在无人值守场景中自动化Excel众所周知的不稳定问题。
Total PDF Converter X专为无人值守使用而设计。没有GUI窗口,没有对话框,没有确认提示。它从命令行静默运行,或作为服务的一部分运行 — 正是生产服务器所需要的。
XLS输出包含具有真正数据类型的真正单元格。数字是数值,列保持在列中,Excel功能 — 排序、筛选、公式、透视表、图表 — 立即可用。这不是带分隔符倾倒到单个单元格中的文本 — 这是真正的工作簿。
同一命令行工具可将PDF转换为DOC、XLSX、CSV、HTML、TIFF、JPEG、TXT等格式。一次安装即可满足所有PDF提取需求。将-c XLS改为-c CSV,即可获得具有相同批处理和自动化功能的CSV输出。请注意,转换器在基于文本的PDF上工作 — 仅扫描的图像PDF需要先进行OCR,本产品不包含OCR功能。
Windows 7/8/10/11 • Server 2008/2012/2016/2019/2022
"我们每月处理大约180份供应商发票和银行对账单,全部以PDF形式到达。Total PDF Converter X通过一个.bat任务在夜间将它们转换为XLS。列正确对齐,总数与源匹配,我们的调节宏读取工作簿的方式与读取从ERP导出的文件相同。-EachPageSeparate标志是决定性功能 — 多页对账单现在每个账户落入一个工作表。"
Caroline Whitfield Senior Accountant, Regional Manufacturing Group
"审计员的季度结算包以PDF报告形式返回。手工将它们拉入Excel是两天的工作。我们通过ActiveX接口将转换器连接到内部报表工具中;团队现在上传PDF并在几秒内得到一个可工作的XLS。透视表和我们现有的分析公式直接在输出上工作。服务器上无Office安装,财务和IT都希望如此。"
Tobias Lindgren Financial Controller, Logistics SaaS
"供应商价目表每周从约三十个供应商以PDF形式到达。手工复制表格不可靠 — 列总是会折叠。命令行转换器作为我们每周加载的一部分将每个列表拉入XLS,除一个供应商外(他们的PDF使用奇怪的布局),列边界都正确检测。对于其余的,工作簿直接喂入我们的定价模型。列检测标志的文档可以更详尽一些,但技术支持当天就做了回复。"
Priya Ramanathan Pricing Analyst, B2B Distributor
PDFConverter.exe C:\Reports\*.pdf C:\Output\ -c XLS。此命令将源文件夹中的每个PDF文件转换为XLS。添加-EachPageSeparate将每个PDF页面放在自己的工作表上,或-log写入验证日志。-EachPageSeparate标志,转换器会创建一个多工作表工作簿,每个PDF页面一个工作表。如果没有该标志,所有页面都合并到单个工作表中。对于每页涵盖不同账户或时段的月度对账单很有用。
string src="C:\\test\\Source.PDF";
string dest="C:\\test\\Dest.TIFF";
PDFConverterX Cnv = new PDFConverterX();
Cnv.Convert(src, dest, "-c TIFF -log c:\\test\\PDF.log");
MessageBox.Show("Convert complete!");
//与表单一起工作
Cnv.LoadFromFile(src);
Cnv.SetFormFieldValue(0, "Test Name");
Cnv.SaveToFile(src);
public static class Function1
{
[FunctionName("Function1")]
public static async Task Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
StringBuilder sbLogs = new StringBuilder();
sbLogs.AppendLine("started...");
try
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
var assemblyDirectoryPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
assemblyDirectoryPath = assemblyDirectoryPath.Substring(0, assemblyDirectoryPath.Length - 4);
var executablePath = $@"{assemblyDirectoryPath}\Converter\PDFConverterX.exe";
sbLogs.AppendLine(executablePath + "...");
var msgPath = $@"{assemblyDirectoryPath}\MSG\MSG.pdf";
var outPath = Path.GetTempFileName() + ".tiff";
startInfo.FileName = executablePath;
if (File.Exists(outPath))
{
File.Delete(outPath);
}
if (File.Exists(executablePath) && File.Exists(msgPath))
{
sbLogs.AppendLine("files exists...");
}
else
sbLogs.AppendLine("EXE & MSG files NOT exists...");
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = $"{msgPath} {outPath}";
using (Process exeProcess = Process.Start(startInfo))
{
sbLogs.AppendLine($"wait...{DateTime.Now.ToString()}");
exeProcess.WaitForExit();
sbLogs.AppendLine($"complete...{DateTime.Now.ToString()}");
}
int sleepCounter = 10;
while(!File.Exists(outPath) && sleepCounter > 0)
{
System.Threading.Thread.Sleep(1000);
sbLogs.AppendLine("sleep...");
sleepCounter--;
}
if (File.Exists(outPath))
sbLogs.AppendLine("Conversion complete successfully.");
}
catch (Exception ex)
{
sbLogs.AppendLine(ex.ToString());
}
return new OkObjectResult(sbLogs);
}
}
#include <windows.h>
static const CLSID CLSID_PDFConverterX =
{0x6B411E7E, 0x9503,0x4793,{0xA2, 0x87, 0x1F, 0x3B, 0xA8, 0x78, 0xB9, 0x1C}};
static const IID IID_IPDFConverterX =
{0xEF633BED, 0xC414,0x49B0,{0x91, 0xFB, 0xC3, 0x9C, 0x3F, 0xE0, 0x08, 0x0D}};
#undef INTERFACE
#define INTERFACE IPDFConverterX
DECLARE_INTERFACE_(IPDFConverterX, IDispatch)
{
STDMETHOD(QueryInterface)(THIS_ REFIID, PVOID*) PURE;
STDMETHOD(Convert)(THIS_ LPCTSTR, LPCTSTR, LPCTSTR) PURE;
STDMETHOD(About)(THIS) PURE;
//const SourceFile: WideString; const DestFile: WideString; const Params: WideString; safecall;
};
typedef HRESULT (__stdcall *hDllGetClassObjectFunc) (REFCLSID, REFIID, void **);
int main () {
HRESULT hr;
if (CoInitialize(NULL)) {
printf ("Error in CoInitialize.");
return -1;
}
LPCTSTR lpFileName = "PDFConverter.dll";
HMODULE hModule;
hModule = LoadLibrary (lpFileName);
printf ("hModule: %d\n", hModule);
if (hModule == 0) {
printf ("Error in LoadLibrary.");
return -1;
}
hDllGetClassObjectFunc hDllGetClassObject = NULL;
hDllGetClassObject = (hDllGetClassObjectFunc) GetProcAddress (hModule, "DllGetClassObject");
if (hDllGetClassObject == 0) {
printf ("Error in GetProcAddress.");
return -1;
}
IClassFactory *pCF = NULL;
hr = hDllGetClassObject (&CLSID_PDFConverterX, &IID_IClassFactory, (void **)&pCF);
/* Can't load with different ID */
printf ("hr hDllGetClassObject: %d\n", hr);
if (!SUCCEEDED (hr)) {
printf ("Error in hDllGetClassObject.");
return -1;
}
IPDFConverterX *pIN;
hr = pCF->lpVtbl->CreateInstance (pCF, 0, &IID_IPDFConverterX, (void **)&pIN);
printf ("hr CreateInstance: %d\n", hr);
if (!SUCCEEDED (hr)) {
printf ("Error in hDllGetClassObject.");
return -1;
}
hr = pCF->lpVtbl->Release (pCF);
printf ("hr Release: %d\n", hr);
if (!SUCCEEDED (hr)) {
printf ("Error in Release.");
return -1;
}
hr = pIN->lpVtbl->About (pIN);
printf ("hr About: %d\n", hr);
if (!SUCCEEDED (hr)) {
printf ("Error in About.");
return -1;
}
hr = pIN->lpVtbl->Convert (pIN, "test.pdf", "test.html","-cHTML");
printf ("hr Convert: %d\n", hr);
if (!SUCCEEDED (hr)) {
printf ("Error in Convert.");
return -1;
}
return 0;
}
dim C
Set C=CreateObject("PDFConverter.PDFConverterX")
C.Convert "c:\source.PDF", "c:\dest.HTML", "-cHTML -log c:\pdf.log"
set C = nothing
dim C
Set C=CreateObject("PDFConverter.PDFConverterX")
Response.Clear
Response.AddHeader "Content-Type", "binary/octet-stream"
Rresponse.AddHeader "Content-Disposition", "attachment; filename=test.TIFF"
Response.BinaryWrite c.ConvertToStream("C:\www\ASP\Source.PDF", "C:\www\ASP", "-cTIFF -log c:\PDF.log")
set C = nothing
$src="C:\\test.pdf";
$dest="C:\\test.tiff";
if (file_exists($dest)) unlink($dest);
$c= new COM("PDFConverter.PDFConverterX");
$c->convert($src,$dest, "-c TIFF -log c:\doc.log");
if (file_exists($dest)) echo "OK"; else echo "fail:".$c->ErrorMessage;
require 'win32ole'
c = WIN32OLE.new('PDFConverter.PDFConverterX')
src="C:\\test\\test.pdf";
dest="C:\\test\\test.tiff";
c.convert(src,dest, "-c TIFF -log c:\\test\\PDF.log");
if not File.exist?(dest)
puts c.ErrorMessage
end
import win32com.client
import os.path
c = win32com.client.Dispatch("PDFConverter.PDFConverterX")
src="C:\\test\\test.pdf";
dest="C:\\test\\test.tiff";
c.convert(src, dest, "-c TIFF -log c:\\test\\PDF.log");
if not os.path.exists(file_path):
print(c.ErrorMessage)
uses Dialogs, Vcl.OleAuto;
var
c: OleVariant;
begin
c:=CreateOleObject('PDFConverter.PDFConverterX');
C.Convert('c:\test\source.pdf', 'c:\test\dest.tiff', '-c TIFF -log c:\test\PDF.log');
IF c.ErrorMessage<> Then
ShowMessage(c.ErrorMessage);
end;
var c = new ActiveXObject("PDFConverter.PDFConverterX");
c.Convert("C:\\test\\source.pdf", "C:\\test\\dest.tiff", "-c TIFF");
if (c.ErrorMessage!="")
alert(c.ErrorMessage)
use Win32::OLE; my $src="C:\\test\\test.pdf"; my $dest="C:\\test\\test.tiff"; my $c = CreateObject Win32::OLE 'PDFConverter.PDFConverterX'; $c->convert($src,$dest, "-c TIFF -log c:\\test\\PDF.log"); print $c->ErrorMessage if -e $dest;