首页 > 代码库 > [LintCode] Read Characters From File - Multiple Calls
[LintCode] Read Characters From File - Multiple Calls
The API: int read4(char *buf)
reads 4
characters at a time from a file.
The return value is the actual number of characters read. For example, it returns 3 if there is only 3 characters left in the file.
By using the read4 API, implement the function int read(char *buf, int n)
that reads n characters from the file.
The read
function may be called multiple times.
Solution analysis
If this read function is only called once, then the solution is pretty straightforward. Simply calling read4 until n characters have
been read or the end of file is reached. If EOF is reached, return however many characters are actually read. In the case of
n % 4 != 0, discard the extra characters read during the last read call and return n.
However, since read function may be called multiple times, we can‘t just discard extra read characters as these characters should be
available for the next read call. So we need to buffer the extra characters for future read calls.
So the read function has one more place to read characters from, the buffer the possibly stores the extra unused characters from
previous read calls. As long as we have not read n characters AND there are characters to be read from the buffer OR from the file,
we keep reading.
In the following solution, variable names are intentionally made long and descriptive, to help understanding of the algorithm.
When we have not read n characters, we always try to read more characters from the buffer. Either the buffer already has characters
from previous read calls, or we call read4 to fill the buffer with new characters then read from the buffer.
When idxOfNextCharInBuffer < totalCharReadPerRead4Call is true, it means we have leftover characters from previous read calls.
We read these leftover characters one by one, and check if a total n has been reached each time. If it has, no need to read from the
file, return n.
If idxOfNextCharInBuffer < totalCharReadPerRead4Call is false, it means either the buffer does not have any leftover characters or
we have read all the leftover characters. In either case, we need to reset idxOfNextCharInBuffer to 0 and call read4 to store more
characters in the buffer. totalCharReadPerRead4Call is also updated to the actual characters read of this read4 call.
If totalCharReadPerRead4Call is 0, it means we‘ve reached EOF and have no more characters to read.
If it is bigger than 0, it means we still have more characters to possibly read n total characters.
The takeaway of this solution is how neat and short it is. The solution you wrote uses the same logic but has more
than 50 lines of code.
The key idea here is to make buffer, idxOfNextCharInBuffer and totalCharReadPerRead4Call instance variables, not
local variables. As long as we use the same instance, its instance variables stay in their life cycle among multiple
read calls. Previous read call correctly updates all 3 instance variables that are used for the next read call.
1 public class Solution extends Reader4 {
2 /**
3 * @param buf destination buffer
4 * @param n maximum number of characters to read
5 * @return the number of characters read
6 */
7 char[] buffer = new char[4];
8 int idxOfNextCharInBuffer = 0, totalCharReadPerRead4Call = 0;
9
10 public int read(char[] buf, int n) {
11 int charReadCnt = 0;
12 while (charReadCnt < n && (idxOfNextCharInBuffer < totalCharReadPerRead4Call || (totalCharReadPerRead4Call = read4(buffer)) > (idxOfNextCharInBuffer = 0))){
13 buf[charReadCnt++] = buffer[idxOfNextCharInBuffer++];
14 }
15 return charReadCnt;
16 }
17 }
[LintCode] Read Characters From File - Multiple Calls