I have to read a file and depending of the content of the last lines, I have to copy most of its content into a new file. Unfortunately I didn't found a way to copy first n lines or chars of a file in java.
The only way I found, is copying the file using nio FileChannels where I can specifiy the length in bytes. However, therefore I would need to know how many bytes the stuff I read needed in the source-file.
Does anyone know a solution for one of these problems?
Try this:
Scanner scanner = new Scanner(yourFileObject); // initialise scanner
then
for (int i = 0; i < amountOfLines; i++) {
String line = scanner.nextLine(); // get line excluding \n at the end
// handle here
}
OR, for n chars, rather than lines:
Pattern charPattern = Pattern.compile(".")
// java.util.regex.Pattern with any char allowed
for (int i = 0; i < amountOfChars; i++) {
char next = scanner.next(charPattern).toCharArray()[0];
// handle here
}
This is, in my opinion, by far the best and easiest to write way to get the first n chars/lines from a file.
You should use a BufferedReader and read N lines which you will write into a fileX. Then redo this process until you've splitted your file into several files.
Here's a basic example:
BufferedReader bw = null;
try (BufferedReader br = new BufferedReader(new FileReader(new File("<path_to_input_file>")))) {
String line = "";
StringBuilder sb = new StringBuilder();
int count = 0;
bw = new BufferedWriter(new FileWriter(new File("<path_to_output_file>")));
while ( (line = br.readLine()) != null) {
sb.append(line)
.append(System.getProperty("line.separator"));
if (count++ == 1000) {
//flush and close current content into the current new file
bw.write(sb.toString());
bw.flush();
bw.close();
//start a new file
bw = new BufferedWriter(new FileWriter(new File("<path_to_new_output_file>")));
//re initialize the counter
count = 0;
//re initialize the String content
sb = new StringBuilder();
}
}
if (bw != null && sb.length() > 0) {
bw.write(sb.toString());
bw.flush();
bw.close();
}
} catch (Exception e) {
e.printStacktrace(System.out);
}
Since you have performance as key quality attribute, use BufferedReader over Scanner. Here's an explanation about the performance comparison: Scanner vs. BufferedReader
Related
I have to count the characters in a text file.
I would like to do it with a for loop, however, I do not know how to refer to the length of the file?
public void countLetters(String) {
for (int i = 0; i < ; i++) {
}
}
What should I write after the i < ?
Well you first need to read the contents of the file. You can do it the following manner.
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
Where file is the file object i.e in your case, the text file which you want to read. Then read each line of the file, like this
String temp;
int totalNoOfCharacters = 0;
int noOfLines = 0; //To count no of lines IF you need it
while ( (temp = br.readline()) != null ){
noOfLines++;
totalNoOfCharacters += temp.length(); //Rememeber this doesnot count the line termination character. So if you want to consider newLine as a character, add one in this step.
}
FileReader fr = new FileReader("pathtofile");
BufferedReader br = new BufferedReader(fr);
String line = "";
int cont=0;
while ((line = br.readLine()) != null) {
line = line.split("\\s+").trim();
cont+=line.length();
}
Don't forget to close streams and use try catch .
Maybe better to read each each character within a while loop that first checks for the end of the file than to try using a for loop.
e.g.
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
. . . .
. . . .
try
{
BufferedReader reader = new BufferedReader(new FileReader("myFile.txt"));
String textLine = reader.readLine();
int count = 0;
while (textLine != null)
{
textLine.replaceAll("\\s+",""); // To avoid counting spaces
count+= textLine.length();
textLine = reader.readLine();
}
reader.close();
System.out.println("Number of characters in myFile.txt is: " + count);
}
catch(FileNotFoundException e)
{
System.out.println("The file, myFile.txt, was not found");
}
catch(IOException e)
{
System.out.println("Read of myFile.txt failed.");
e.printStackTrace();
}
Scanner scanner = new Scanner(yourfile);
while(scanner.hasNext()){
word = scanner.next();
char += word.length();
}
the following code will only read the first line of a text file and it will stop there. I've been experimenting with loops but i cannot get it to successfully update the line until there are no more lines in the file. can anyone help? thanks
public void readFile(){
try {
BufferedReader in = new BufferedReader(new FileReader("test1.txt"));
words = new ArrayList<Word>();
int lineNum = 1; // we read first line in start
// delimeters of line in this example only "space"
char [] parse = {' '};
String delims = new String(parse);
String line = in.readLine();
String [] lineWords = line.split(delims);
// split the words and create word object
for (int i = 0; i < lineWords.length; i++) {
Word w = new Word(lineWords[i]);
words.add(w);
}
lineNum++; // pass the next line
line = in.readLine();
in.close();
} catch (IOException e) {
}
}
Basically, you want to keep reading until you run out of lines, at which time BufferedReader will return null
char[] parse = {' '};
String delims = new String(parse);
String line = null;
while ((line = in.readLine()) != null) {
String[] lineWords = line.split(delims);
// split the words and create word object
for (int i = 0; i < lineWords.length; i++) {
Word w = new Word(lineWords[i]);
words.add(w);
}
lineNum++; // pass the next line
}
You should be managing your resources better, if you open it, you should make all reasonable attempts to close. Currently, if your code fails for some reason, the in.close line will never be called. Also, you shouldn't ignore exceptions
Luckily, in Java 8, this is easy to manage...
try (BufferedReader in = new BufferedReader(new FileReader("test1.txt"))) {
//...
} catch (IOException e) {
e.printStackTrace();
}
Take a closer look at Basic I/O, The try-with-resources Statement and BufferedReader JavaDocs, especially BufferedReader#readLine
You may also want to take a look at LineNumberReader ;)
while((line = in.readLine()) != null){
//process line
}
This nested statement reads a line from the BufferedReader and stores it in line. At the end of the file, readLine() will return null and stop the loop.
Using the BufferedReader method instead of the Scanner to read a txt file, containing all prime numbers between 2 and 10000.
I want to put the integers in an array tall.
With the Scanner method it works but not with the BufferedReader equivalent.
The try statement works with both methods, but when i'm closing the BufferedReader in the finally statement, it says my variables don't exist.
If i use the Scanner method, it's working.
Scanner (works):
public class Main {
public static void main(String[] arg) throws IOException {
File file = new File ("C:/Users/Victor/workspace/Bvijfb/Priem.txt");
file.getParentFile().mkdirs();
FileWriter xw = new FileWriter("Priem.txt");
PrintWriter yw = new PrintWriter(xw);
int i;
boolean isPriem;
int[] tall = new int[1240];
for (i = 2; i < 10000; i++) {
isPriem = true;
for (int j = 2; j < i; j++) {
if (i % j == 0) {
isPriem = false;
break;
}
}
if (isPriem == true)
yw.println("" + i);
}
yw.close();
Scanner sc = new Scanner(file);
int a = 0;
try {
while (sc.hasNextLine()) {
if(sc.hasNextInt()){
tall[a] = sc.nextInt();
a++;
}
else {
break;
}
}
} finally {
sc.close();
}
}
The try statement Using the BufferedReader method:
try{
InputStream is = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
int a = 0;
int value = 0;
while ((value = br.read()) != -1) {
tall[a] = value;
a++;
}
}catch(Exception e){
e.printStackTrace();
}finally{
is.close();
isr.close();
br.close();
}
Your scanner code is looking for an int by looking for characters that define an int. So for instance, the three characters '1', '2', and '3', in a row, are read as the int value 123 by your Scanner code.
But your BufferedReader code is working at a lower level than that; it works at the individual character level. So when you do br.read() for the first time on my 123 example, you get the value 49 ('1' == 49).
BufferedReader doesn't implement the parsing functionality that Scanner does. If you want it, use Scanner (or implement your own custom if necessary).
Unrelated side note: On any vaguely-recent version of Java, your try in the BufferedReader example would be much better off as a try-with-resources:
try (
InputStream is = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr)
) {
int a = 0;
int value = 0;
while ((value = br.read()) != -1) {
tall[a] = value;
a++;
}
} catch (Exception e){
e.printStackTrace(); // This is also generally poor practice, but for quick-and-dirty code...
}
Note that I never call close. I don't have to, try-with-resources handles it for me, and handles it property regardless of where or when an exception is thrown. In your code, for instance, if for some reason new InputStreamReader(is) threw, you'd leave is open.
For starters, when using a BufferedReader, you probably want to be using readLine() instead of read(). Read consumes a binary byte at a time; readLine() converts a line of bytes into a String and (assuming these files are one-line-per-number) that String will be the representation of a prime number.
If there is more than one number per line of text in the file, you'll need to split the String.
In order to convert that String to an int, you'll need to run Integer.parseInt() on it.
Also, you can remove some of the setup ceremony as follows:
FileReader fr = new FileReader(fileName);
BufferedReader br = new BufferedReader(fr);
Or even just
BufferedReader br = new BufferedReader(new FileReader(fileName));
I have files containing text in pattern like this
Type:status
Origin:some text
Text:some text
URL:some url
Time:time
around 500 lines with same pattern. I want to extract only the text part from it. I tried reading the file with BufferedReader and used indexOf("Text") and indexOf("URL") and subString(i,j) but its giving exception at run time. How can I do this. My code:
FileReader fr = new FileReader("test.txt");
BufferedReader br = new BufferedReader(fr);
FileWriter wr = new FileWriter("new.txt");
// char buffer[] = null;
String s;
String str="";
BufferedWriter bw = new BufferedWriter(wr);
while ((s = br.readLine()) != null) {
str= str + s;
i = str.indexOf("Text:");
j= str.indexOf("URL:");
String a= str.substring(i, j);
bw.write(a);
}
br.close();
bw.close();
The "Text:" is found first in the 3rd line and "URL:" in the 4th, but if your program doesn't find both strings, it throws an exception.
Even if it worked you would find the same text over and over again.
Try something like this:
FileReader fr = new FileReader("test.txt");
BufferedReader br = new BufferedReader(fr);
FileWriter wr = new FileWriter("new.txt");
String s;
BufferedWriter bw = new BufferedWriter(wr);
while ((s = br.readLine()) != null) {
if (s.startsWith("Text:"))
bw.write(s);
}
br.close();
bw.close();
You could use
String[] pieces = str.split(":");
That will give you an array of strings split by what ever you put in the parenthesis. Then if you know the pattern you can get each piece out by iterating through it in a loop. For example: if you know that Type is at [0] and six things in each sequence you can say that the next Type will be at [6] and so on.
You should check for indexes. Of i and j. If one line is wrong, it will skip it and print the line that is wrong to the console. You should probably handle it in a different way but keep in mind that substring shouldn't love indexes of -1.
FileReader fr = new FileReader("test.txt");
BufferedReader br = new BufferedReader(fr);
String tokenText = "Text:";
String tokenURL = "URL:";
FileWriter wr = new FileWriter("new.txt");
// char buffer[] = null;
String s;
String str="";
BufferedWriter bw = new BufferedWriter(wr);
while ((s = br.readLine()) != null) {
String a;
str = str + s;
i = str.indexOf(tokenText);
j = str.indexOf(tokenURL);
if (i < 0 && j >= 0){
// pad with the token string
a = s.substring(j + tokenURL.length);
} else if(i >= 0) {
// pad with the token string
a = s.substring(i + tokenText.length);
} else {
System.out.printl("Unparsed line:");
System.out.printl(s);
}
bw.write(a);
}
br.close();
bw.close();
That said, as jonhchen902 said in the comments, you could also check for the strings after the while loop. It really depends on your input file and if you're expecting to find the "string" multiple times or once.
According to your example, Text: and Url: are on consecutive lines.
Your problem is you're reading the file line by line (br.readLine()), so calling indexOf() will most of the time return -1 in i or j (and you will never find both strings, since they aren't on the same line).
As the javadoc of substring() states, calling the method with a negative start index will throw an IndexOutOfBoundsException. So your approach isn't right.
You should instead parse the file line by line as you're doing, and simply test for a positive index to the call to indexOf("Text:"), and then substring the current line starting at the returned index + 5.
Not tested:
while ((line = br.readLine()) != null) {
i = line.indexOf("Text:");
if (i > 0) {
String text = line.substring(i);
bw.write(text + "\n");
}
}
I have a text file that I am reading. It has chunks that I would want to remove. Is there a way I can say If the reader comes across a String "STATEMENT OF ACCOUNT" it skips reading the 10 lines before that Statement. This is the code I am currently using which is reading everything from the Text file.
for(int i = 0; i < filenames.length; i++){
FileInputStream fstemp = new FileInputStream("C:/Temporary/" + filenames[i]);
FileOutputStream fos = new FileOutputStream("C:/Statements/" + filenames[i]);
DataInputStream in1 = new DataInputStream(fstemp);
UniqueLineReader brtemp = new UniqueLineReader(new InputStreamReader(in1));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos));
String strLine;
while((strLine = brtemp.readLine()) != null){
bw.write(strLine);
bw.newLine();
bw.flush();
}
}
I'm assuming you actually want to skip the 10 lines after the "STATEMENT OF ACCOUNT" line. In which case, you want something like this:
int linesToSkip = 0;
String strLine;
while((strLine = brtemp.readLine()) != null) {
if (linesToSkip > 0) {
linesToSkip--;
continue;
}
if (strLine.equals("STATEMENT OF ACCOUNT")) {
linesToSkip = 10;
continue;
}
bw.write(strLine);
bw.newLine();
bw.flush();
}
If you really want to somehow obliterate the previous ten lines, then you'd need to delay output (e.g. saving it in a cyclical buffer) until ten lines later, just in case you see "STATEMENT OF ACCOUNT" in a few lines' time.
You can do it by buffering the preceding 10 lines in a queue:
Queue<String> queue = new LinkedList<String>();
String strLine;
while ((strLine = brtemp.readLine()) != null {
queue.add(strLine);
if (strLine.equals("STATEMENT OF ACCOUNT")) {
queue.clear();
continue;
}
while (queue.size() >= 10) {
bw.write(queue.remove());
bw.newLine();
}
}
while (!queue.isEmpty()) {
bw.write(queue.remove());
bw.newLine();
}
bw.flush();
It sounds like you need to maintain a buffer of 10 lines so that when you encounter your special line, you can abandon the contents. Until you see it, you add every line to one end and only output from the other end when the buffer is full. The answers to this question recommend a Queue or CircularFifoBuffer for this type of situation.
Here's an untested code sample using a CircularFifoBuffer:
for (int i = 0; i < filenames.length; i++) {
FileInputStream fstemp = new FileInputStream("C:/Temporary/" + filenames[i]);
FileOutputStream fos = new FileOutputStream("C:/Statements/" + filenames[i]);
DataInputStream in1 = new DataInputStream(fstemp);
UniqueLineReader brtemp = new UniqueLineReader(new InputStreamReader(in1));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos));
Buffer ringbuf = new CircularFifoBuffer(10);
String strLine;
while ((strLine = brtemp.readLine()) != null) {
if (strLine.equals("STATEMENT OF ACCOUNT")) {
ringbuf.clear();
}
ringbuf.add(strLine);
if (ringbuf.isFull()) {
bw.write(ringbuf.remove());
bw.newLine();
bw.flush();
}
}
for (Object item : ringbuf) {
bw.write(item);
bw.newLine();
bw.flush();
}
}