2015-01-12 1 views
1

나는 내가 어디에 있는지 알 수있는 많은 게시물을 보았으며 프로그래밍에 익숙하지 않습니다. 내 의도는 "sourceDir"디렉토리 내의 파일을 가져와 Regex Match를 찾는 것입니다. Match가 발견되면 이름이 Match 인 새 파일을 만들고 싶습니다. 코드가 동일한 Match (파일이 이미 있음)가있는 다른 파일을 찾으면 해당 문서 내에 새 페이지를 만듭니다.C# iTextSharp - 페이지를 추가하는 대신 코드 덮어 쓰기

지금 코드는 작동하지만 새 페이지를 추가하는 대신 문서의 첫 페이지를 덮어 씁니다. 참고 : 디렉토리의 모든 문서는 한 페이지에 불과합니다!

string sourceDir = @"C:\Users\bob\Desktop\results\"; 
string destDir = @"C:\Users\bob\Desktop\results\final\"; 
string[] files = Directory.GetFiles(sourceDir); 
foreach (string file in files) 
    { 
     using (var pdfReader = new PdfReader(file.ToString())) 
      { 
       for (int page = 1; page <= pdfReader.NumberOfPages; page++) 
       { 
        var text = new StringBuilder(); 

        ITextExtractionStrategy strategy = new SimpleTextExtractionStrategy(); 
        var currentText = 
        PdfTextExtractor.GetTextFromPage(pdfReader, page, strategy); 

        currentText = Encoding.UTF8.GetString(Encoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes(currentText))); 
        text.Append(currentText); 

        Regex reg = new Regex(@"ABCDEFG"); 
        MatchCollection matches = reg.Matches(currentText); 

        foreach (Match m in matches) 
        { 
         string newFile = destDir + m.ToString() + ".pdf"; 

         if (!File.Exists(newFile)) 
         { 
          using (PdfReader reader = new PdfReader(File.ReadAllBytes(file))) 
          { 
           using (Document doc = new Document(reader.GetPageSizeWithRotation(page))) 
           { 
            using (PdfCopy copy = new PdfCopy(doc, new FileStream(newFile, FileMode.Create))) 
            { 
             var importedPage = copy.GetImportedPage(reader, page); 
             doc.Open(); 
             copy.AddPage(importedPage); 
             doc.Close(); 
            } 
           } 
          } 
         } 
         else 
         { 
          using (PdfReader reader = new PdfReader(File.ReadAllBytes(newFile))) 
          { 
           using (Document doc = new Document(reader.GetPageSizeWithRotation(page))) 
           { 
            using (PdfCopy copy = new PdfCopy(doc, new FileStream(newFile, FileMode.OpenOrCreate))) 
            { 
             var importedPage = copy.GetImportedPage(reader, page); 
             doc.Open(); 
             copy.AddPage(importedPage); 
             doc.Close(); 
            } 
           } 
          } 
         } 
        } 
       } 
      } 
     } 
+1

파일을 계속 덮어 쓰는 것처럼 보입니다. 바깥 쪽 루프에'PdfCopy' 인스턴스를 생성해야합니다. 사실, 당신의 코드를 이해하지 못합니다. 당신이 원하는 것과 일치하지 않는 것 같습니다. 코드를 문서화 할 수 있습니까 (예 : 원하는 것을 설명하는 설명을 추가하여)? –

+0

당신은 PdfCopy, PdfReader, Document를 의미합니까? 이 시점에서 PdfReader가 필요합니까? 최종 문서에서 두 번째, 세 번째 등의 페이지로 파일 (정규식 일치가 있음)을 추가하려고합니다. –

+0

내 목표는 최종 문서에 페이지를 추가하는 대신에 –

답변

2

브루노 (Bruno)는 문제를 설명하고 문제를 해결하는 방법을 잘 설명했지만 프로그래밍에 익숙하지 않고 새로운 것을 익혔다 고 말하면서 posted a very similar and related question 조금만 더 자세히 설명 드리겠습니다.

  1. :

    1. 각 PDF 그런 다음 단일 페이지

    목적이 PDF 파일의 전체 디렉토리있다 :

    첫째, 과학적 이해를 적어 보자 각 PDF의 텍스트를 추출하십시오

  2. 예전과 비교하십시오 패턴으로 tracted 텍스트 중 하나
  3. 다음 파일 이름을 경기를 할 사용하여 일치가 있다면
  4. : 파일이
  5. 에 원본 PDF를 추가 존재하는 경우
    1. 일치가없는 경우 의 PDF

