1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.channel;
17
18 import io.netty.util.AbstractReferenceCounted;
19 import io.netty.util.IllegalReferenceCountException;
20 import io.netty.util.internal.ObjectUtil;
21 import io.netty.util.internal.logging.InternalLogger;
22 import io.netty.util.internal.logging.InternalLoggerFactory;
23
24 import java.io.File;
25 import java.io.IOException;
26 import java.io.RandomAccessFile;
27 import java.nio.channels.FileChannel;
28 import java.nio.channels.WritableByteChannel;
29
30 import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
31
32
33
34
35
36
37
38 public class DefaultFileRegion extends AbstractReferenceCounted implements FileRegion {
39
40 private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultFileRegion.class);
41 private final File f;
42 private final long position;
43 private final long count;
44 private long transferred;
45 private FileChannel file;
46
47
48
49
50
51
52
53
54 public DefaultFileRegion(FileChannel fileChannel, long position, long count) {
55 this.file = ObjectUtil.checkNotNull(fileChannel, "fileChannel");
56 this.position = checkPositiveOrZero(position, "position");
57 this.count = checkPositiveOrZero(count, "count");
58 this.f = null;
59 }
60
61
62
63
64
65
66
67
68
69 public DefaultFileRegion(File file, long position, long count) {
70 this.f = ObjectUtil.checkNotNull(file, "file");
71 this.position = checkPositiveOrZero(position, "position");
72 this.count = checkPositiveOrZero(count, "count");
73 }
74
75
76
77
78 public boolean isOpen() {
79 return file != null;
80 }
81
82
83
84
85 public void open() throws IOException {
86 if (!isOpen() && refCnt() > 0) {
87
88 file = new RandomAccessFile(f, "r").getChannel();
89 }
90 }
91
92 @Override
93 public long position() {
94 return position;
95 }
96
97 @Override
98 public long count() {
99 return count;
100 }
101
102 @Deprecated
103 @Override
104 public long transfered() {
105 return transferred;
106 }
107
108 @Override
109 public long transferred() {
110 return transferred;
111 }
112
113 @Override
114 public long transferTo(WritableByteChannel target, long position) throws IOException {
115 long count = this.count - position;
116 if (count < 0 || position < 0) {
117 throw new IllegalArgumentException(
118 "position out of range: " + position +
119 " (expected: 0 - " + (this.count - 1) + ')');
120 }
121 if (count == 0) {
122 return 0L;
123 }
124 if (refCnt() == 0) {
125 throw new IllegalReferenceCountException(0);
126 }
127
128 open();
129
130 long written = file.transferTo(this.position + position, count, target);
131 if (written > 0) {
132 transferred += written;
133 } else if (written == 0) {
134
135
136
137
138 validate(this, position);
139 }
140 return written;
141 }
142
143 @Override
144 protected void deallocate() {
145 FileChannel file = this.file;
146
147 if (file == null) {
148 return;
149 }
150 this.file = null;
151
152 try {
153 file.close();
154 } catch (IOException e) {
155 logger.warn("Failed to close a file.", e);
156 }
157 }
158
159 @Override
160 public FileRegion retain() {
161 super.retain();
162 return this;
163 }
164
165 @Override
166 public FileRegion retain(int increment) {
167 super.retain(increment);
168 return this;
169 }
170
171 @Override
172 public FileRegion touch() {
173 return this;
174 }
175
176 @Override
177 public FileRegion touch(Object hint) {
178 return this;
179 }
180
181 static void validate(DefaultFileRegion region, long position) throws IOException {
182
183
184
185
186 long size = region.file.size();
187 long count = region.count - position;
188 if (region.position + count + position > size) {
189 throw new IOException("Underlying file size " + size + " smaller then requested count " + region.count);
190 }
191 }
192 }