31 java pdf validation text
我在Java中使用PdfBox从PDF文件中提取文本.提供的某些输入文件无效,PDFTextStripper会暂停这些文件.是否有一种干净的方法来检查提供的文件是否确实是有效的PDF?
Nin*_*oss 22
以下是我在NUnit测试中使用的内容,它必须针对使用Crystal Reports生成的多个PDF版本进行验证:
public static void CheckIsPDF(byte[] data)
{
Assert.IsNotNull(data);
Assert.Greater(data.Length,4);
// header
Assert.AreEqual(data[0],0x25); // %
Assert.AreEqual(data[1],0x50); // P
Assert.AreEqual(data[2],0x44); // D
Assert.AreEqual(data[3],0x46); // F
Assert.AreEqual(data[4],0x2D); // -
if(data[5]==0x31 && data[6]==0x2E && data[7]==0x33) // version is 1.3 ?
{
// file terminator
Assert.AreEqual(data[data.Length-7],0x25); // %
Assert.AreEqual(data[data.Length-6],0x25); // %
Assert.AreEqual(data[data.Length-5],0x45); // E
Assert.AreEqual(data[data.Length-4],0x4F); // O
Assert.AreEqual(data[data.Length-3],0x46); // F
Assert.AreEqual(data[data.Length-2],0x20); // SPACE
Assert.AreEqual(data[data.Length-1],0x0A); // EOL
return;
}
if(data[5]==0x31 && data[6]==0x2E && data[7]==0x34) // version is 1.4 ?
{
// file terminator
Assert.AreEqual(data[data.Length-6],0x25); // %
Assert.AreEqual(data[data.Length-5],0x25); // %
Assert.AreEqual(data[data.Length-4],0x45); // E
Assert.AreEqual(data[data.Length-3],0x4F); // O
Assert.AreEqual(data[data.Length-2],0x46); // F
Assert.AreEqual(data[data.Length-1],0x0A); // EOL
return;
}
Assert.Fail("Unsupported file format");
}
Run Code Online (Sandbox Code Playgroud)
你可以找到一个文件(或字节数组)的mime类型,所以你不要愚蠢地依赖扩展.我是用光学的MimeExtractor(http://aperture.sourceforge.net/)做的,或者我前几天看到了一个图书馆(http://sourceforge.net/projects/mime-util)
我使用光圈从各种文件中提取文本,不仅仅是pdf,而且必须调整为pdfs思考(光圈使用pdfbox,但我在pdfbox失败时添加了另一个库作为后备)
由于您使用PDFBox,您可以简单地执行:
PDDocument.load(file);
Run Code Online (Sandbox Code Playgroud)
如果PDF损坏等,它将以异常失败.
如果成功,您还可以检查PDF是否使用加密 .isEncrypted()
这里是NinjaCross代码的改编Java版本.
/**
* Test if the data in the given byte array represents a PDF file.
*/
public static boolean is_pdf(byte[] data) {
if (data != null && data.length > 4 &&
data[0] == 0x25 && // %
data[1] == 0x50 && // P
data[2] == 0x44 && // D
data[3] == 0x46 && // F
data[4] == 0x2D) { // -
// version 1.3 file terminator
if (data[5] == 0x31 && data[6] == 0x2E && data[7] == 0x33 &&
data[data.length - 7] == 0x25 && // %
data[data.length - 6] == 0x25 && // %
data[data.length - 5] == 0x45 && // E
data[data.length - 4] == 0x4F && // O
data[data.length - 3] == 0x46 && // F
data[data.length - 2] == 0x20 && // SPACE
data[data.length - 1] == 0x0A) { // EOL
return true;
}
// version 1.3 file terminator
if (data[5] == 0x31 && data[6] == 0x2E && data[7] == 0x34 &&
data[data.length - 6] == 0x25 && // %
data[data.length - 5] == 0x25 && // %
data[data.length - 4] == 0x45 && // E
data[data.length - 3] == 0x4F && // O
data[data.length - 2] == 0x46 && // F
data[data.length - 1] == 0x0A) { // EOL
return true;
}
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
还有一些简单的单元测试:
@Test
public void test_valid_pdf_1_3_data_is_pdf() {
assertTrue(is_pdf("%PDF-1.3 CONTENT %%EOF \n".getBytes()));
}
@Test
public void test_valid_pdf_1_4_data_is_pdf() {
assertTrue(is_pdf("%PDF-1.4 CONTENT %%EOF\n".getBytes()));
}
@Test
public void test_invalid_data_is_not_pdf() {
assertFalse(is_pdf("Hello World".getBytes()));
}
Run Code Online (Sandbox Code Playgroud)
如果你想出任何失败的单元测试,请告诉我.
Pdf 文件以“%PDF”开头(在 TextPad 或类似工具中打开一个并查看)
有什么理由不能只用 StringReader 读取文件并检查这个吗?
你必须尝试这个....
public boolean isPDF(File file){
file = new File("Demo.pdf");
Scanner input = new Scanner(new FileReader(file));
while (input.hasNextLine()) {
final String checkline = input.nextLine();
if(checkline.contains("%PDF-")) {
// a match!
return true;
}
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用我在此处和其他网站/帖子上找到的一些建议来确定 pdf 是否有效。我故意损坏了一个pdf文件,不幸的是,许多解决方案都没有检测到文件已损坏。
最终,在修改了 API 中的不同方法之后,我尝试了这个:
PDDocument.load(file).getPage(0).getContents().toString();
Run Code Online (Sandbox Code Playgroud)
这没有抛出异常,但确实输出了:
WARN [COSParser:1154] The end of the stream doesn't point to the correct offset, using workaround to read the stream, stream start position: 171, length: 1145844, expected end position: 1146015
Run Code Online (Sandbox Code Playgroud)
就个人而言,我希望在文件损坏时抛出异常,以便我可以自己处理它,但似乎我正在实现的 API 已经以自己的方式处理了它们。
为了解决这个问题,我决定尝试使用提供热语句的类 (COSParser) 来解析文件。我发现有一个子类,叫做PDFParser,它继承了一个叫做“setLenient”的方法,这是关键(https://pdfbox.apache.org/docs/2.0.4/javadocs/org/apache/pdfbox/pdfparser /COSParser.html)。
然后我实现了以下内容:
RandomAccessFile accessFile = new RandomAccessFile(file, "r");
PDFParser parser = new PDFParser(accessFile);
parser.setLenient(false);
parser.parse();
Run Code Online (Sandbox Code Playgroud)
如我所愿,这为我损坏的文件抛出了异常。希望这可以帮助别人!