/***************************************************************************** * Copyright 2012 bitsofinfo.g [at] gmail [dot] com * * 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 * * Author: bitsofinfo.g [at] gmail [dot] com * @see bitsofinfo.wordpress.com *****************************************************************************/ package org.bitsofinfo.util.io; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; import java.util.List; import com.sun.xml.internal.rngom.parse.compact.EOFException; /** * DefaultRecordLoader is an RecordLoader implementation * which supports reading files from a local "file" URI * via an internal BufferedReader * * @author bitsofinfo.g [at] gmail [dot] com * */ public class DefaultRecordLoader implements RecordLoader { @Override public List<String> loadRecords(FileHandle handle, long startAtRecord, long totalRecordsToRead, int sizeOfEachRecordInBytes) throws EOFException, SecurityException, FileNotFoundException, IOException, Exception { ListBackedRecordHandler handler = new ListBackedRecordHandler(); this.loadRecords(handle, handler, startAtRecord, totalRecordsToRead, sizeOfEachRecordInBytes); return handler.getAllRecords(); } private void loadRecordsFromFile(FileHandle handle, RecordHandler recordHandler, long startAtRecord, long totalRecordsToRead, int sizeOfEachRecordInBytes) throws EOFException, IOException, Exception { File file = new File(handle.getUri()); if (!file.exists()) { throw new FileNotFoundException("File not found @"+handle.getUri().toString()); } else if (file.isDirectory()) { throw new FileNotFoundException("File @"+handle.getUri().toString() + " is a directory, not a file"); } else if (!file.canRead()) { throw new SecurityException("Cannot read from file @" + handle.getUri().toString()); } long bytePos = (startAtRecord == 1 ? 0 :((startAtRecord-1) * sizeOfEachRecordInBytes)); if (bytePos > file.length()) { throw new EOFException(); } // seek to that position long startAtByte; try { RandomAccessFile rand = new RandomAccessFile(file,"r"); rand.seek(bytePos); startAtByte = rand.getFilePointer(); rand.close(); } catch(IOException e) { throw new IOException("There was an error seeking to the specified record/line in the file: " + startAtRecord + " @position: " +bytePos); } BufferedReader reader = null; try { // lets fire up a buffered reader and skip right to that spot. reader = new BufferedReader(new FileReader(file)); reader.skip(startAtByte); String line; long totalRead = 0; long recordNumber = startAtRecord; char[] buffer = new char[sizeOfEachRecordInBytes]; while(totalRead < totalRecordsToRead && (-1 != reader.read(buffer, 0, sizeOfEachRecordInBytes))) { recordHandler.handleRecord(recordNumber,new String(buffer)); totalRead++; recordNumber++; } } catch(Exception e) { throw new Exception("An unexpected error occurred while reading records/lines from the file @" + handle.getUri().toString() + " error=" + e.getMessage()); } finally { if (reader != null) { // might not be good try {reader.close();} catch(Exception ignore) {} } } // call finish; recordHandler.finish(); } @Override public void loadRecords(FileHandle handle, RecordHandler recordHandler, long startAtRecord, long totalRecordsToRead, int sizeOfEachRecordInBytes) throws EOFException, SecurityException, FileNotFoundException, IOException, Exception { if (handle.getUri().getScheme().toLowerCase().equals(URIScheme.FILE.getName())) { loadRecordsFromFile(handle, recordHandler, startAtRecord, totalRecordsToRead, sizeOfEachRecordInBytes); } else { throw new Exception("DefaultRecordLoader.loadLines() only supports loading" + " lines from URIs which schemes of type URIScheme.FILE"); } } /** * Internal RecordHandler implementation which simply stores * each processed record in an internal List * * @author bitsofinfo.g [at] gmail [dot] com * */ private class ListBackedRecordHandler implements RecordHandler { private ArrayList<String> records = new ArrayList<String>(); public void handleRecord(long recordNumber, String record) { records.add(record); } public List<String> getAllRecords() { return records; } public long getTotalRecordsHandled() { return records.size(); } public void finish() throws Exception { // nothing } } }