/* * Copyright 2010 NCHOVY * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.krakenapps.util.directoryfile; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; public class SplitDirectoryFileOutputStream extends OutputStream { protected final long unitSize; protected final File fileBase; protected final boolean append; protected final DirectoryFileArchive dfa; private OutputStream stream = null; private long currentStreamLength; private int lastId; public SplitDirectoryFileOutputStream(long unitSize, DirectoryFileArchive dfa, File file, boolean append) throws IOException { this.unitSize = unitSize; this.fileBase = file; this.append = append; this.dfa = dfa; this.dfa.attach(); init(); } public SplitDirectoryFileOutputStream(long unitSize, DirectoryFileArchive dfa, File file) throws IOException { this.unitSize = unitSize; this.fileBase = file; this.append = false; this.dfa = dfa; this.dfa.attach(); init(); } public SplitDirectoryFileOutputStream(long unitSize, DirectoryFileArchive dfa, String name, boolean append) throws IOException { this.unitSize = unitSize; this.fileBase = new File(name); this.append = append; this.dfa = dfa; this.dfa.attach(); init(); } public SplitDirectoryFileOutputStream(long unitSize, DirectoryFileArchive dfa, String name) throws IOException { this.unitSize = unitSize; this.fileBase = new File(name); this.append = false; this.dfa = dfa; this.dfa.attach(); init(); } protected OutputStream getOutputStream(File lastFile, boolean append) throws IOException { return dfa.getOutputStreamAbsolutePath(lastFile.getAbsolutePath(), (int) unitSize); } public DirectoryFileArchive getDirectoryFileArchive() { return this.dfa; } private void init() throws IOException { if (append) { // find last file. lastId = getLastId(dfa, this.fileBase); File lastFile = getLastFile(this.fileBase, lastId); stream = getOutputStream(lastFile, append); currentStreamLength = lastFile.length(); } else { // remove existing files. int l = getLastId(dfa, this.fileBase); for (int i = 1; i <= l; ++i) { File c = new File(fileBase.getPath() + "." + i); c.delete(); } new File(fileBase.getPath() + ".lastId").delete(); lastId = 0; stream = getOutputStream(fileBase, false); currentStreamLength = 0; } if (currentStreamLength >= unitSize) { initNextStream(); } } private void initNextStream() throws IOException { lastId++; dfa.setReservedAbsolutePath(fileBase.getAbsolutePath(), lastId); stream.close(); stream = getOutputStream(getLastFile(fileBase, lastId), false); currentStreamLength = 0; } public static int getLastId(DirectoryFileArchive dfa, File base) { if (dfa.exists(base)) { try { long lastId = dfa.getReservedAbsolutePath(base.getAbsolutePath()); return (int) lastId; } catch (FileNotFoundException e) { } catch (IOException e) { } } return 0; } public static File getLastFile(File base, int lastId) throws FileNotFoundException { if (lastId > 0) { return new File(base.getPath() + "." + lastId); } else { return base; } } public void close() throws IOException { if (stream != null) stream.close(); if (dfa != null) dfa.close(); } @Override public void write(int b) throws IOException { if (currentStreamLength < unitSize) stream.write(b); else { initNextStream(); stream.write(b); } currentStreamLength++; } @Override public void write(byte[] b) throws IOException { write(b, 0, b.length); } @Override public void write(byte[] b, int off, int len) throws IOException { long expected = unitSize - (currentStreamLength + len); if (expected > 0) { stream.write(b, off, len); currentStreamLength += len; } else if (expected < 0) { int middle = (int) (len + expected); stream.write(b, off, middle); initNextStream(); stream.write(b, off + middle, (int) -expected); currentStreamLength += -expected; } else { stream.write(b, off, len); initNextStream(); } } @Override public void flush() throws IOException { if (stream != null) stream.flush(); } }