<!---
	We are going to be reading in a file, line by line, so first,
	let's create a file to read. Define the path to the file we
	are going to populate.
--->
<cfset filePath = expandPath( "./data.txt" ) />

<!---
	Delete the file if it exists so that we don't keep populating
	the same document.
--->
<cfif fileExists( filePath )>

	<cfset fileDelete( filePath ) />

</cfif>

<!--- Write some data to the file. --->
<cfloop
	index="i"
	from="1"
	to="10"
	step="1">

	<cffile
		action="append"
		file="#filePath#"
		output="This is line #i# in this file."
		addnewline="true"
		/>

</cfloop>


<!--- ----------------------------------------------------- --->
<!--- ----------------------------------------------------- --->


<!---
	If you are not on ColdFusion 8 yet, you can still read files
	in a line at a time by dipping down into the Java layer.
	Behind the scenes, ColdFusion is probably using some sort of
	buffered file reader, so we can do the same explicitly.

	To create the line number reader, we have to pass it a Reader
	object, which will a buffered reader for performance reasons.
--->
<cfset lineReader = createObject( "java", "java.io.LineNumberReader" ).init(
	createObject( "java", "java.io.BufferedReader" ).init(
		createObject( "java", "java.io.FileReader" ).init(
			javaCast( "string", filePath )
			)
		)
	) />

<!---
	Mark the beginning of the stream so we can reset the position
	of the reader if we need to.

	NOTE: You typically won't need this - I just need to do this so
	I can demonstrate two file reads without creating a new line
	number reader object.
--->
<cfset lineReader.mark(
	javaCast( "int", 999999 )
	) />


<cfoutput>


	<!---
		Now, let's read the file in a line at a time. As we use the
		readLine(), it will return a NULL when it gets to the end of
		the file. When that happens, the variable we are using to
		read the line will be deleted.
	--->
	<cfset line = lineReader.readLine() />

	<!---
		Check to make sure we didn't hit the end of the file (which
		will return NULL, which will delete our variable).
	--->
	<cfloop condition="structKeyExists( variables, 'line' )">

		Line: #line#<br />

		<!--- Read the next line. --->
		<cfset line = lineReader.readLine() />

	</cfloop>


	<br />


	<!---
		Reset the line number reader to the beginning of input
		stream for next demo.
	--->
	<cfset lineReader.reset() />

	<!---
		We can also use the buffered line reader to read in chunks
		of the file as we did with the CFLoop tag. This is a bit
		more compliated as we need to read the character data into
		a character array.
	--->

	<!---
		Create a character array of length 50 for out read buffer
		(we will be reading in a max of 50 characters at any time).

		NOTE: It doesn't matter what the inital values are at this
		point since our line number reader will overwrite the data.
	--->
	<cfset buffer = listToArray( repeatString( " ,", 50 ) ) />

	<!---
		Cast the ColdFusion array (collection) to a typed Java array
		so that we can use it with the line number reader.
	--->
	<cfset buffer = javaCast( "char[]", buffer ) />


	<!---
		Read the file data into the buffer and record the number
		of characters that were read.
	--->
	<cfset charCount = lineReader.read(
		buffer,
		javaCast( "int", 0 ),
		javaCast( "int", arrayLen( buffer ) )
		) />

	<!---
		Keep looping while characters were read-in. When the line
		reader hits the end of the file, it will return -1 for the
		character count.
	--->
	<cfloop condition="(charCount neq -1)">

		<!---
			Output the chunk. When we do this, we want to convert
			the buffer to a string and then just take out what's
			needed.
		--->
		<cfset chunk = mid(
			arrayToList( buffer, "" ),
			1,
			charCount
			) />

		50 Char Chunk: #chunk#<br />

		<!---
			Read the next chunk of character data from the file
			into the buffer and record the number of characters
			that were read.
		--->
		<cfset charCount = lineReader.read(
			buffer,
			javaCast( "int", 0 ),
			javaCast( "int", arrayLen( buffer ) )
			) />

	</cfloop>


</cfoutput>