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