Преглед на файлове

Make ReverseFileReader use Paths.

Change-Id: I921a395e088846216650d1ac14207cb915a6bb8c
Reviewed-on: http://gerrit.dmdirc.com/4045
Automatic-Compile: DMDirc Build Manager
Reviewed-by: Chris Smith <chris@dmdirc.com>
changes/45/4045/3
Greg Holmes преди 9 години
родител
ревизия
87e3c1343d
променени са 3 файла, в които са добавени 82 реда и са изтрити 66 реда
  1. 39
    54
      src/com/dmdirc/util/io/ReverseFileReader.java
  2. 4
    0
      test-res/com/dmdirc/util/io/test5.txt
  3. 39
    12
      test/com/dmdirc/util/io/ReverseFileReaderTest.java

+ 39
- 54
src/com/dmdirc/util/io/ReverseFileReader.java Целия файл

@@ -23,10 +23,13 @@
23 23
 package com.dmdirc.util.io;
24 24
 
25 25
 import java.io.EOFException;
26
-import java.io.File;
27 26
 import java.io.IOException;
28
-import java.io.RandomAccessFile;
27
+import java.nio.ByteBuffer;
28
+import java.nio.channels.SeekableByteChannel;
29 29
 import java.nio.charset.Charset;
30
+import java.nio.file.Files;
31
+import java.nio.file.Path;
32
+import java.nio.file.StandardOpenOption;
30 33
 import java.util.ArrayList;
31 34
 import java.util.Stack;
32 35
 
@@ -35,33 +38,25 @@ import java.util.Stack;
35 38
  */
