5

これは、処理されるファイルのサイズ (50 ~ 100 MB の xml ファイル) により、Java VM の機能を超えている可能性があります。

現在、一連の xml ファイルを zip として送信しています。これらはすべて解凍され、ディレクトリ内のすべての XML が SAX を使用して一度に 1 つずつ処理されます。

時間とスペースを節約するために (圧縮率は約 1:10 であるため)、xml ファイルである ZipFileEntry を SAX ハンドラーに渡す方法はないかと考えていました。

DocumentBuilder やその他の xml 解析メソッドを使用してそれが行われるのを見てきましたが、パフォーマンス (および特にメモリ) のために、私は SAX を使い続けています。

現在、私は次の方法でSAXを使用しています

        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser saxParser = factory.newSAXParser();

        MyHandler handler = new MyHandler();

        for( String curFile : xmlFiles )
        {
            System.out.println( "\n\n\t>>>>> open " + curFile + " <<<<<\n");
            saxParser.parse( "file://" + new File( dirToProcess + curFile ).getAbsolutePath(), handler );
        }
4

2 に答える 2

8

InputStream をソースとして使用して XML を解析できます。したがって、ZipFileを開いて、必要なエントリの InputStream を取得し、それを解析できます。getInputStreamメソッドを参照してください。

- - 編集 - -

ここにあなたを導くためのいくつかのコードがあります:

for( String curFile : xmlFiles )
{
        ZipFile zip = new ZipFile(new File( dirToProcess + curFile));
        Enumeration<? extends ZipEntry> entries = zip.entries();
        while (entries.hasMoreElements()){
            ZipEntry entry = entries.nextElement();
            InputStream xmlStream = zip.getInputStream(entry);
            saxParser.parse( xmlStream, handler );
            xmlStream.close();
        }
}
于 2012-09-13T16:24:51.090 に答える
1
  • ZipInputStream.read()からxバイトを読み取りZipFileEntry、それらを解凍して、解凍されたバイトを提供します。
  • ここのいずれかの方法を使用して、イン/アウトストリームを作成します。
  • パーサーに関して、そのイン/アウトストリームを提供します。InputStream
  • 解凍されたデータの入出力ストリームへの書き込みを開始します(現在はとして扱われますOutputStream)。
  • つまり、zipファイルからデータのチャンクを読み取り、それらを解凍してパーサーに渡すことになります。

PS:

  1. zipファイルに複数のファイルが含まれている場合は、次を参照してください。byte[](Java)から読み取ったときにZipFileエントリの内容を抽出する場合は、エントリの最後に到達したときにわかるようにチェックを入れる必要があります。
  2. 私はSAXパーサーをあまり使用していませんが、この方法でファイルを解析すると想定しています(チャンクで指定された場合)。

- - 編集 - -

これが私が意味したことです:

import java.io.File;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class Main {
    static class MyRunnable implements Runnable {

        private InputStream xmlStream;
        private SAXParser sParser;

        public MyRunnable(SAXParser p, InputStream is) {
            sParser = p;
            xmlStream = is;
        }

        public void run() {
            try {
                sParser.parse(xmlStream, new DefaultHandler() {
                    public void startElement(String uri, String localName, String qName, Attributes attributes)
                            throws SAXException {
                        System.out.println("\nStart Element :" + qName);
                    }

                    public void endElement(String uri, String localName, String qName) throws SAXException {
                        System.out.println("\nEnd Element :" + qName);
                    }
                });
                System.out.println("Done parsing..");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

    final static int BUF_SIZE = 5;
    public static void main(String argv[]) {

        try {

            SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();

            ZipFile zip = new ZipFile(new File("D:\\Workspaces\\Indigo\\Test\\performance.zip"));
            Enumeration<? extends ZipEntry> entries = zip.entries();
            while (entries.hasMoreElements()) {
                // in stream for parser..
                PipedInputStream xmlStream = new PipedInputStream();
                // out stream attached to in stream above.. we would read from zip file and write to this..
                // thus passing whatever we write to the parser..
                PipedOutputStream out = new PipedOutputStream(xmlStream);
                // Parser blocks in in stream, so put him on a different thread..
                Thread parserThread = new Thread(new Main.MyRunnable(saxParser, xmlStream));
                parserThread.start();

                ZipEntry entry = entries.nextElement();
                System.out.println("\nOpening zip entry: " + entry.getName());
                InputStream unzippedStream = zip.getInputStream(entry);

                byte buf[] = new byte[BUF_SIZE]; int bytesRead = 0;
                while ((bytesRead = unzippedStream.read(buf)) > 0) {
                    // write to err for different color in eclipse..
                    System.err.write(buf, 0, bytesRead);
                    out.write(buf, 0, bytesRead);
                    Thread.sleep(150); // theatrics...
                }

                out.flush();
                // give parser a couple o seconds to catch up just in case there is some IO lag...
                parserThread.join(2000);

                unzippedStream.close(); out.close(); xmlStream.close();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
于 2012-09-13T17:07:17.017 に答える