Как я могу определить, является ли файл файлом PDF? - PullRequest
30 голосов
/ 03 июня 2009

Я использую PdfBox в Java для извлечения текста из файлов PDF. Некоторые из предоставленных входных файлов недействительны, и PDFTextStripper останавливается на этих файлах. Есть ли простой способ проверить, является ли предоставленный файл действительно действительным PDF?

Ответы [ 12 ]

22 голосов
/ 09 февраля 2010

Вот то, что я использую в своих тестах NUnit, которые должны проверяться на наличие нескольких версий PDF, созданных с использованием Crystal Reports:

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");
    }
8 голосов
/ 06 июня 2009

вы можете узнать тип MIME файла (или байтового массива), так что вы не можете полагаться на расширение. Я делаю это с помощью MimeExtractor апертуры (http://aperture.sourceforge.net/) или я видел несколько дней назад библиотеку только для этого (http://sourceforge.net/projects/mime-util)

Я использую апертуру для извлечения текста из множества файлов, не только pdf, но мне нужно настроить, например, pdfs (aperture использует pdfbox, но я добавил другую библиотеку как запасной вариант, когда pdfbox не работает)

6 голосов
/ 20 февраля 2016

Здесь адаптированная Java-версия кода NinjaCross.

/**
 * 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;
}

И несколько простых юнит-тестов:

@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()));
}

Если у вас возникнут какие-либо неудачные юнит-тесты, пожалуйста, дайте мне знать.

6 голосов
/ 18 февраля 2011

Поскольку вы используете PDFBox, вы можете просто сделать:

PDDocument.load(file);

С исключением, если файл PDF поврежден и т.д., произойдет сбой.

Если это удается, вы также можете проверить, зашифрован ли PDF, используя .isEncrypted()

5 голосов
/ 23 февраля 2014

Вы должны попробовать это ....

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;
}
4 голосов
/ 17 мая 2017

Я использовал некоторые из предложений, которые я нашел здесь и на других сайтах / в постах, чтобы определить, является ли PDF верным или нет. Я намеренно испортил файл PDF, и, к сожалению, многие решения не обнаружили, что файл был поврежден.

В конце концов, после возни с разными методами в API, я попробовал это:

PDDocument.load(file).getPage(0).getContents().toString();

Это не выдало исключение, но вывело это:

 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

Лично я хотел, чтобы было выброшено исключение, если файл был поврежден, чтобы я мог обработать его сам, но оказалось, что 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();

Это вызвало исключение для моего поврежденного файла, как я и хотел. Надеюсь, это кому-нибудь поможет!

4 голосов
/ 03 июня 2009

Pdf файлы начинаются с "% PDF" (откройте один в TextPad или аналогичный и посмотрите)

По какой причине вы не можете просто прочитать файл с помощью StringReader и проверить это?

2 голосов
/ 13 апреля 2016

Может быть, я слишком поздно, чтобы ответить. Но вы должны взглянуть на Тику. Он использует PDFBox Parser для анализа PDF

Вам просто нужно импортировать tika-app-latest * .jar

 public String parseToStringExample() throws IOException, SAXException, TikaException 
 {

      Tika tika = new Tika();
      try (InputStream stream = ParsingExample.class.getResourceAsStream("test.pdf")) {
           return tika.parseToString(stream); // This should return you the pdf's text
      }
}

Это было бы намного чище. Вы можете обратиться сюда для более подробной информации об использовании Tika: https://tika.apache.org/1.12/api/

1 голос
/ 12 января 2018

В общем, нам может понравиться любая PDF-версия, заканчивающаяся на %% EOF, поэтому мы можем проверить, как показано ниже.

public static boolean is_pdf(byte[] data) {
        String s = new String(data);
        String d = s.substring(data.length - 7, data.length - 1);
        if (data != null && data.length > 4 &&
                data[0] == 0x25 && // %
                data[1] == 0x50 && // P
                data[2] == 0x44 && // D
                data[3] == 0x46 && // F
                data[4] == 0x2D) { // -

              if(d.contains("%%EOF")){
                 return true; 
              }         
        }
        return false;
    }
1 голос
/ 29 мая 2017

Ответ Роджера Киса неправильный! поскольку не все файлы PDF в версии 1.3 и не все прекращены EOL. Ответ ниже работает для всех не поврежденных PDF-файлов:

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...