/* * Project Info: http://jcae.sourceforge.net * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. * * (C) Copyright 2009, by EADS France */ package org.jcae.mesh.xmldata; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.DoubleBuffer; import java.nio.channels.FileChannel; public class DoubleFileReaderByDirectBuffer implements DoubleFileReader { private final static int BUFFER_SIZE = 8*1024*1024; private final static int ARRAY_SIZE = 4096; private static final int ELEMENT_SIZE = 8; private final FileChannel fc; private final long numberOfElements; private final ByteBuffer bb; private final DoubleBuffer tb; private double[] array; private int startBufferIndex; private int arrayIndex; private int remaining; public DoubleFileReaderByDirectBuffer(File file) throws IOException { fc = new FileInputStream(file).getChannel(); numberOfElements = fc.size() / ELEMENT_SIZE; if (fc.size() > BUFFER_SIZE) bb = ByteBuffer.allocateDirect(BUFFER_SIZE); else bb = ByteBuffer.allocateDirect((int) fc.size()); tb = bb.asDoubleBuffer(); // Copy from file into buffer copyFileIntoBuffer(); } public long size() { return numberOfElements; } private void moveBufferTo(long newPosition) throws IOException { fc.position(newPosition); // Fill in buffer copyFileIntoBuffer(); } public double get() throws IOException { if (remaining == 0) copyBufferIntoArray(); if (remaining < 0) throw new IOException(); double ret = array[arrayIndex]; arrayIndex++; remaining--; // We must check for EOF if all values are exhausted if (remaining == 0 && !tb.hasRemaining()) copyFileIntoBuffer(); return ret; } public double get(int index) throws IOException { int relIndex = index - startBufferIndex; if (relIndex < 0 || relIndex >= tb.limit()) { moveBufferTo(index * ELEMENT_SIZE); if (remaining < 0) throw new IndexOutOfBoundsException(); relIndex = index - startBufferIndex; } return tb.get(relIndex); } public int get(double[] dst) throws IOException { return get(dst, 0, dst.length); } public final int get(double[] dst, int pos, int len) throws IOException { int ret = 0; // First copy ints from array if (remaining > 0) { int nr = Math.min(remaining, len); System.arraycopy(array, arrayIndex, dst, pos, nr); arrayIndex += nr; remaining -= nr; pos += nr; len -= nr; ret += nr; if (len == 0) { if (remaining == 0 && !tb.hasRemaining()) copyFileIntoBuffer(); return ret; } } // Now copy ints directly from buffer while (tb.remaining() < len) { int nr = tb.remaining(); tb.get(dst, pos, nr); pos += nr; len -= nr; ret += nr; if (!copyFileIntoBuffer()) return ret; } tb.get(dst, pos, len); ret += len; // Discard array remaining = 0; return ret; } public int get(int index, double[] dst) throws IOException { return get(index, dst, 0, dst.length); } public final int get(int index, double[] dst, int offset, int len) throws IOException { int relIndex = index - startBufferIndex; if (relIndex < 0 || relIndex >= tb.limit()) { moveBufferTo(index * ELEMENT_SIZE); if (remaining < 0) throw new IndexOutOfBoundsException(); relIndex = index - startBufferIndex; } // Change buffer position and discard array tb.position(relIndex); remaining = 0; return get(dst, offset, len); } private boolean copyFileIntoBuffer() throws IOException { tb.clear(); bb.clear(); int nr; startBufferIndex = (int) (fc.position() / ELEMENT_SIZE); do { nr = fc.read(bb); } while (nr == 0); if (nr == -1) { remaining = -1; return false; } nr /= ELEMENT_SIZE; tb.position(0); tb.limit(nr); // Discard array remaining = 0; return true; } private void copyBufferIntoArray() throws IOException { if (!tb.hasRemaining()) { if (!copyFileIntoBuffer()) return; } if (array == null) array = new double[Math.min((int) numberOfElements, ARRAY_SIZE)]; arrayIndex = 0; remaining = Math.min(tb.remaining(), array.length); tb.get(array, 0, remaining); } public boolean isEOF() { return remaining < 0; } public void close() { try { fc.close(); } catch (IOException ex) { /* Do not care */ } } }