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