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.IOException;
22 import java.io.RandomAccessFile;
23
24 import org.jboss.netty.channel.FileRegion;
25
26
27
28
29
30
31
32
33
34
35
36
37 public class ChunkedFile implements ChunkedInput {
38
39 private final RandomAccessFile file;
40 private final long startOffset;
41 private final long endOffset;
42 private final int chunkSize;
43 private volatile long offset;
44
45
46
47
48 public ChunkedFile(File file) throws IOException {
49 this(file, ChunkedStream.DEFAULT_CHUNK_SIZE);
50 }
51
52
53
54
55
56
57
58 public ChunkedFile(File file, int chunkSize) throws IOException {
59 this(new RandomAccessFile(file, "r"), chunkSize);
60 }
61
62
63
64
65 public ChunkedFile(RandomAccessFile file) throws IOException {
66 this(file, ChunkedStream.DEFAULT_CHUNK_SIZE);
67 }
68
69
70
71
72
73
74
75 public ChunkedFile(RandomAccessFile file, int chunkSize) throws IOException {
76 this(file, 0, file.length(), chunkSize);
77 }
78
79
80
81
82
83
84
85
86
87 public ChunkedFile(RandomAccessFile file, long offset, long length, int chunkSize) throws IOException {
88 if (file == null) {
89 throw new NullPointerException("file");
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 this.file = file;
106 this.offset = startOffset = offset;
107 endOffset = offset + length;
108 this.chunkSize = chunkSize;
109
110 file.seek(offset);
111 }
112
113
114
115
116 public long getStartOffset() {
117 return startOffset;
118 }
119
120
121
122
123 public long getEndOffset() {
124 return endOffset;
125 }
126
127
128
129
130 public long getCurrentOffset() {
131 return offset;
132 }
133
134 public boolean hasNextChunk() throws Exception {
135 return offset < endOffset && file.getChannel().isOpen();
136 }
137
138 public boolean isEndOfInput() throws Exception {
139 return !hasNextChunk();
140 }
141
142 public void close() throws Exception {
143 file.close();
144 }
145
146 public Object nextChunk() throws Exception {
147 long offset = this.offset;
148 if (offset >= endOffset) {
149 return null;
150 }
151
152 int chunkSize = (int) Math.min(this.chunkSize, endOffset - offset);
153 byte[] chunk = new byte[chunkSize];
154 file.readFully(chunk);
155 this.offset = offset + chunkSize;
156 return wrappedBuffer(chunk);
157 }
158 }