Skip to content

Commit c395904

Browse files
committed
[IO-269] Tailer locks file from deletion/rename on Windows.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/io/trunk@1348698 13f79535-47bb-0310-9956-ffa450edef68
1 parent 199dd8d commit c395904

3 files changed

Lines changed: 79 additions & 5 deletions

File tree

src/changes/changes.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ The <action> type attribute can be add,update,fix,remove.
4747
<body>
4848
<!-- The release date is the date RC is cut -->
4949
<release version="2.4" date="2012-TDB-TDB" description="">
50+
<action issue="IO-269" dev="ggregory" type="add" due-to="sebb">
51+
Tailer locks file from deletion/rename on Windows.
52+
</action>
5053
<action issue="IO-279" dev="sebb" type="fix" due-to="Sergio Bossa, Chris Baron">
5154
Tailer erroneously considers file as new.
5255
</action>

src/main/java/org/apache/commons/io/input/Tailer.java

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,11 @@ public class Tailer implements Runnable {
137137
*/
138138
private final TailerListener listener;
139139

140+
/**
141+
* Whether to close and reopen the file whilst waiting for more input.
142+
*/
143+
private final boolean reOpen;
144+
140145
/**
141146
* The tailer will run as long as this value is true.
142147
*/
@@ -172,6 +177,18 @@ public Tailer(File file, TailerListener listener, long delayMillis, boolean end)
172177
this(file, listener, delayMillis, end, DEFAULT_BUFSIZE);
173178
}
174179

180+
/**
181+
* Creates a Tailer for the given file, with a delay other than the default 1.0s.
182+
* @param file the file to follow.
183+
* @param listener the TailerListener to use.
184+
* @param delayMillis the delay between checks of the file for new content in milliseconds.
185+
* @param end Set to true to tail from the end of the file, false to tail from the beginning of the file.
186+
* @param reOpen if true, close and reopen the file between reading chunks
187+
*/
188+
public Tailer(File file, TailerListener listener, long delayMillis, boolean end, boolean reOpen) {
189+
this(file, listener, delayMillis, end, reOpen, DEFAULT_BUFSIZE);
190+
}
191+
175192
/**
176193
* Creates a Tailer for the given file, with a specified buffer size.
177194
* @param file the file to follow.
@@ -181,7 +198,19 @@ public Tailer(File file, TailerListener listener, long delayMillis, boolean end)
181198
* @param bufSize Buffer size
182199
*/
183200
public Tailer(File file, TailerListener listener, long delayMillis, boolean end, int bufSize) {
184-
201+
this(file, listener, delayMillis, end, false, bufSize);
202+
}
203+
204+
/**
205+
* Creates a Tailer for the given file, with a specified buffer size.
206+
* @param file the file to follow.
207+
* @param listener the TailerListener to use.
208+
* @param delayMillis the delay between checks of the file for new content in milliseconds.
209+
* @param end Set to true to tail from the end of the file, false to tail from the beginning of the file.
210+
* @param reOpen if true, close and reopen the file between reading chunks
211+
* @param bufSize Buffer size
212+
*/
213+
public Tailer(File file, TailerListener listener, long delayMillis, boolean end, boolean reOpen, int bufSize) {
185214
this.file = file;
186215
this.delayMillis = delayMillis;
187216
this.end = end;
@@ -191,6 +220,7 @@ public Tailer(File file, TailerListener listener, long delayMillis, boolean end,
191220
// Save and prepare the listener
192221
this.listener = listener;
193222
listener.init(this);
223+
this.reOpen = reOpen;
194224
}
195225

196226
/**
@@ -211,6 +241,26 @@ public static Tailer create(File file, TailerListener listener, long delayMillis
211241
return tailer;
212242
}
213243

244+
/**
245+
* Creates and starts a Tailer for the given file.
246+
*
247+
* @param file the file to follow.
248+
* @param listener the TailerListener to use.
249+
* @param delayMillis the delay between checks of the file for new content in milliseconds.
250+
* @param end Set to true to tail from the end of the file, false to tail from the beginning of the file.
251+
* @param reOpen whether to close/reopen the file between chunks
252+
* @param bufSize buffer size.
253+
* @return The new tailer
254+
*/
255+
public static Tailer create(File file, TailerListener listener, long delayMillis, boolean end, boolean reOpen,
256+
int bufSize) {
257+
Tailer tailer = new Tailer(file, listener, delayMillis, end, reOpen, bufSize);
258+
Thread thread = new Thread(tailer);
259+
thread.setDaemon(true);
260+
thread.start();
261+
return tailer;
262+
}
263+
214264
/**
215265
* Creates and starts a Tailer for the given file with default buffer size.
216266
*
@@ -224,6 +274,20 @@ public static Tailer create(File file, TailerListener listener, long delayMillis
224274
return create(file, listener, delayMillis, end, DEFAULT_BUFSIZE);
225275
}
226276

277+
/**
278+
* Creates and starts a Tailer for the given file with default buffer size.
279+
*
280+
* @param file the file to follow.
281+
* @param listener the TailerListener to use.
282+
* @param delayMillis the delay between checks of the file for new content in milliseconds.
283+
* @param end Set to true to tail from the end of the file, false to tail from the beginning of the file.
284+
* @param reOpen whether to close/reopen the file between chunks
285+
* @return The new tailer
286+
*/
287+
public static Tailer create(File file, TailerListener listener, long delayMillis, boolean end, boolean reOpen) {
288+
return create(file, listener, delayMillis, end, reOpen, DEFAULT_BUFSIZE);
289+
}
290+
227291
/**
228292
* Creates and starts a Tailer for the given file, starting at the beginning of the file
229293
*
@@ -345,10 +409,17 @@ public void run() {
345409
last = System.currentTimeMillis();
346410
}
347411
}
412+
if (reOpen) {
413+
IOUtils.closeQuietly(reader);
414+
}
348415
try {
349416
Thread.sleep(delayMillis);
350417
} catch (InterruptedException e) {
351418
}
419+
if (run && reOpen) {
420+
reader = new RandomAccessFile(file, RAF_MODE);
421+
reader.seek(position);
422+
}
352423
}
353424

354425
} catch (Exception e) {

src/test/java/org/apache/commons/io/input/TailerTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,9 @@ public void testTailer() throws Exception {
146146
final File file = new File(getTestDirectory(), "tailer1-test.txt");
147147
createFile(file, 0);
148148
final TestTailerListener listener = new TestTailerListener();
149-
tailer = new Tailer(file, listener, delayMillis, false);
149+
String osname = System.getProperty("os.name");
150+
boolean isWindows = osname.startsWith("Windows");
151+
tailer = new Tailer(file, listener, delayMillis, false, isWindows);
150152
final Thread thread = new Thread(tailer);
151153
thread.start();
152154

@@ -178,9 +180,7 @@ public void testTailer() throws Exception {
178180
// Delete & re-create
179181
file.delete();
180182
boolean exists = file.exists();
181-
String osname = System.getProperty("os.name");
182-
boolean isWindows = osname.startsWith("Windows");
183-
assertFalse("File should not exist (except on Windows)", exists && !isWindows);
183+
assertFalse("File should not exist", exists);
184184
createFile(file, 0);
185185
Thread.sleep(testDelayMillis);
186186

0 commit comments

Comments
 (0)