I'm new to Java and am trying to write a program that has one argument, the path of a text file. The program will locate the text file and print it out to the screen. Eventually I'm going to build this to format the given text file and then print it out to an outfile, but I'll get there later.
Anyways my program is always throwing and IOException and I'm not sure why. Given the argument C:\JavaUtility\input.txt , I receieve "Error, could not read file" during runtime. My code is located below.
import java.io.*;
public class utility {
public static void main(String[] path){
try{
FileReader fr = new FileReader(path[0]);
BufferedReader textReader = new BufferedReader(fr);
String aLine;
int numberOfLines = 0;
while ((aLine = textReader.readLine()) != null) {
numberOfLines++;
}
String[] textData = new String[numberOfLines];
for (int i=0;i < numberOfLines; i++){
textData[i] = textReader.readLine();
}
System.out.println(textData);
return;
}
catch(IOException e){
System.out.println("Error, could not read file");
}
}
}
[EDIT] Thanks for all the help everyone! So given my end goal, I thought it would still be useful to find the number of lines and store in a finite array. So I ended up writing two classes. The first, ReadFile.java found the data I wanted and handles most of the reading. The second FileData.java invokes the methods in ReadFile and prints out. I've posted them below incase someone later finds them useful.
package textfiles;
import java.io.*;
public class ReadFile {
private String path;
public ReadFile(String file_path){
path = file_path;
}
int readLines() throws IOException{
FileReader file_to_read = new FileReader(path);
BufferedReader bf = new BufferedReader(file_to_read);
String aLine;
int numberOfLines = 0;
while ((aLine = bf.readLine()) != null){
numberOfLines++;
}
bf.close();
return numberOfLines;
}
public String[] OpenFile() throws IOException{
FileReader fr = new FileReader(path);
BufferedReader textReader = new BufferedReader(fr);
int numberOfLines = readLines();
String[] textData = new String[numberOfLines];
for(int i=0; i < numberOfLines; i++){
textData[i] = textReader.readLine();
}
textReader.close();
return textData;
}
}
package textfiles;
import java.io.IOException;
public class FileData {
public static void main(String[] args)throws IOException{
String file_name = args[0];
try{
ReadFile file = new ReadFile(file_name);
String[] aryLines = file.OpenFile();
for(int i=0; i < aryLines.length; i++){
System.out.println(aryLines[i]);
}
}
catch (IOException e){
System.out.println(e.getMessage());
}
}
}
You're at the end of the file. When you determine the number of lines in the file, you've read until the end of the file,and the EOF Flag is set. [Edit: As #EJP notes below, BufferedReader returns null reading past the end of a file. The fact your reader isn't where you want it, however, remains true.] In the past, I've hacked around this simply by closing and re-opening the file. Alternatively, look into Array Lists or simple Lists. They're dynamically re-sizing, so you don't need to know the number of lines in the file ahead of time.
As mentioned by #mikeTheLiar you are at End Of File. BufferedReader reference is File Handler with an internal cursor pointing to current position in file. As you fire readLine() method, the pointer reads characters till it reaches new line character, returning the string. The pointer is set to new position. Once you read all the lines then readLine() returns null. After that if you call readLine() it will throw IOException. As noted by #EJP
One of the best coding rules while using IO API is to always check for EOF condition - the way you have in first loop. Once you reach EOF after that you should not call read method on the same reference without resetting the cursor - this can be done by calling reset() method.
IMHO, in your case there is no need for second loop. You can achieve the functionalty using one loop only.
import java.io.*;
import java.util.ArrayList;
public class utility {
public static void main(String[] path){
try{
FileReader fr = new FileReader(path[0]);
BufferedReader textReader = new BufferedReader(fr);
String aLine;
int numberOfLines = 0;
ArrayList readLines = new ArrayList();
while ((aLine = textReader.readLine()) != null) {
numberOfLines++;
readLines.add(aLine);
}
//Assuming you need array of lines, if not then you can print the lines directly in above loop
String[] textData = readLines.toArray();
System.out.println(textData);
return;
}
catch(IOException e){
System.out.println("Error, could not read file");
}
}
}
EDIT
I tried your code - it is working fine and printing the array reference. As suggested in comments the problem is with source (file might not be readable due to security or any other reason) - if you can print the exception message and get the exact line number where exception is thrown it would be helpful.
Couple of observations apart from the IO exception:
You are trying to open the file twice. readLines() method is called from within OpenFile(). Following the sequence of code file is first opened in OpenFile() when you create textReader. After that you are calling readLines() which is again trying to open the file when you create file_to_read.
You should try to avoid that and in your flow you should call int numberOfLines = readLines(); before FileReader fr = new FileReader(path);
Again IMHO there should be only one method and you should iterate over the file only once - both from efficience/performance and code maintainability perspective. You can change your ReadFile class as follows:
package textfiles;
import java.io.*;
import java.util.ArrayList;
public class ReadFile {
private String path;
public ReadFile(String file_path){
path = file_path;
}
//You need not have separate file for counting lines in file
//Java provides dynamic sized arrays using ArrayList
//There is no need to count lines
public String[] OpenFile() throws IOException{
FileReader fr = new FileReader(path);
BufferedReader textReader = new BufferedReader(fr);
ArrayList fileLines = new ArrayList();
String readLine = textReader.readLine();
while(readLine != null){
fileLines.add(readLine);
readLine = textReader.readLine();
}
textReader.close();
return fileLines.toArray();
}
}
Another small observation: in some places the java variable naming conventions are not followed. OpenFile() method should be openFile() and file_to_read should be fileToRead
Contrary to several answers here, readLine() does not throw an exception at end of file, it just keeps returning null. Your problem is being masked by another one. Never just make up your own error messages. Always print the one that comes with the exception. If you had done that you would probably have found the problem immediately. Almost certainly you weren't able to open the file at all, either because it wasn't there or you didn't have read access. The exception will tell you.
Related
I am trying to create a program that takes an inputted text file and reads the lines one by one. It then needs to store the most recently read lines (the number of lines depends on the parameter lines) in an array and then I need to print the lines using PrintWriter.
I started the first part but I'm not sure if I have the right idea. If anyone can help me on the second part as well that would be very appreciated!
public void RecentLines(Reader in, Writer out, int lines) throws IOException {
BufferedReader r3ader = new BufferedReader(in);
String str;
while((str = r3ader.readLine()) != null){
String[] arr = str.split(" ");
for( int i =0; i < lines; i++){
arr[i] = r3ader.readLine();
}
}
EDIT
the full question is this:
Create a program which reads lines from IN, one line at the time until the end. Your method must maintain an internal buffer that stores the most recently read lines (this might be best done using an array). Once the method reaches the end of the file, it should print the lines stored in the internal buffer into out, probably best done by creating a PrintWriter to decorate this Writer. (Except for your debugging purposes during the development stage, this method should not print anything to System.out.)
Try this one:
public void RecentLines(Reader in, Writer out, int lines) throws IOException {
BufferedReader r3ader = new BufferedReader(in);
String str;
int i=0;
String[] lineArray = new String[lines];
while((str = r3ader.readLine()) != null){
lines[i%lines] = str;
i++;
if(!r3ader.hasNextLine()){
break;
}
}
sounds like a task for data structures. Queue seems to be the best fit for a given task.
public void RecentLines(Reader in, Writer out, int lines) throws IOException {
BufferedReader r3ader = new BufferedReader(in);
BufferedWriter wout = new BufferedWriter(out);
String str;
Queue<String> content = new LinkedList<String>();
int i = 0;
while ((str = r3ader.readLine()) != null) {
if (i >= lines) {
content.remove();
}
content.add(str);
i++;
}
wout.write(String.valueOf(content));
}
I´m in a bit of a struggle here, I´m trying to add each word from a textfile to an ArrayList and every time the reader comes across the same word again it will skip it. (Makes sense?)
I don't even know where to start. I kind of know that I need one loop that adds the textfile to the ArrayList and one the checks if the word is not in the list. Any ideas?
PS: Just started with Java
This is what I've done so far, don't even know if I'm on the right path..
public String findWord(){
int text = 0;
int i = 0;
while sc.hasNextLine()){
wordArray[i] = sc.nextLine();
}
if wordArray[i].contains() {
}
i++;
}
A List (an ArrayList or otherwise) is not the best data structure to use; a Set is better. In pseudo code:
define a Set
for each word
if adding to the set returns false, skip it
else do whatever do want to do with the (first time encountered) word
The add() method of Set returns true if the set changed as a result of the call, which only happens if the word isn't already in the set, because sets disallow duplicates.
I once made a similar program, it read through a textfile and counted how many times a word came up.
Id start with importing a scanner, as well as a file system(this needs to be at the top of the java class)
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.File;
import java.io.PrintStream;
import java.util.Scanner;
then you can make file, as well as a scanner reading from this file, make sure to adjsut the path to the file accordingly. The new Printstream is not necessary but when dealing with a big amount of data i dont like to overflow the console.
public static void main(String[] args) throws FileNotFoundException {
File file=new File("E:/Youtube analytics/input/input.txt");
Scanner scanner = new Scanner(file); //will read from the file above
PrintStream out = new PrintStream(new FileOutputStream("E:/Youtube analytics/output/output.txt"));
System.setOut(out);
}
after this you can use scanner.next() to get the next word so you would write something like this:
String[] array=new String[MaxAmountOfWords];//this will make an array
int numberOfWords=0;
String currentWord="";
while(scanner.hasNext()){
currentWord=scanner.next();
if(isNotInArray(currentWord))
{
array[numberOfWords]=currentWord
}
numberOfWords++;
}
If you dont understand any of this or need further guidence to progress, let me know. It is hard to help you if we dont exactly know where you are at...
You can try this:
public List<String> getAllWords(String filePath){
String line;
List<String> allWords = new ArrayList<String>();
BufferedReader reader = new BufferedReader(new FileReader(new File(filePath)));
//read each line of the file
while((line = reader.readLine()) != null) {
//get each word in the line
for(String word: line.split("(\\w)+"))
//validate if the current word is not empty
if(!word.isEmpty())
if(!allWords.contains(word))
allWords.add(word);
}
}
return allWords;
}
Best solution is to use a Set. But if you still want to use a List, here goes:
Suppose the file has the following data:
Hi how are you
I am Hardi
Who are you
Code will be:
List<String> list = new ArrayList<>();
// Get the file.
FileInputStream fis = new FileInputStream("C:/Users/hdinesh/Desktop/samples.txt");
//Construct BufferedReader from InputStreamReader
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
String line = null;
// Loop through each line in the file
while ((line = br.readLine()) != null) {
// Regex for finding just the words
String[] strArray = line.split("[ ]");
for (int i = 0; i< strArray.length; i++) {
if (!list.contains(strArray[i])) {
list.add(strArray[i]);
}
}
}
br.close();
System.out.println(list.toString());
If your text file has sentences with special characters, you will have to write a regex for that.
In Java, is there any method to read a particular line from a file? For example, read line 32 or any other line number.
For small files:
String line32 = Files.readAllLines(Paths.get("file.txt")).get(32)
For large files:
try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
line32 = lines.skip(31).findFirst().get();
}
Unless you have previous knowledge about the lines in the file, there's no way to directly access the 32nd line without reading the 31 previous lines.
That's true for all languages and all modern file systems.
So effectively you'll simply read lines until you've found the 32nd one.
Not that I know of, but what you could do is loop through the first 31 lines doing nothing using the readline() function of BufferedReader
FileInputStream fs= new FileInputStream("someFile.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fs));
for(int i = 0; i < 31; ++i)
br.readLine();
String lineIWant = br.readLine();
Joachim is right on, of course, and an alternate implementation to Chris' (for small files only because it loads the entire file) might be to use commons-io from Apache (though arguably you might not want to introduce a new dependency just for this, if you find it useful for other stuff too though, it could make sense).
For example:
String line32 = (String) FileUtils.readLines(file).get(31);
http://commons.apache.org/io/api-release/org/apache/commons/io/FileUtils.html#readLines(java.io.File, java.lang.String)
You may try indexed-file-reader (Apache License 2.0). The class IndexedFileReader has a method called readLines(int from, int to) which returns a SortedMap whose key is the line number and the value is the line that was read.
Example:
File file = new File("src/test/resources/file.txt");
reader = new IndexedFileReader(file);
lines = reader.readLines(6, 10);
assertNotNull("Null result.", lines);
assertEquals("Incorrect length.", 5, lines.size());
assertTrue("Incorrect value.", lines.get(6).startsWith("[6]"));
assertTrue("Incorrect value.", lines.get(7).startsWith("[7]"));
assertTrue("Incorrect value.", lines.get(8).startsWith("[8]"));
assertTrue("Incorrect value.", lines.get(9).startsWith("[9]"));
assertTrue("Incorrect value.", lines.get(10).startsWith("[10]"));
The above example reads a text file composed of 50 lines in the following format:
[1] The quick brown fox jumped over the lazy dog ODD
[2] The quick brown fox jumped over the lazy dog EVEN
Disclamer: I wrote this library
Although as said in other answers, it is not possible to get to the exact line without knowing the offset (pointer) before. So, I've achieved this by creating an temporary index file which would store the offset values of every line. If the file is small enough, you could just store the indexes (offset) in memory without needing a separate file for it.
The offsets can be calculated by using the RandomAccessFile
RandomAccessFile raf = new RandomAccessFile("myFile.txt","r");
//above 'r' means open in read only mode
ArrayList<Integer> arrayList = new ArrayList<Integer>();
String cur_line = "";
while((cur_line=raf.readLine())!=null)
{
arrayList.add(raf.getFilePointer());
}
//Print the 32 line
//Seeks the file to the particular location from where our '32' line starts
raf.seek(raf.seek(arrayList.get(31));
System.out.println(raf.readLine());
raf.close();
Also visit the Java docs on RandomAccessFile for more information:
Complexity: This is O(n) as it reads the entire file once. Please be aware for the memory requirements. If it's too big to be in memory, then make a temporary file that stores the offsets instead of ArrayList as shown above.
Note: If all you want in '32' line, you just have to call the readLine() also available through other classes '32' times. The above approach is useful if you want to get the a specific line (based on line number of course) multiple times.
Another way.
try (BufferedReader reader = Files.newBufferedReader(
Paths.get("file.txt"), StandardCharsets.UTF_8)) {
List<String> line = reader.lines()
.skip(31)
.limit(1)
.collect(Collectors.toList());
line.stream().forEach(System.out::println);
}
No, unless in that file format the line lengths are pre-determined (e.g. all lines with a fixed length), you'll have to iterate line by line to count them.
In Java 8,
For small files:
String line = Files.readAllLines(Paths.get("file.txt")).get(n);
For large files:
String line;
try (Stream<String> lines = Files.lines(Paths.get("file.txt"))) {
line = lines.skip(n).findFirst().get();
}
In Java 7
String line;
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
for (int i = 0; i < n; i++)
br.readLine();
line = br.readLine();
}
Source: Reading nth line from file
If you are talking about a text file, then there is really no way to do this without reading all the lines that precede it - After all, lines are determined by the presence of a newline, so it has to be read.
Use a stream that supports readline, and just read the first X-1 lines and dump the results, then process the next one.
It works for me:
I have combined the answer of
Reading a simple text file
But instead of return a String I am returning a LinkedList of Strings. Then I can select the line that I want.
public static LinkedList<String> readFromAssets(Context context, String filename) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(context.getAssets().open(filename)));
LinkedList<String>linkedList = new LinkedList<>();
// do reading, usually loop until end of file reading
StringBuilder sb = new StringBuilder();
String mLine = reader.readLine();
while (mLine != null) {
linkedList.add(mLine);
sb.append(mLine); // process line
mLine = reader.readLine();
}
reader.close();
return linkedList;
}
Use this code:
import java.nio.file.Files;
import java.nio.file.Paths;
public class FileWork
{
public static void main(String[] args) throws IOException {
String line = Files.readAllLines(Paths.get("D:/abc.txt")).get(1);
System.out.println(line);
}
}
You can use LineNumberReader instead of BufferedReader. Go through the api. You can find setLineNumber and getLineNumber methods.
You can also take a look at LineNumberReader, subclass of BufferedReader. Along with the readline method, it also has setter/getter methods to access line number. Very useful to keep track of the number of lines read, while reading data from file.
public String readLine(int line){
FileReader tempFileReader = null;
BufferedReader tempBufferedReader = null;
try { tempFileReader = new FileReader(textFile);
tempBufferedReader = new BufferedReader(tempFileReader);
} catch (Exception e) { }
String returnStr = "ERROR";
for(int i = 0; i < line - 1; i++){
try { tempBufferedReader.readLine(); } catch (Exception e) { }
}
try { returnStr = tempBufferedReader.readLine(); } catch (Exception e) { }
return returnStr;
}
you can use the skip() function to skip the lines from begining.
public static void readFile(String filePath, long lineNum) {
List<String> list = new ArrayList<>();
long totalLines, startLine = 0;
try (Stream<String> lines = Files.lines(Paths.get(filePath))) {
totalLines = Files.lines(Paths.get(filePath)).count();
startLine = totalLines - lineNum;
// Stream<String> line32 = lines.skip(((startLine)+1));
list = lines.skip(startLine).collect(Collectors.toList());
// lines.forEach(list::add);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
list.forEach(System.out::println);
}
EASY WAY - Reading a line using line number.
Let's say Line number starts from 1 till null .
public class TextFileAssignmentOct {
private void readData(int rowNum, BufferedReader br) throws IOException {
int n=1; //Line number starts from 1
String row;
while((row=br.readLine()) != null) { // Reads every line
if (n == rowNum) { // When Line number matches with which you want to read
System.out.println(row);
}
n++; //This increments Line number
}
}
public static void main(String[] args) throws IOException {
File f = new File("../JavaPractice/FileRead.txt");
FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr);
TextFileAssignmentOct txf = new TextFileAssignmentOct();
txf.readData(4, br); //Read a Specific Line using Line number and Passing buffered reader
}
}
for a text file you can use an integer with a loop to help you get the number of the line, don't forget to import the classes we are using in this example
File myObj = new File("C:\\Users\\LENOVO\\Desktop\\test.txt");//path of the file
FileReader fr = new FileReader(myObj);
fr.read();
BufferedReader bf = new BufferedReader(fr); //BufferedReader of the FileReader fr
String line = bf.readLine();
int lineNumber = 0;
while (line != null) {
lineNumber = lineNumber + 1;
if(lineNumber == 7)
{
//show line
System.out.println("line: " + lineNumber + " has :" + line);
break;
}
//lecture de la prochaine ligne, reading next
line = bf.readLine();
}
They are all wrong I just wrote this in about 10 seconds.
With this I managed to just call the object.getQuestion("linenumber") in the main method to return whatever line I want.
public class Questions {
File file = new File("Question2Files/triviagame1.txt");
public Questions() {
}
public String getQuestion(int numLine) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(file));
String line = "";
for(int i = 0; i < numLine; i++) {
line = br.readLine();
}
return line; }}
So I need to do exactly what it says in the title, take a text file called "words.txt", have the program read it, take all the words in it, and store them into an array. After that, the program needs to pick one out randomly, and print it in reverse. I'm having a lot of trouble getting it to work, as it always crashes at the end. Here's what I got so far:
import java.io.*;
import java.util.Random;
public class wordReader{
public static void main (String args[]) throws Exception{
BufferedReader br = new BufferedReader(new FileReader("words.txt"));
String strLine;
String[] filearray;
filearray = new String[10];
while ((strLine = br.hasNextLine())) {
for (int j = 0; j < filearray.length; j++){
filearray[j] = br.readLine();
System.out.println(filearray);
}
}
}
}
Alright, this i what I have at the moment:
import java.io.*;
import java.util.Random;
public class wordReader{
public static void main (String args[]) throws Exception{
BufferedReader br = new BufferedReader(new FileReader("words.txt"));
String strLine;
String[] filearray;
filearray = new String[10];
int j = 0;
int i = 0;
Random r = new Random();
while(((strLine = br.readLine()) !=null) && j < filearray.length){
filearray[j++] = strLine;
int idx = r.nextInt(filearray.length);
}
}
}
You can do this easily using the new Files API and StringBuilder to reverse your String. It will cut down your lines of code significantly.
public static void main(String[] args) throws Exception {
Path path = Paths.get("words.txt");
Charset charset = StandardCharsets.UTF_8;
String content = new String(Files.readAllBytes(path), charset);
String[] words = content.split(",|\.|\s+");
int randomIndex = new Random().nextInt(words.length);
String word = words[randomIndex];
String reversed = StringBuilder(word).reverse().toString();
System.out.println(reversed);
}
Try using the StringTokenizer to read the line.
http://docs.oracle.com/javase/7/docs/api/java/util/StringTokenizer.html
StringTokenizer st = new StringTokenizer("this is a test");
while (st.hasMoreTokens()) {
System.out.println(st.nextToken());
}
Lot's of ways to accomplish this. Here's a recursive method that prints as the calls are popping off the return stack. This was adapted from Reversing Lines With Recursion Java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.PrintWriter;
public class ReverseLines {
public static BufferedReader input;
public static PrintWriter output;
public static void main(String[] args) throws Exception {
input = new BufferedReader(new FileReader("/tmp/words.txt"));
output = new PrintWriter(System.out);
reverse(input, output);
input.close();
output.flush();
output.close();
}
public static void reverse(BufferedReader input, PrintWriter output)
throws Exception {
String line = input.readLine();
if (line != null) {
reverse(input, output);
output.println(line);
}
}
}
You don't seem to have gotten to the point of doing the random index selection or the line reversal yet, so I won't address that stuff here. There are endless duplicates all over StackOverflow to tell you how to reverse a String.
At the moment, you're getting compile errors because (among other things) you're trying to use a method (BufferedReader#hasNextLine()) that doesn't exist. It looks like you were mixing up a couple of other approaches that you might have found, e.g.:
int j = 0;
while ((strLine = br.readLine()) != null) { // Set strLine to the next line
filearray[j++] = strLine; // Add strLine to the array
// I don't recommend printing the whole array on every pass through the loop...
}
You'll notice that I also took out your inner for loop, because it was just setting every element of your list to the most recent line on every iteration. I'm assuming you wanted to populate the list with all of your lines. Realistically, you should also check whether j is in an acceptable range as well:
while (((strLine = br.readLine()) != null) && j < filearray.length) {...}
Note that realistically, you'd almost certainly be better off using a List to store your lines, so you could just add all the lines to the List and not worry about the length:
List<String> contents = new ArrayList<String>();
while ((strLine = br.readLine()) != null) {
contents.add(strLine); // Add strLine to the List
}
But, this does smell like homework, so maybe you're required to use a String[] for whatever reason.
Finally, there's a discrepancy between what you've written in your question and what your program looks like it's intended to do. You claim that you need a list of each word, but it looks more like you're trying to create a list of each line. If you need words instead of lines, you'll need to split up each line and add each token to the list.
My Sample Code
String line = null;
RandomAccessFile file = new RandomAccessFile("D:/mahtew.txt", "rw");
System.out.println(file.getFilePointer());
while((line = file.readLine()) != null){
System.out.println(line);
System.out.println(file.getFilePointer());
if(line.contains("Text to be appended with")){
file.seek(file.getFilePointer());
file.write(" new text has been appended".getBytes());
break;
}
}
file.close();
demo.txt before execution
one two three
Text to be appended with
five six seven
eight nine ten
demo.txt after execution
one two three
Text to be appended with
new text has been appendedten
Also i tried using setLength to change length of file before new text is appended. But still some text is getting trimmed from output file. Any help will be appreciated
Thanks
Mathew
RandomAccessFile
A random access file behaves like a large array of bytes stored in the
file system.
In fact it does not care about shifting the array elements in the case of write operations (only the pointer is advanced). Such an operation overwrites existing values:
Output operations write bytes starting at the file pointer and advance
the file pointer past the bytes written.
When you seek to the file's byte location and writes data, the bytes will be overwritten.
Which is why you get an output like this.
Just imagine editing something in notepad with the insert key pressed. It will replace instead of inserting the new data in between. Same thing's happening here.
EDIT:
You should actually do what Eel is suggesting if you want to edit the file content.
Or you can get the rest of the file and add it to the modified data and write to the file in order to avoid the loss, but that will get ugly and complicated real fast. Not to mention performance penalties.
Understand that when you write with a RAF, you over-write data which was previously held at the file pointer location. If you want to insert text into a file, I suggest that you not use a RAF but rather simply read the text of the file into a String or ArrayList<String> or StringBuilder, using a File held by a FileReader wrapped in a BufferedReader or a File wrapped in a Scanner, alter the Strings or StringBuilder held in memory, and then write the altered data to the new file using a FileWriter wrapped in a PrintWriter.
e.g.,
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class AppendLine {
private static final String FILE_PATH = "src/tetris/mahtew.txt";
private static final String MARKER_LINE = "Text to be appended with";
private static final String TEXT_TO_ADD = "new text has been appended";
public static void main(String[] args) {
List<String> fileLines = new ArrayList<String>();
Scanner scanner = null;
try {
scanner = new Scanner(new File(FILE_PATH));
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
fileLines.add(line);
if (line.trim().equalsIgnoreCase(MARKER_LINE)) {
fileLines.add(TEXT_TO_ADD);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (scanner != null) {
scanner.close();
}
}
PrintWriter pw = null;
try {
pw = new PrintWriter(new File(FILE_PATH));
for (String line : fileLines) {
pw.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (pw != null) {
pw.close();
}
}
}
}
You can use RandomAccessFile in Java to achieve this on one condition:
The size of each line has to be fixed otherwise, when new string is written back, it might override the string in the next line.
Therefore, in my example, I set the line length as 100 and padding with space string when creating the file and writing back to the file.
So in order to allow update, you need to set the length of line a little larger than the longest length of the line in this file.
public class RandomAccessFileUtil {
public static final long RECORD_LENGTH = 100;
public static final String EMPTY_STRING = " ";
public static final String CRLF = "\n";
public static final String PATHNAME = "/home/mjiang/JM/mahtew.txt";
/**
* one two three
Text to be appended with
five six seven
eight nine ten
*
*
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException
{
String starPrefix = "Text to be appended with";
String replacedString = "new text has been appended";
RandomAccessFile file = new RandomAccessFile(new File(PATHNAME), "rw");
String line = "";
while((line = file.readLine()) != null)
{
if(line.startsWith(starPrefix))
{
file.seek(file.getFilePointer() - RECORD_LENGTH - 1);
file.writeBytes(replacedString);
}
}
}
public static void createFile() throws IOException
{
RandomAccessFile file = new RandomAccessFile(new File(PATHNAME), "rw");
String line1 = "one two three";
String line2 = "Text to be appended with";
String line3 = "five six seven";
String line4 = "eight nine ten";
file.writeBytes(paddingRight(line1));
file.writeBytes(CRLF);
file.writeBytes(paddingRight(line2));
file.writeBytes(CRLF);
file.writeBytes(paddingRight(line3));
file.writeBytes(CRLF);
file.writeBytes(paddingRight(line4));
file.writeBytes(CRLF);
file.close();
System.out.println(String.format("File is created in [%s]", PATHNAME));
}
public static String paddingRight(String source)
{
StringBuilder result = new StringBuilder(100);
if(source != null)
{
result.append(source);
for (int i = 0; i < RECORD_LENGTH - source.length(); i++)
{
result.append(EMPTY_STRING);
}
}
return result.toString();
}
}
If replaced string is too long, the strings after the line matched with input will be replaced. It seems you have to read file, modify it and write back to old or new file.
Of course, you have options to use multi-threading programming and Java 7's new IO features to improve performance.