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
28
29
30
31
32
33
34
35 public class ChunkedFile implements ChunkedInput<ByteBuf> {
36
37 private final RandomAccessFile file;
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 ChunkedFile(File file) throws IOException {
47 this(file, ChunkedStream.DEFAULT_CHUNK_SIZE);
48 }
49
50
51
52
53
54
55
56 public ChunkedFile(File file, int chunkSize) throws IOException {
57 this(new RandomAccessFile(file, "r"), chunkSize);
58 }
59
60
61
62
63 public ChunkedFile(RandomAccessFile file) throws IOException {
64 this(file, ChunkedStream.DEFAULT_CHUNK_SIZE);
65 }
66
67
68
69
70
71
72
73 public ChunkedFile(RandomAccessFile file, int chunkSize) throws IOException {
74 this(file, 0, file.length(), chunkSize);
75 }
76
77
78
79
80
81
82
83
84
85 public ChunkedFile(RandomAccessFile file, long offset, long length, int chunkSize) throws IOException {
86 ObjectUtil.checkNotNull(file, "file");
87 ObjectUtil.checkPositiveOrZero(offset, "offset");
88 ObjectUtil.checkPositiveOrZero(length, "length");
89 ObjectUtil.checkPositive(chunkSize, "chunkSize");
90
91 this.file = file;
92 this.offset = startOffset = offset;
93 this.endOffset = offset + length;
94 this.chunkSize = chunkSize;
95
96 file.seek(offset);
97 }
98
99
100
101
102 public long startOffset() {
103 return startOffset;
104 }
105
106
107
108
109 public long endOffset() {
110 return endOffset;
111 }
112
113
114
115
116 public long currentOffset() {
117 return offset;
118 }
119
120 @Override
121 public boolean isEndOfInput() throws Exception {
122 return !(offset < endOffset && file.getChannel().isOpen());
123 }
124
125 @Override
126 public void close() throws Exception {
127 file.close();
128 }
129
130 @Deprecated
131 @Override
132 public ByteBuf readChunk(ChannelHandlerContext ctx) throws Exception {
133 return readChunk(ctx.alloc());
134 }
135
136 @Override
137 public ByteBuf readChunk(ByteBufAllocator allocator) throws Exception {
138 long offset = this.offset;
139 if (offset >= endOffset) {
140 return null;
141 }
142
143 int chunkSize = (int) Math.min(this.chunkSize, endOffset - offset);
144
145
146 ByteBuf buf = allocator.heapBuffer(chunkSize);
147 boolean release = true;
148 try {
149 file.readFully(buf.array(), buf.arrayOffset(), chunkSize);
150 buf.writerIndex(chunkSize);
151 this.offset = offset + chunkSize;
152 release = false;
153 return buf;
154 } finally {
155 if (release) {
156 buf.release();
157 }
158 }
159 }
160
161 @Override
162 public long length() {
163 return endOffset - startOffset;
164 }
165
166 @Override
167 public long progress() {
168 return offset - startOffset;
169 }
170 }