36 39
 public class ReverseFileReader {
37 40
 
41
+    /** Path to the file we're reading. */
42
+    private final Path file;
38 43
     /** File to manipulate. */
39
-    private RandomAccessFile file;
40
-
44
+    private SeekableByteChannel byteChannel;
41 45
     /** Number of bytes to skip backwards at a time. */
42 46
     private byte seekLength = 50;
43 47
 
44 48
     /**
45 49
      * Create a new ReverseFileReader.
46 50
      *
47
-     * @param filename File to open.
48
-     * @throws SecurityException If a security manager exists and its checkRead method denies read access to the file.
49
-     * @throws IOException If there is an error seeking to the end of the file.
50
-     */
51
-    public ReverseFileReader(final String filename) throws SecurityException, IOException {
52
-        file = new RandomAccessFile(filename, "r");
53
-        reset();
54
-    }
55
-
56
-    /**
57
-     * Create a new ReverseFileReader.
51
+     * @param file File to read
58 52
      *
59
-     * @param myFile Existing file to use.
60
-     * @throws SecurityException If a security manager exists and its checkRead method denies read access to the file.
53
+     * @throws SecurityException If a security manager exists and its checkRead method denies
54
+     * read access to the file.
61 55
      * @throws IOException If there is an error seeking to the end of the file.
62 56
      */
63
-    public ReverseFileReader(final File myFile) throws SecurityException, IOException {
64
-        file = new RandomAccessFile(myFile, "r");
57
+    public ReverseFileReader(final Path file) throws SecurityException, IOException {
58
+        this.file = file;
59
+        byteChannel = Files.newByteChannel(file, StandardOpenOption.READ);
65 60
         reset();
66 61
     }
67 62
 
@@ -70,11 +65,12 @@ public class ReverseFileReader {
70 65
      *
71 66
      * @throws IOException If there is an error seeking, or the file is closed.
72 67
      */
73
-    public void reset() throws IOException {
74
-        if (file == null) {
75
-            throw new IOException("File has been closed.");
68
+    public final void reset() throws IOException {
69
+        if (!byteChannel.isOpen()) {
70
+            throw new IOException("Channel has been closed.");
76 71
         }
77
-        file.seek(file.length());
72
+        byteChannel = Files.newByteChannel(file, StandardOpenOption.READ);
73
+        byteChannel.position(byteChannel.size());
78 74
     }
79 75
 
80 76
     /**
@@ -102,11 +98,10 @@ public class ReverseFileReader {
102 98
      * @throws IOException If there is an error closing the file, or if it has been closed already.
103 99
      */
104 100
     public void close() throws IOException {
105
-        if (file == null) {
106
-            throw new IOException("File has been closed.");
101
+        if (!byteChannel.isOpen()) {
102
+            throw new IOException("Channel has been closed.");
107 103
         }
108
-        file.close();
109
-        file = null;
104
+        byteChannel.close();
110 105
     }
111 106
 
112 107
     /**
@@ -116,37 +111,26 @@ public class ReverseFileReader {
116 111
      * @throws IOException If an error reading or seeking occured, or if the fiel is closed.
117 112
      */
118 113
     public String getNextLine() throws IOException {
119
-        if (file == null) {
120
-            throw new IOException("File has been closed.");
114
+        if (!byteChannel.isOpen()) {
115
+            throw new IOException("Channel has been closed.");
121 116
         }
122 117
         // Used to store result to output.
123
-
124 118
         final ArrayList<Byte> line = new ArrayList<>(seekLength);
125
-        // Used to store position in file pre-read
126
-        long fp;
127
-        // Used to store position in file when this is called
128
-        final long startfp;
129
-        // Used to store read bytes
130
-        byte[] bytes;
131
-        // Distance seeked
132
-        int seekDistance;
133
-
134 119
         // Check current position, if 0 we are at the start of the file
135 120
         // and should throw an exception.
136
-        startfp = file.getFilePointer();
121
+        final long startfp = byteChannel.position();
137 122
         if (startfp == 0) {
138 123
             throw new EOFException("Reached Start of file");
139 124
         }
140 125
 
141 126
         // Keep looping until we get a full line, or the end of the file
142 127
         boolean keepLooping = true;
143
-        boolean gotNewLine;
144 128
         while (keepLooping) {
145
-            gotNewLine = false;
146 129
             // Get Current Position
147
-            fp = file.getFilePointer();
130
+            long fp = byteChannel.position();
148 131
 
149 132
             // Check how far to seek backwards (seekLength or to the start of the file)
133
+            final int seekDistance;
150 134
             if (fp < seekLength) {
151 135
                 // Seek to the start of the file;
152 136
                 seekDistance = (int) fp;
@@ -154,27 +138,28 @@ public class ReverseFileReader {
154 138
             } else {
155 139
                 // Seek to position current-seekLength
156 140
                 seekDistance = seekLength;
157
-                fp = fp - seekDistance;
141
+                fp -= seekDistance;
158 142
             }
159 143
             // Seek!
160
-            file.seek(fp);
144
+            byteChannel.position(fp);
161 145
 
162
-            bytes = new byte[seekDistance];
146
+            final ByteBuffer bytes = ByteBuffer.allocate(seekDistance);
163 147
             // Read into the bytes array
164
-            file.read(bytes);
148
+            byteChannel.read(bytes);
165 149
 
166 150
             // And loop looking for data
167 151
             // This uses seekDistance so that only wanted data is checked.
152
+            boolean gotNewLine = false;
168 153
             for (int i = seekDistance - 1; i >= 0; --i) {
169 154
                 // Check for New line Character, or a non carriage-return char
170
-                if (bytes[i] == '\n') {
155
+                if (bytes.get(i) == '\n') {
171 156
                     // Seek to the location of this character and exit this loop.
172
-                    file.seek(fp + i);
157
+                    byteChannel.position(fp + i);
173 158
                     gotNewLine = true;
174 159
                     break;
175
-                } else if (bytes[i] != '\r') {
160
+                } else if (bytes.get(i) != '\r') {
176 161
                     // Add to the result, the loop will continue going.
177
-                    line.add(0, bytes[i]);
162
+                    line.add(0, bytes.get(i));
178 163
                 }
179 164
             }
180 165
 
@@ -186,7 +171,7 @@ public class ReverseFileReader {
186 171
                 // find a new line anywhere. no more loops are possible, so Treat
187 172
                 // this as "got new line"
188 173
                 gotNewLine = true;
189
-                file.seek(0);
174
+                byteChannel.position(0);
190 175
             }
191 176
 
192 177
             // Do we need to continue?
@@ -197,7 +182,7 @@ public class ReverseFileReader {
197 182
             } else {
198 183
                 // We have not found a new line anywhere,
199 184
                 // Seek to the pre-read position, and repeat.
200
-                file.seek(fp);
185
+                byteChannel.position(fp);
201 186
             }
202 187
 
203 188
         }
@@ -240,7 +225,7 @@ public class ReverseFileReader {
240 225
         final StringBuilder result = new StringBuilder();
241 226
         for (int i = 0; i < numLines; ++i) {
242 227
             try {
243
-                result.insert(0, "\n");
228
+                result.insert(0, '\n');
244 229
                 result.insert(0, getNextLine());
245 230
             } catch (IOException e) {
246 231
                 break;

+ 4
- 0
test-res/com/dmdirc/util/io/test5.txt Целия файл

@@ -0,0 +1,4 @@
1
+
2
+Line 1
3
+Line 2
4
+Line 3

+ 39
- 12
test/com/dmdirc/util/io/ReverseFileReaderTest.java Целия файл

@@ -22,21 +22,21 @@
22 22
 
23 23
 package com.dmdirc.util.io;
24 24
 
25
-import java.io.File;
26 25
 import java.io.IOException;
27 26
 import java.net.URISyntaxException;
27
+import java.nio.file.Paths;
28 28
 import java.util.Stack;
29 29
 
30 30
 import org.junit.Test;
31 31
 
32
-import static org.junit.Assert.*;
32
+import static org.junit.Assert.assertEquals;
33 33
 
34 34
 public class ReverseFileReaderTest {
35 35
 
36 36
     @Test
37 37
     public void testIndividual() throws IOException, URISyntaxException {
38 38
         final ReverseFileReader reader = new ReverseFileReader(
39
-                new File(getClass().getResource("test1.txt").toURI()));
39
+                Paths.get(getClass().getResource("test1.txt").toURI()));
40 40
         assertEquals("Line 7", reader.getNextLine());
41 41
         assertEquals("Line 6", reader.getNextLine());
42 42
         assertEquals("Line 5", reader.getNextLine());
@@ -50,7 +50,7 @@ public class ReverseFileReaderTest {
50 50
     @Test
51 51
     public void testCarriageReturn() throws IOException, URISyntaxException {
52 52
         final ReverseFileReader reader = new ReverseFileReader(
53
-                new File(getClass().getResource("test4.txt").toURI()));
53
+                Paths.get((getClass().getResource("test4.txt").toURI())));
54 54
         reader.getNextLine();
55 55
         assertEquals("Normal line", reader.getNextLine());
56 56
         reader.close();
@@ -59,7 +59,7 @@ public class ReverseFileReaderTest {
59 59
     @Test
60 60
     public void testLongLine() throws IOException, URISyntaxException {
61 61
         final ReverseFileReader reader = new ReverseFileReader(
62
-                new File(getClass().getResource("test4.txt").toURI()));
62
+                Paths.get((getClass().getResource("test4.txt").toURI())));
63 63
         assertEquals("This is a line that is longer than 50 characters, so " +
64 64
                 "should cause the reader to have to scan back multiple times.",
65 65
                 reader.getNextLine());
@@ -69,7 +69,7 @@ public class ReverseFileReaderTest {
69 69
     @Test
70 70
     public void testStack() throws IOException, URISyntaxException {
71 71
         final ReverseFileReader reader = new ReverseFileReader(
72
-                new File(getClass().getResource("test1.txt").toURI()));
72
+                Paths.get((getClass().getResource("test1.txt").toURI())));
73 73
         final Stack<String> lines = reader.getLines(10);
74 74
 
75 75
         assertEquals(7, lines.size());
@@ -86,7 +86,7 @@ public class ReverseFileReaderTest {
86 86
     @Test
87 87
     public void testSmallStack() throws IOException, URISyntaxException {
88 88
         final ReverseFileReader reader = new ReverseFileReader(
89
-                new File(getClass().getResource("test1.txt").toURI()));
89
+                Paths.get((getClass().getResource("test1.txt").toURI())));
90 90
         final Stack<String> lines = reader.getLines(3);
91 91
 
92 92
         assertEquals(3, lines.size());
@@ -96,10 +96,37 @@ public class ReverseFileReaderTest {
96 96
         reader.close();
97 97
     }
98 98
 
99
+    @Test
100
+    public void testgetLinesAsString() throws IOException, URISyntaxException {
101
+        final ReverseFileReader reader = new ReverseFileReader(
102
+                Paths.get((getClass().getResource("test5.txt").toURI())));
103
+        final String lines = reader.getLinesAsString(3);
104
+        assertEquals("Line 1\nLine 2\nLine 3\n", lines);
105
+        reader.close();
106
+    }
107
+
108
+    @Test
109
+    public void testgetLinesAsStringLeadingNewline() throws IOException, URISyntaxException {
110
+        final ReverseFileReader reader = new ReverseFileReader(
111
+                Paths.get((getClass().getResource("test5.txt").toURI())));
112
+        final String lines = reader.getLinesAsString(4);
113
+        assertEquals("Line 1\nLine 2\nLine 3\n", lines);
114
+        reader.close();
115
+    }
116
+
117
+    @Test
118
+    public void testIllegalGetLinesAsString() throws IOException, URISyntaxException {
119
+        final ReverseFileReader reader = new ReverseFileReader(
120
+                Paths.get((getClass().getResource("test5.txt").toURI())));
121
+        reader.close();
122
+        final String lines = reader.getLinesAsString(4);
123
+        assertEquals("", lines);
124
+    }
125
+
99 126
     @Test
100 127
     public void testReset() throws IOException, URISyntaxException {
101 128
         final ReverseFileReader reader = new ReverseFileReader(
102
-                new File(getClass().getResource("test1.txt").toURI()));
129
+                Paths.get((getClass().getResource("test1.txt").toURI())));
103 130
         assertEquals("Line 7", reader.getNextLine());
104 131
         assertEquals("Line 6", reader.getNextLine());
105 132
         reader.reset();
@@ -112,7 +139,7 @@ public class ReverseFileReaderTest {
112 139
     @Test(expected=IOException.class)
113 140
     public void testIllegalClose() throws URISyntaxException, IOException {
114 141
         final ReverseFileReader reader = new ReverseFileReader(
115
-                new File(getClass().getResource("test1.txt").toURI()));
142
+                Paths.get((getClass().getResource("test1.txt").toURI())));
116 143
         reader.close();
117 144
         reader.close();
118 145
     }
@@ -120,7 +147,7 @@ public class ReverseFileReaderTest {
120 147
     @Test(expected=IOException.class)
121 148
     public void testIllegalReset() throws URISyntaxException, IOException {
122 149
         final ReverseFileReader reader = new ReverseFileReader(
123
-                new File(getClass().getResource("test1.txt").toURI()));
150
+                Paths.get((getClass().getResource("test1.txt").toURI())));
124 151
         reader.close();
125 152
         reader.reset();
126 153
     }
@@ -128,7 +155,7 @@ public class ReverseFileReaderTest {
128 155
     @Test(expected=IOException.class)
129 156
     public void testIllegalGetNextLine() throws URISyntaxException, IOException {
130 157
         final ReverseFileReader reader = new ReverseFileReader(
131
-                new File(getClass().getResource("test1.txt").toURI()));
158
+                Paths.get((getClass().getResource("test1.txt").toURI())));
132 159
         reader.close();
133 160
         reader.getNextLine();
134 161
     }
@@ -136,7 +163,7 @@ public class ReverseFileReaderTest {
136 163
     @Test
137 164
     public void testSeekLength() throws IOException, URISyntaxException {
138 165
         final ReverseFileReader reader = new ReverseFileReader(
139
-                new File(getClass().getResource("test1.txt").toURI()));
166
+                Paths.get((getClass().getResource("test1.txt").toURI())));
140 167
         reader.setSeekLength((byte) 100);
141 168
         assertEquals((byte) 100, reader.getSeekLength());
142 169
     }

Loading…
Отказ
Запис