1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.handler.stream;
17
18 import org.jboss.netty.channel.FileRegion;
19
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.IOException;
23 import java.nio.ByteBuffer;
24 import java.nio.channels.FileChannel;
25
26 import static org.jboss.netty.buffer.ChannelBuffers.*;
27
28
29
30
31
32
33
34
35
36 public class ChunkedNioFile implements ChunkedInput {
37
38 private final FileChannel in;
39 private final long startOffset;
40 private final long endOffset;
41 private final int chunkSize;
42 private long offset;
43
44
45
46
47 public ChunkedNioFile(File in) throws IOException {
48 this(new FileInputStream(in).getChannel());
49 }
50
51
52
53
54
55
56
57 public ChunkedNioFile(File in, int chunkSize) throws IOException {
58 this(new FileInputStream(in).getChannel(), chunkSize);
59 }
60
61
62
63
64 public ChunkedNioFile(FileChannel in) throws IOException {
65 this(in, ChunkedStream.DEFAULT_CHUNK_SIZE);
66 }
67
68
69
70
71
72
73
74 public ChunkedNioFile(FileChannel in, int chunkSize) throws IOException {
75 this(in, 0, in.size(), chunkSize);
76 }
77
78
79
80
81
82
83
84
85
86 public ChunkedNioFile(FileChannel in, long offset, long length, int chunkSize)
87 throws IOException {
88 if (in == null) {
89 throw new NullPointerException("in");
90 }
91 if (offset < 0) {
92 throw new IllegalArgumentException(
93 "offset: " + offset + " (expected: 0 or greater)");
94 }
95 if (length < 0) {
96 throw new IllegalArgumentException(
97 "length: " + length + " (expected: 0 or greater)");
98 }
99 if (chunkSize <= 0) {
100 throw new IllegalArgumentException(
101 "chunkSize: " + chunkSize +
102 " (expected: a positive integer)");
103 }
104
105 if (offset != 0) {
106 in.position(offset);
107 }
108 this.in = in;
109 this.chunkSize = chunkSize;
110 this.offset = startOffset = offset;
111 endOffset = offset + length;
112 }
113
114
115
116
117 public long getStartOffset() {
118 return startOffset;
119 }
120
121
122
123
124 public long getEndOffset() {
125 return endOffset;
126 }
127
128
129
130
131 public long getCurrentOffset() {
132 return offset;
133 }
134
135 public boolean hasNextChunk() throws Exception {
136 return offset < endOffset && in.isOpen();
137 }
138
139 public boolean isEndOfInput() throws Exception {
140 return !hasNextChunk();
141 }
142
143 public void close() throws Exception {
144 in.close();
145 }
146
147 public Object nextChunk() throws Exception {
148 long offset = this.offset;
149 if (offset >= endOffset) {
150 return null;
151 }
152
153 int chunkSize = (int) Math.min(this.chunkSize, endOffset - offset);
154 byte[] chunkArray = new byte[chunkSize];
155 ByteBuffer chunk = ByteBuffer.wrap(chunkArray);
156 int readBytes = 0;
157 for (;;) {
158 int localReadBytes = in.read(chunk);
159 if (localReadBytes < 0) {
160 break;
161 }
162 readBytes += localReadBytes;
163 if (readBytes == chunkSize) {
164 break;
165 }
166 }
167
168 this.offset += readBytes;
169 return wrappedBuffer(chunkArray);
170 }
171 }