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