【问题标题】:How to copy some content in one .docx to another .docx , using POI without losing format?如何使用 POI 将一个 .docx 中的某些内容复制到另一个 .docx 而不丢失格式?
【发布时间】:2020-05-31 05:27:18
【问题描述】:

假设我有两个.docx 文件,input.docxoutput.docx 我需要选择input.docx 中的一些内容,并将它们复制到output.docxnewdoc 在控制台中显示其内容似乎是正确的,但我在output.docx 中没有得到任何东西,除了空行。谁能给点建议?

InputStream is = new FileInputStream("D:\\input.docx"); 
XWPFDocument doc = new XWPFDocument(is);

List<XWPFParagraph> paras = doc.getParagraphs();  
List<XWPFRun> runs;
XWPFDocument newdoc = new XWPFDocument();                                     
for (XWPFParagraph para : paras) {  
            runs = para.getRuns();      
            if(!para.isEmpty())
            {
                XWPFParagraph newpara = newdoc.createParagraph(); 
                XWPFRun newrun = newpara.createRun();
                for (int i=0; i<runs.size(); i++) {                       
                    newrun=runs.get(i);
                    newpara.addRun(newrun);
                }
            }
        }


        List<XWPFParagraph> newparas = newdoc.getParagraphs(); 
        for (XWPFParagraph para1 : newparas) {  
            System.out.println(para1.getParagraphText());
        }// in the console, I have the correct information

        FileOutputStream fos = new FileOutputStream(new File("D:\\output.docx"));
        newdoc.write(fos);
        fos.flush();
        fos.close();

【问题讨论】:

  • 小心,在你的问题中你提到output.doc而不是.docx,这可能只是一个错字

标签: java apache-poi


【解决方案1】:

我稍微修改了你的代码,它复制文本而不改变文本格式。

public static void main(String[] args) {
    try {
        InputStream is = new FileInputStream("Japan.docx"); 
        XWPFDocument doc = new XWPFDocument(is);

        List<XWPFParagraph> paras = doc.getParagraphs();  

        XWPFDocument newdoc = new XWPFDocument();                                     
        for (XWPFParagraph para : paras) {  

            if (!para.getParagraphText().isEmpty()) {       
                XWPFParagraph newpara = newdoc.createParagraph();
                copyAllRunsToAnotherParagraph(para, newpara);
            }

        }

        FileOutputStream fos = new FileOutputStream(new File("newJapan.docx"));
        newdoc.write(fos);
        fos.flush();
        fos.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

// Copy all runs from one paragraph to another, keeping the style unchanged
private static void copyAllRunsToAnotherParagraph(XWPFParagraph oldPar, XWPFParagraph newPar) {
    final int DEFAULT_FONT_SIZE = 10;

    for (XWPFRun run : oldPar.getRuns()) {  
        String textInRun = run.getText(0);
        if (textInRun == null || textInRun.isEmpty()) {
            continue;
        }

        int fontSize = run.getFontSize();
        System.out.println("run text = '" + textInRun + "' , fontSize = " + fontSize); 

        XWPFRun newRun = newPar.createRun();

        // Copy text
        newRun.setText(textInRun);

        // Apply the same style
        newRun.setFontSize( ( fontSize == -1) ? DEFAULT_FONT_SIZE : run.getFontSize() );    
        newRun.setFontFamily( run.getFontFamily() );
        newRun.setBold( run.isBold() );
        newRun.setItalic( run.isItalic() );
        newRun.setStrike( run.isStrike() );
        newRun.setColor( run.getColor() );
    }   
}

fontSize 还是有一点问题。有时 POI 无法确定运行的大小(我将其值写入控制台以跟踪它)并给出 -1。当我自己设置它时,它完美地定义了字体的大小(例如,我在 Word 中选择了一些段落并手动设置其字体,无论是大小还是字体系列)。但是当它处理另一个 POI 生成的文本时,它有时会给出 -1。所以我引入了一个默认字体大小(上例中为 10),当 POI 给出 ​​-1 时设置。

Calibri 字体系列似乎出现了另一个问题。但在我的测试中,POI 默认将其设置为 Arial,所以我没有使用默认 fontFamily 的相同技巧,因为它是 fontSize。

其他字体属性(粗体、斜体等)运行良好。

可能所有这些字体问题都是由于在我的测试中文本是从 .doc 文件中复制的。如果您有 .doc 作为输入,请在 Word 中打开 .doc 文件,然后“另存为..”并选择 .docx 格式。然后在你的程序中只使用XWPFDocument 而不是HWPFDocument,我想它会没事的。

【讨论】:

  • 感谢您的回答。 POI没有我想象的那么好。我想知道是否有其他方法可以做同样的事情。我使用 .docx 文件(1.03mb,443pages,221803words)运行您的代码,存在 3 个问题: 1. 正如您所说,“-1”问题。几乎所有的字体都被识别为“-1”,所以输出并不完美,还丢失了数字的信息(如1., 2., 3.,)。我按照您的建议,将 doc 文件“另存为”为 .docx 文件,问题仍然存在。
  • 2.处理文档需要40多分钟(我的电脑是4G RAM的Inter-i7-3770)。我有数百个类似的文件,这太耗时了。 3.output.docx不能直接打开。它说无法打开 Office Open XML 文档 output.docx。文件有错误。幸运的是,我可以通过将文件恢复到新文件来打开它。无论如何,非常感谢您的回答。我会继续寻找更好的解决方案。
  • @flyingmouse 谢谢你的绿色标记。但我并不完全满意,因为你仍然有很大的问题。所以让我们试着看看我们能做些什么。哎呀,40分钟?那是巨大的!我从来没有处理过大文件,这就是为什么我从来没有真正关心过时间优化。但是现在是时候了 ;-) 上面的这段代码并不完美,我会尝试优化它。在这里我需要你的帮助:我想面临和你一样的问题,所以请告诉我你从一开始就执行的操作顺序:你从网站上获取 .doc,下一步是什么?
  • @flyingmouse 不幸的是,这段代码不应该保留数字“1. 2. 3.”。有一段时间,我没有处理它的代码。在工作中,我目前正在开发一个实用程序,它将处理 .docx 并过滤章节:用户选择要包含的章节/子章节,程序重新构建 .docx 以仅包含选定的章节,刷新编号。但我仍处于编写需求和设计架构的阶段。星期五我休假两周,直到八月底我才会写代码。你的任务紧急吗?
  • @flyingmouse 关于其他技术,我只听说过Jasper Reports,但我不能说在这里应用它是否真的很方便。 POI 并不理想,这是事实。但是,也许问题出在微软自己身上,因为他们在 .doc 和 .docx 格式之间进行了巨大的更改。尝试一个技巧:将任何example.docx 重命名为example.zip,然后解压缩它。您会看到一个文件结构,其中包含许多文件,如 document.xml、styles.xml 等。这就是 Microsoft 在 .docx 中存储数据的方式,它与 .doc 完全不同。这就是为什么 POI 的 HWPF 和 XWPF 几乎不兼容的原因
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-04
  • 1970-01-01
  • 2011-10-24
  • 2017-09-04
相关资源
最近更新 更多