# Read N Characters Given Read4

**Easy**

Given a file and assume that you can only read the file using a given method `read4`, implement a method to read\_n\_characters.

**Method read4:**

The API `read4`reads 4 consecutive characters from the file, then writes those characters into the buffer array`buf`.

The return value is the number of actual characters read.

Note that `read4()`has its own file pointer, much like`FILE *fp`in C.

**Definition of read4:**

```
    Parameter:  char[] buf
    Returns:    int

Note: buf[] is destination not source, the results from read4 will be copied to buf[]
```

Below is a high level example of how`read4`works:

```
File file("abcdefghijk"); // File is "abcdefghijk", initially file pointer (fp) points to 'a'
char[] buf = new char[4]; // Create buffer with enough space to store characters
read4(buf); // read4 returns 4. Now buf = "abcd", fp points to 'e'
read4(buf); // read4 returns 4. Now buf = "efgh", fp points to 'i'
read4(buf); // read4 returns 3. Now buf = "ijk", fp points to end of file
```

**Method read:**

By using the`read4`method, implement the method `read`that readsncharacters from the file and store it in the buffer array `buf`. Consider that you **cannot** manipulate the file directly.

The return value is the number of actual characters read.

**Definition of read:**

```
    Parameters:    char[] buf, int n
    Returns:    int

Note: buf[] is destination not source, you will need to write the results to buf[]
```

**Example 1:**

```
Input: 
file = "abc", n = 4

Output: 
3

Explanation:
 After calling your read method, buf should contain "abc". We read a total of 3 characters from the file, so return 3. Note that "abc" is the file's content, not buf. buf is the destination buffer that you will have to write the results to.
```

**Example 2:**

```
Input: 
file = "abcde", n = 5

Output: 
5

Explanation: 
After calling your read method, buf should contain "abcde". We read a total of 5 characters from the file, so return 5.
```

**Example 3:**

```
Input: 
file = "abcdABCD1234", n = 12

Output: 
12

Explanation: 
After calling your read method, buf should contain "abcdABCD1234". We read a total of 12 characters from the file, so return 12.
```

**Example 4:**

```
Input: 
file = "leetcode", n = 5

Output: 
5

Explanation: 
After calling your read method, buf should contain "leetc". We read a total of 5 characters from the file, so return 5.
```

**Note:**

1. Consider that you **cannot** manipulate the file directly, the file is only accesible for `read4` but **not** for `read`.
2. The `read` function will only be called once for each test case.
3. You may assume the destination buffer array, `buf`, is guaranteed to have enough space for storing *n* characters.

## Solution & Analysis

Source: <https://mnmunknown.gitbooks.io/algorithm-notes/728,_fb_tag_ti.html>

重新理一下这题的 API 和题目描述：

* 已知 `int read4(char[] buf)` 可用
* 你的程序要传入一个 `char[]` 过去，函数写入最多 4 个 char 在上面，然后返回写入 char 的长度； 到文件末尾的时候返回 char 长度会小于 4.
* 于是我们的目标是把最终长度为 n 的字符串写入自己函数的 `read(char[] buf)` 里，然后返回实际长度。

### 主要的注意点和难点

有的时候 read4 是短板，有的时候 readN 自己是短板(不需要4个那么多的字符)，在写入的时候要注意处理下。

可以通过

```java
// get the actual count
count = Math.min(count, n - total);
```

或者

```java
while (i < count && cur < n) {
...
}
```

来限制。

### 思路：

比较巧妙的是用一个pointer `cur`记录已经从临时buffer tmp\[]写完到buf\[]的位置，外层循环的条件则是pointer `cur < n`

EOF的条件则是read4() 返回的count < SIZE, 也就是 count < 4。

```java
/**
 * The read4 API is defined in the parent class Reader4.
 *     int read4(char[] buf);
 */
public class Solution extends Reader4 {
    private int SIZE = 4;
    /**
     * @param buf Destination buffer
     * @param n   Number of characters to read
     * @return    The number of actual characters read
     */
    public int read(char[] buf, int n) {
        char[] tmp = new char[SIZE];
        int cur = 0;
        int count = 0;
        boolean EOF = false;
        while (!EOF && cur < n) {
            count = read4(tmp);
            EOF = (count < SIZE);

            int i = 0;
            while (i < count && cur < n) {
                buf[cur++] = tmp[i++];
            }
        }

        return cur;
    }
}
```

### \*Using EOF, count, tmp\[]

```java
public int read(char[] buf, int n) {
  boolean eof = false;      // end of file flag
  int total = 0;            // total bytes have read
  char[] tmp = new char[4]; // temp buffer

  while (!eof && total < n) {
    int count = read4(tmp);

    // check if it's the end of the file
    eof = count < 4;

    // get the actual count
    count = Math.min(count, n - total);

    // copy from temp buffer to buf
    for (int i = 0; i < count; i++) 
      buf[total++] = tmp[i];
  }

  return total;
}
```

The reason we need `Math.min(count, n-total)` is because we only want to read `N` characters even if we have all 4 characters returned from `Read4`.

Say, N = 18 and we're implentening Read18, then Read4 will takes us to 4\*4 = 16 chars. After that, we only want to read 2 more chars (even if the next Read4 returns 3 or 4 characters).

### Another Implementation

```java
public int read(char[] buf, int n) {

    char[] temp = new char[4];  //Store our read chars from Read4
    int total = 0;

    while(total < n){
        // Read and store characters in Temp. Count will store total chars read from Read4
        int count = read4(temp);

        // Even if we read 4 chars from Read4, we don't want to exceed N and only want to read chars till N.
        count = Math.min(count, n-total);

        // Transfer all the characters read from Read4 to our buffer
        for(int i = 0;  i < count; i++){
            buf[total] = temp[i];
            total++;
        }

        // EOF. Done. We can't read more characters.
        if(count < 4) break;
    }

    return total;
}
```

## Reference

<https://mnmunknown.gitbooks.io/algorithm-notes/728,_fb_tag_ti.html>
