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