계속하기 전에 알아야 할 몇 가지가있다하여 새 파일을 만듭니다. FileMode.OpenOrCreate을 사용하여 "추가 모드"에서 작업하려고했습니다. 그것은 좋은 추측 이었지만 부정확했습니다. PDF 형식에는 시작과 끝이 모두 있으므로 "여기에서 시작"과 "끝내기"가 있습니다. 기존 파일에 다른 PDF (또는 해당 내용)를 추가하려고하면 "여기에 끝"부분을 지나서 작성하는 것입니다. 기껏해야 정크 데이터가 무시되지만 더 많은 PDF가 손상 될 가능성이 높습니다. 거의 모든 파일 형식에서도 마찬가지입니다. XML 문서에는 하나의 루트 요소 만 있기 때문에 연결된 두 개의 XML 파일은 유효하지 않습니다.

둘째로 관련되었지만 iText/iTextSharp는 기존 파일을 편집 할 수 없습니다. 이건 매우 중요합니다. 그러나 다른 파일의 정확한 또는 수정 된 버전을 사용하는 새로운 파일을 만들 수 있습니다. 나는 이것이 얼마나 중요한지 강조 할 수 있는지 모르겠다.

셋째, 반복적으로 복사되는 줄을 사용하고 있지만 매우 잘못되어 실제로 데이터가 손상 될 수 있습니다. 그것이 왜 나쁜지에 대해서는 read this입니다.

currentText = Encoding.UTF8.GetString(Encoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes(currentText))); 

넷째, 검색을 수행하는 데 지나치게 복잡한 방법 인 RegEx를 사용하고 있습니다. 어쩌면 당신이 게시 한 코드는 단지 예제 일 뿐이지 만, 그렇지 않다면 currentText.Contains("")을 사용하거나, 아니면 currentText.IndexOf("", StringComparison.InvariantCultureIgnoreCase)을 무시할 필요가 있다면 추천 할 것입니다. 의심스러운 점을 위해 아래 코드에서는 RegEx가 더 복잡한 것으로 가정합니다.

아래 내용은 모든 것을 처리해야하는 완전한 작동 예제입니다. PDF에 액세스 할 수 없으므로 두 번째 섹션에서는 실제로 검색 용어가 추가 된 100 개의 샘플 PDF를 만듭니다. 귀하의 실제 코드는 분명히 그렇게하지 않을 것이지만 우리는 당신과 함께 일하는 공통점을 필요로합니다. 세 번째 섹션은 수행하려는 검색 및 병합 기능입니다. 바라건대 코드의 주석은 모든 것을 설명하기를 바랍니다.

/** 
* Step 1 - Variable Setup 
*/ 

//This is the folder that we'll be basing all other directory paths on 
var workingFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); 

//This folder will hold our PDFs with text that we're searching for 
var folderPathContainingPdfsToSearch = Path.Combine(workingFolder, "Pdfs"); 

var folderPathContainingPdfsCombined = Path.Combine(workingFolder, "Pdfs Combined"); 

//Create our directories if they don't already exist 
System.IO.Directory.CreateDirectory(folderPathContainingPdfsToSearch); 
System.IO.Directory.CreateDirectory(folderPathContainingPdfsCombined); 

var searchText1 = "ABC"; 
var searchText2 = "DEF"; 

/** 
* Step 2 - Create sample PDFs 
*/ 

//Create 100 sample PDFs 
for (var i = 0; i < 100; i++) { 
    using (var fs = new FileStream(Path.Combine(folderPathContainingPdfsToSearch, i.ToString() + ".pdf"), FileMode.Create, FileAccess.Write, FileShare.None)) { 
     using (var doc = new Document()) { 
      using (var writer = PdfWriter.GetInstance(doc, fs)) { 
       doc.Open(); 

       //Add a title so we know what page we're on when we combine 
       doc.Add(new Paragraph(String.Format("This is page {0}", i))); 

       //Add various strings every once in a while. 
       //(Yes, I know this isn't evenly distributed but I haven't 
       // had enough coffee yet.) 
       if (i % 10 == 3) { 
        doc.Add(new Paragraph(searchText1)); 
       } else if (i % 10 == 6) { 
        doc.Add(new Paragraph(searchText2)); 
       } else if (i % 10 == 9) { 
        doc.Add(new Paragraph(searchText1 + searchText2)); 
       } else { 
        doc.Add(new Paragraph("Blah blah blah")); 
       } 

       doc.Close(); 
      } 
     } 
    } 
} 

/** 
* Step 3 - Search and merge 
*/ 


//We'll search for two different strings just to add some spice 
var reg = new Regex("(" + searchText1 + "|" + searchText2 + ")"); 

