001: /**
002: * com.mckoi.store.StreamFile 17 Jun 2003
003: *
004: * Mckoi SQL Database ( http://www.mckoi.com/database )
005: * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * Version 2 as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License Version 2 for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * Version 2 along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: * Change Log:
021: *
022: *
023: */package com.mckoi.store;
024:
025: import java.io.*;
026:
027: /**
028: * A RandomAccessFile that acts as an OutputStream, and can also be read as an
029: * InputStream.
030: *
031: * @author Tobias Downer
032: */
033:
034: public class StreamFile {
035:
036: /**
037: * The File object.
038: */
039: private final File file;
040:
041: /**
042: * The RandomAccessFile.
043: */
044: private RandomAccessFile data;
045:
046: /**
047: * Pointer to the end of the file.
048: */
049: private long end_pointer;
050:
051: /**
052: * The OutputStream object for this file.
053: */
054: private OutputStream output_stream;
055:
056: /**
057: * Constructor.
058: */
059: public StreamFile(File file, String mode) throws IOException {
060: this .file = file;
061: data = new RandomAccessFile(file, mode);
062: end_pointer = data.length();
063: output_stream = new SFOutputStream();
064: }
065:
066: /**
067: * Closes the file.
068: */
069: public void close() throws IOException {
070: synchronized (data) {
071: data.close();
072: }
073: }
074:
075: /**
076: * Synchs the file.
077: */
078: public void synch() throws IOException {
079: synchronized (data) {
080: try {
081: data.getFD().sync();
082: } catch (SyncFailedException e) {
083: // A SyncFailedException seems to occur on some specific OS under
084: // JDK 1.4.x. We ignore the exception which reduces the robustness
085: // of the journal file for the OS where this problem occurs.
086: // Unfortunately there's no sane way to handle this excption when it
087: // does occur.
088: }
089: }
090: }
091:
092: /**
093: * Deletes the file.
094: */
095: public void delete() throws IOException {
096: file.delete();
097: }
098:
099: /**
100: * Fully reads a block from a section of the file into the given byte[]
101: * array at the given position.
102: */
103: public void readFully(final long position, byte[] buf, int off,
104: int len) throws IOException {
105: synchronized (data) {
106: data.seek(position);
107: int to_read = len;
108: while (to_read > 0) {
109: int read = data.read(buf, off, to_read);
110: to_read -= read;
111: off += read;
112: }
113: }
114: }
115:
116: /**
117: * Returns the current length of the data.
118: */
119: public long length() {
120: synchronized (data) {
121: return end_pointer;
122: }
123: }
124:
125: /**
126: * Opens an OutputStream to the file. Only one output stream may be open
127: * on the file at once.
128: */
129: public OutputStream getOutputStream() throws IOException {
130: return output_stream;
131: }
132:
133: /**
134: * Returns an InputStream to the file that allows us to read from the start
135: * to the end of the file.
136: */
137: public InputStream getInputStream() throws IOException {
138: return new SFInputStream();
139: }
140:
141: // ---------- Inner classes ----------
142:
143: class SFOutputStream extends OutputStream {
144:
145: public void write(int i) throws IOException {
146: synchronized (data) {
147: data.seek(end_pointer);
148: data.write(i);
149: ++end_pointer;
150: }
151: }
152:
153: public void write(byte[] buf, int off, int len)
154: throws IOException {
155: if (len > 0) {
156: synchronized (data) {
157: data.seek(end_pointer);
158: data.write(buf, off, len);
159: end_pointer += len;
160: }
161: }
162: }
163:
164: }
165:
166: class SFInputStream extends InputStream {
167:
168: private long fp = 0;
169:
170: public int read() throws IOException {
171: synchronized (data) {
172: if (fp >= end_pointer) {
173: return -1;
174: }
175: data.seek(fp);
176: ++fp;
177: return data.read();
178:
179: }
180: }
181:
182: public int read(byte[] buf, int off, int len)
183: throws IOException {
184: synchronized (data) {
185: if (len == 0) {
186: return 0;
187: }
188: len = (int) Math.min((long) len, end_pointer - fp);
189: if (len <= 0) {
190: return -1;
191: }
192:
193: data.seek(fp);
194: int act_read = data.read(buf, off, len);
195: fp += act_read;
196: return act_read;
197: }
198: }
199:
200: public long skip(long v) throws IOException {
201: synchronized (data) {
202: fp += v;
203: }
204: return v;
205: }
206:
207: }
208:
209: }
|