⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 blobbuffer.java

📁 第三方的SQL Server and Sybase的jdbc dirver,速度更快
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
// jTDS JDBC Driver for Microsoft SQL Server and Sybase// Copyright (C) 2004 The jTDS Project//// This library 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 library 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 library; if not, write to the Free Software// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA//package net.sourceforge.jtds.util;import java.io.*;import java.sql.SQLException;import net.sourceforge.jtds.jdbc.Messages;/** * Manages a buffer (backed by optional disk storage) for use as a data store * by the CLOB and BLOB objects. * <p/> * The data can be purely memory based until the size exceeds the value * dictated by the <code>lobBuffer</code> URL property after which it will be * written to disk. The disk array is accessed randomly one page (1024 bytes) * at a time. * <p/> * This class is not synchronized and concurrent open input and output * streams can conflict. * <p/> * Tuning hints: * <ol> *   <li>The <code>PAGE_SIZE</code> governs how much data is buffered when *     reading or writing data a byte at a time. 1024 bytes seems to work well *     but if very large objects are being written a byte at a time 4096 may be *     better. <b>NB.</b> ensure that the <code>PAGE_MASK</code> and *     <code>BYTE_MASK</code> fields are also adjusted to match. *   <li>Reading or writing byte arrays that are greater than or equal to the *     page size will go directly to or from the random access file cutting out *     an ArrayCopy operation. *   <li>If BLOBs are being buffered exclusively in memory you may wish to *     adjust the <code>MAX_BUF_INC</code> value. Every time the buffer is *     expanded the existing contents are copied and this may get expensive *     with very large BLOBs. *   <li>The BLOB file will be kept open for as long as there are open input or *     output streams. Therefore BLOB streams should be explicitly closed as *     soon as they are finished with. * </ol> * * @author Mike Hutchinson * @version $Id: BlobBuffer.java,v 1.3 2005/04/28 14:29:31 alin_sinpalean Exp $ */public class BlobBuffer {    /**     * Default zero length buffer.     */    private static final byte[] EMPTY_BUFFER = new byte[0];    /**     * Default page size (must be power of 2).     */    private static final int PAGE_SIZE = 1024;    /**     * Mask for page component of read/write pointer.     */    private static final int PAGE_MASK = 0xFFFFFC00;    /**     * Mask for page offset component of R/W pointer.     */    private static final int BYTE_MASK = 0x000003FF;    /**     * Maximum buffer increment.     */    private static final int MAX_BUF_INC = 16384;    /**     * Invalid page marker.     */    private static final int INVALID_PAGE = -1;    /**     * The BLOB buffer or the current page buffer.     */    private byte[] buffer;    /**     * The total length of the valid data in buffer.     */    private int length;    /**     * The number of the current page in memory.     */    private int currentPage;    /**     * The name of the temporary BLOB disk file.     */    private File blobFile;    /**     * The RA file object reference or null if closed.     */    private RandomAccessFile raFile;    /**     * Indicates page in memory must be saved.     */    private boolean bufferDirty;    /**     * Count of callers that have opened the BLOB file.     */    private int openCount;    /**     * True if attempts to create a BLOB file have failed.     */    private boolean isMemOnly;    /**     * The maximum size of an in memory buffer.     */    private final int maxMemSize;    /**     * Creates a blob buffer.     *     * @param maxMemSize the maximum size of the in memory buffer     */    public BlobBuffer(long maxMemSize) {        this.maxMemSize = (int) maxMemSize;        buffer = EMPTY_BUFFER;    }    /**     * Finalizes this object by deleting any work files.     */    protected void finalize() throws Throwable {        try {            if (raFile != null) {                raFile.close();            }        } catch (IOException e) {            // Ignore we are going to delete anyway        } finally {            if (blobFile != null) {                blobFile.delete();            }        }    }    /**     * Creates a random access disk file to use as backing storage for the LOB     * data.     * <p/>     * This method may fail due to security exceptions or local disk problems,     * in which case the blob storage will remain entirely in memory.     */    public void createBlobFile() {        try {            blobFile = File.createTempFile("jtds", ".tmp");            blobFile.deleteOnExit();            raFile = new RandomAccessFile(blobFile, "rw");            if (length > 0) {                raFile.write(buffer, 0, (int) length);            }            buffer = new byte[PAGE_SIZE];            currentPage = INVALID_PAGE;            openCount = 0;        } catch (SecurityException e) {            blobFile = null;            raFile = null;            isMemOnly = true;            Logger.println("SecurityException creating BLOB file:");            Logger.logException(e);        } catch (IOException ioe) {            blobFile = null;            raFile = null;            isMemOnly = true;            Logger.println("IOException creating BLOB file:");            Logger.logException(ioe);        }    }    /**     * Opens the BLOB disk file.     * <p/>     * A count of open and close requests is kept so that the file may be     * closed when no longer required thus keeping the number of open files to     * a minimum.     *     * @throws IOException if an I/O error occurs     */    public void open() throws IOException {        if (raFile == null && blobFile != null) {            // reopen file            raFile = new RandomAccessFile(blobFile, "rw");            openCount = 1;            currentPage = INVALID_PAGE;            buffer = new byte[PAGE_SIZE];            return;        }        if (raFile != null) {            openCount++;        }    }    /**     * Reads byte from the BLOB buffer at the specified location.     * <p/>     * The read pointer is partitioned into a page number and an offset within     * the page. This routine will read new pages as required. The page size     * must be a power of 2 and is currently set to 1024 bytes.     *     * @param readPtr the offset in the buffer of the required byte     * @return the byte value as an <code>int</code> or -1 if at EOF     * @throws IOException if an I/O error occurs     */    public int read(int readPtr) throws IOException {        if (readPtr >= length) {            // At end of file.            return -1;        }        if (raFile != null) {            // Paged storage as a file exists            if (currentPage != (readPtr & PAGE_MASK)) {                // Requested page not in memory so read it                readPage(readPtr);            }            // Use the byte offset to return the correct            // byte from the page.            return buffer[readPtr & BYTE_MASK] & 0xFF;        } else {            // In memory buffer just return byte.            return buffer[readPtr] & 0xFF;        }    }    /**     * Reads bytes from the BLOB buffer at the specified location.     *     * @param readPtr the offset in the buffer of the required byte     * @param bytes   the byte array to fill     * @param offset  the start position in the byte array     * @param len     the number of bytes to read     * @return the number of bytes read or -1 if at end of file     * @throws IOException if an I/O error occurs     */    public int read(int readPtr, byte[] bytes, int offset, int len)            throws IOException {        // Validate parameters        if (bytes == null) {            throw new NullPointerException();        } else if ((offset < 0) || (offset > bytes.length) || (len < 0)                || ((offset + len) > bytes.length) || ((offset + len) < 0)) {            throw new IndexOutOfBoundsException();        } else if (len == 0) {            return 0;        }        if (readPtr >= length) {            // At end of file            return -1;        }        if (raFile != null) {            // Need to read from disk file            len = Math.min(length - readPtr, len);            if (len >= PAGE_SIZE) {                // This is a big write so we optimize by reading directly                // from the RA File.                if (bufferDirty) {                    writePage(currentPage);                }                currentPage = INVALID_PAGE;                raFile.seek(readPtr);                raFile.readFully(bytes, offset, len);            } else {                //                // Partial read so buffer locally                //                int count = len;                while (count > 0) {                    if (currentPage != (readPtr & PAGE_MASK)) {                        // Requested page not in memory so read it                        readPage(readPtr);                    }                    int inBuffer = Math.min(PAGE_SIZE - (readPtr & BYTE_MASK), count);                    System.arraycopy(buffer, readPtr & BYTE_MASK, bytes, offset, inBuffer);                    offset += inBuffer;                    readPtr += inBuffer;                    count -= inBuffer;                }            }        } else {            // In memory buffer            len = Math.min(length - readPtr, len);            System.arraycopy(buffer, readPtr, bytes, offset, len);        }        return len;    }    /**     * Inserts a byte into the buffer at the specified location.     * <p/>     * The write pointer is partitioned into a page number and an offset within     * the page. This routine will write new pages as required. The page size     * must be a power of 2 and is currently set to 1024 bytes.     *     * @param writePtr the offset in the buffer of the required byte     * @param b        the byte value to write     * @throws IOException if an I/O error occurs     */    public void write(int writePtr, int b) throws IOException {        if (writePtr >= length) {            if (writePtr > length) {                // Probably because the user called truncate at                // the same time as writing to the blob!                throw new IOException("BLOB buffer has been truncated");            }            // We are writing beyond the current length            // of the buffer and need to update the total length.            if (++length < 0) {                // We have wrapped 31 bits!                // This should ensure that the disk file is limited to 2GB.                // If in memory JVM will probably have failed by now anyway.                throw new IOException("BLOB may not exceed 2GB in size");            }        }        if (raFile != null) {            // OK we have a disk based buffer            if (currentPage != (writePtr & PAGE_MASK)) {                // The page we need is not in memory                readPage(writePtr);            }            buffer[writePtr & BYTE_MASK] = (byte) b;            // Ensure change will saved if buffer is replaced            bufferDirty = true;        } else {            // In memory buffer only (only used here if disk unavailable            if (writePtr >= buffer.length) {                growBuffer(writePtr + 1);            }            buffer[writePtr] = (byte) b;        }    }    /**     * Inserts bytes into the buffer at the specified location.     *     * @param writePtr the offset in the buffer of the required byte     * @param bytes    the byte array value to write     * @param offset   the start position in the byte array     * @param len      the number of bytes to write     * @throws IOException if an I/O error occurs     */    void write(int writePtr, byte[] bytes, int offset, int len)            throws IOException {        // Validate parameters        if (bytes == null) {            throw new NullPointerException();        } else if ((offset < 0) || (offset > bytes.length) || (len < 0) ||                ((offset + len) > bytes.length) || ((offset + len) < 0)) {            throw new IndexOutOfBoundsException();        } else if (len == 0) {            return;        }        if ((long) writePtr + len > (long) Integer.MAX_VALUE) {            throw new IOException("BLOB may not exceed 2GB in size");        }        if (writePtr > length) {            // Probably because the user called truncate at            // the same time as writing to the blob!            throw new IOException("BLOB buffer has been truncated");        }        if (raFile != null) {            // dealing with disk storage (normal case)            //            if (len >= PAGE_SIZE) {                // This is a big write so we optimize by writing directly                // to the RA File.                if (bufferDirty) {                    writePage(currentPage);                }                currentPage = INVALID_PAGE;                raFile.seek(writePtr);                raFile.write(bytes, offset, len);                writePtr += len;            } else {                // Small writes so use the page buffer for                // effeciency.                int count = len;                while (count > 0) {                    // Paged storage as a file exists                    if (currentPage != (writePtr & PAGE_MASK)) {                        // Requested page not in memory so read it                        readPage(writePtr);                    }                    int inBuffer = Math.min(                            PAGE_SIZE - (writePtr & BYTE_MASK), count);                    System.arraycopy(bytes, offset, buffer,                            writePtr & BYTE_MASK, inBuffer);                    bufferDirty = true;                    offset += inBuffer;                    writePtr += inBuffer;                    count -= inBuffer;                }            }        } else {            // In memory (only used here if disk not available)            if (writePtr + len > buffer.length) {                growBuffer(writePtr + len);            }            System.arraycopy(bytes, offset, buffer, writePtr, len);            writePtr += len;        }        if (writePtr > length) {            length = writePtr;        }    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -