/* * [TestReadFileAtOnce.java] * * Summary: Discover best way te reay an entire file all at once. * * Copyright: (c) 2014-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.0 2014-05-16 initial version */ package com.mindprod.example; import com.mindprod.common18.EIO; import com.mindprod.hunkio.HunkIO; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.Charset; import java.text.DecimalFormat; import java.util.Random; import static java.lang.System.*; /** * Discover best way te reay an entire file all at once. * * @author Roedy Green, Canadian Mind Products * @version 1.0 2014-05-16 initial version * @since 2014-05-16 */ public final class TestReadFileAtOnce { // declarations /** * size of line in chars including \n */ private static final int LINESIZE = 100; /** * how many benchmark trials */ private static final int TRIALS = 5; /** * size of test file in chars */ private static final long FILESIZE = 400L * 1024 * 1024; /** * chars we allow in our random data */ private static final String ALLOWED = "abcdefghijklmnopqrstuvwxyzABCDEFGHJKMLMOPQRSTUVWXYZ 0123456789 +!@$#$%^&*()_-?/|\\\n"; /** * character set to use */ private static final Charset charset = Charset.forName( "UTF-8" ); /** * allows us to display seconds to zero decimal places. */ private static final DecimalFormat df0 = new DecimalFormat( "###,##0" ); /** * allows us to display seconds to two decimal places. */ private static final DecimalFormat df2 = new DecimalFormat( "###,##0.00" ); /** * sample date file we read to test */ private static File sampleDataFile = null; // /declarations // methods /** * display nanoseconds as seconds to two decimal places. * * @param nanoseconds how many nanoseconds ( billionths of a second ) * * @return displayable String. */ private static String asSeconds( double nanoseconds ) { return df2.format( nanoseconds / 1000000000d ) + " seconds"; }// /method /** * generate 100K of sample data in a temporary file. */ private static void generateSampleData() throws IOException { // place on hard disk, not SSD HunkIO.createTempFile( "temp_", ".tmp", new File( "H:/temp" ) ); sampleDataFile = File.createTempFile( "temp_", ".tmp" ); final Random wheel = new Random(); final BufferedWriter bw = EIO.getBufferedWriter( sampleDataFile, 256 * 1024, charset ); char[] line = new char[ LINESIZE - 1 ]; for ( int i = 0; i < ( FILESIZE / LINESIZE ); i++ ) { for ( int j = 0; j < line.length; j++ ) { line[ j ] = ALLOWED.charAt( ( wheel.nextInt() & Integer.MAX_VALUE ) % ALLOWED.length() ); } bw.write( line ); // encoding irrelevant here bw.write( "\n" ); } bw.close(); }// /method /** * Benchmark three ways of buffered writing and three ways of buffered reading. * * @param args not used * * @throws java.io.IOException if problem writing or reading the test file. */ public static void main( String[] args ) throws IOException { generateSampleData(); out.println( "Using a random sample data file of " + df0.format( FILESIZE ) + " chars " + df0.format( sampleDataFile.length() ) + " bytes." ); for ( int i = 0; i < TRIALS; i++ ) { readFileAtOnceWithRandomAccess( sampleDataFile ); readFileAtOnceWithInputStream( sampleDataFile ); readFileAtOnceWithNIO( sampleDataFile ); } //noinspection ResultOfMethodCallIgnored sampleDataFile.delete(); // results // Using a random sample data file of 419,430,400 chars 419,430,400 bytes. // RandomAccess 1.46 seconds // InputStream 1.48 seconds // NIO 1.56 seconds }// /method /** * read file of bytes in one I/O and convert to a String using an InputStream * * @param fromFile file to read * * @throws IOException when cannot access file. * @noinspection WeakerAccess */ public static String readFileAtOnceWithInputStream( File fromFile ) throws IOException { final long prevTime = System.nanoTime(); final int size = ( int ) fromFile.length(); final FileInputStream fis = new FileInputStream( fromFile ); // R E A D final byte[] rawContents = new byte[ size ]; final int bytesRead = fis.read( rawContents ); if ( bytesRead != size ) { throw new IOException( "error: problems reading InputStream file " + fromFile ); } // C L O S E fis.close(); final String result = new String( rawContents, charset ); out.println( "InputStream " + asSeconds( System.nanoTime() - prevTime ) ); return result; }// /method /** * read file of bytes in one I/O and convert to a String using NIO * * @param fromFile file to read * * @return String that was in the file * @throws IOException when cannot access file. * @noinspection WeakerAccess */ public static String readFileAtOnceWithNIO( File fromFile ) throws IOException { final long prevTime = System.nanoTime(); final int size = ( int ) fromFile.length(); final ByteBuffer b = ByteBuffer.allocateDirect( size ); final RandomAccessFile raf = new RandomAccessFile( fromFile, "r" ); final FileChannel fc = raf.getChannel(); fc.read( b ); if ( fc.position() != size ) { throw new IOException( "error: problems reading NIO file " + fromFile ); } b.flip(); // rewinds position back to 0, ready to process with get fc.close(); // b.array is unsupported, so we have to use b.get final byte[] holder = new byte[ size ]; // results in holder, copied in byte by byte. b.get( holder ); final String result = new String( holder, charset ); out.println( "NIO " + asSeconds( System.nanoTime() - prevTime ) ); return result; }// /method /** * read file of bytes in one I/O and convert to a String, using a RAF. * * @param fromFile file to read * * @return String that was in the file * @throws IOException when cannot access file. * @noinspection WeakerAccess */ public static String readFileAtOnceWithRandomAccess( File fromFile ) throws IOException { final long prevTime = System.nanoTime(); final int size = ( int ) fromFile.length(); final RandomAccessFile raf = new RandomAccessFile( fromFile, "r" ); // R E A D final byte[] rawContents = new byte[ size ]; final int bytesRead = raf.read( rawContents ); if ( bytesRead != size ) { throw new IOException( "error: problems reading RandomAccess file " + fromFile ); } // C L O S E raf.close(); final String result = new String( rawContents, charset ); out.println( "RandomAccess " + asSeconds( System.nanoTime() - prevTime ) ); return result; }// /method // /methods }