//Loop through each file in the directory 
foreach (var filePath in Directory.EnumerateFiles(folderPathContainingPdfsToSearch, "*.pdf")) { 
    using (var pdfReader = new PdfReader(filePath)) { 
     for (var page = 1; page <= pdfReader.NumberOfPages; page++) { 

      //Get the text from the page 
      var currentText = PdfTextExtractor.GetTextFromPage(pdfReader, page, new SimpleTextExtractionStrategy()); 

      currentText.IndexOf("", StringComparison.InvariantCultureIgnoreCase) 



      //DO NOT DO THIS EVER!! See this for why https://stackoverflow.com/a/10191879/231316 
      //currentText = Encoding.UTF8.GetString(Encoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes(currentText))); 

      //Match our pattern against the extracted text 
      var matches = reg.Matches(currentText); 

      //Bail early if we can 
      if (matches.Count == 0) { 
       continue; 
      } 

      //Loop through each match 
      foreach (var m in matches) { 

       //This is the file path that we want to target 
       var destFile = Path.Combine(folderPathContainingPdfsCombined, m.ToString() + ".pdf"); 

       //If the file doesn't already exist then just copy the file and move on 
       if (!File.Exists(destFile)) { 
        System.IO.File.Copy(filePath, destFile); 
        continue; 
       } 

       //The file exists so we're going to "append" the page 
       //However, writing to the end of file in Append mode doesn't work, 
       //that would be like "add a file to a zip" by concatenating two 
       //two files. In this case, we're actually creating a brand new file 
       //that "happens" to contain the original file and the matched file. 
       //Instead of writing to disk for this new file we're going to keep it 
       //in memory, delete the original file and write our new file 
       //back onto the old file 
       using (var ms = new MemoryStream()) { 

        //Use a wrapper helper provided by iText 
        var cc = new PdfConcatenate(ms); 

        //Open for writing 
        cc.Open(); 

        //Import the existing file 
        using (var subReader = new PdfReader(destFile)) { 
         cc.AddPages(subReader); 
        } 

        //Import the matched file 
        //The OP stated a guarantee of only 1 page so we don't 
        //have to mess around with specify which page to import. 
        //Also, PdfConcatenate closes the supplied PdfReader so 
        //just use the variable pdfReader. 
        using (var subReader = new PdfReader(filePath)) { 
         cc.AddPages(subReader); 
        } 

        //Close for writing 
        cc.Close(); 

        //Erase our exisiting file 
        File.Delete(destFile); 

        //Write our new file 
        File.WriteAllBytes(destFile, ms.ToArray()); 
       } 
      } 
     } 
    } 
} 
+0

정말 감사합니다. 나는 브루노가 절대적으로 옳았다는 것에 동의한다. 나는 단지 pdfs가 어떻게 생성되는지에 대한 이해가 부족하다. PDF vs XML에 대한 귀하의 설명은 저에게 완벽했습니다. 제 실제 프로젝트에서 제공 한 테스트 케이스에서이 작업을 수행 할 수있었습니다. –

0

의사 코드로 작성합니다.

당신은 같은 것을 할 :

// loop over different single-page documents 
for() { 
    // introduce a condition 
    if (condition == met) { 
     // create single-page PDF 
     new Document(); 
     new PdfCopy(); 
     document.Open(); 
     copy.add(singlePage); 
     document.Close(); 
    } 
} 

이 단일 페이지 PDF를 조건이 충족 될 때마다 만드는 것을 의미한다. 덧붙여 말하면, 기존 파일을 여러 번 덮어 쓰는 것입니다.

// Create a document with as many pages as times a condition is met 
new Document(); 
new PdfCopy(); 
document.Open(); 
// loop over different single-page documents 
for() { 
    // introduce a condition 
    if (condition == met) { 
     copy.addPage(singlePage); 
    } 
} 
document.Close(); 

지금 당신은 아마도 당신이 PdfCopy으로 만드는 새 문서에 하나 이상의 페이지를 추가 : 당신은 무엇을해야

,이 같은 것입니다. 주의해야합니다. 조건이 충족되지 않으면 예외가 throw 될 수 있습니다.

+0

나는 당신의 제안 (또는 내가 당신이 제안한다고 믿는 바를)을 시도했고 나는 같은 결과를 얻고있다. iText 전체에 대한 이해가 부족하다고 생각합니다. 나는 그것을 완전히 깨뜨리기를 요구하고 싶지 않다. 나는 책을 가지고 있다는 것을 알고있다. 당신의 도움을 주셔서 감사합니다! –